summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/ac.c27
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c25
-rw-r--r--drivers/acpi/acpi_extlog.c2
-rw-r--r--drivers/acpi/acpi_memhotplug.c3
-rw-r--r--drivers/acpi/acpi_processor.c124
-rw-r--r--drivers/acpi/acpi_tad.c27
-rw-r--r--drivers/acpi/acpi_video.c26
-rw-r--r--drivers/acpi/acpica/acdebug.h2
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/aclocal.h38
-rw-r--r--drivers/acpi/acpica/acpredef.h3
-rw-r--r--drivers/acpi/acpica/dbcmds.c58
-rw-r--r--drivers/acpi/acpica/dbinput.c8
-rw-r--r--drivers/acpi/acpica/dswstate.c4
-rw-r--r--drivers/acpi/acpica/exserial.c3
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/utdebug.c5
-rw-r--r--drivers/acpi/arm64/Makefile1
-rw-r--r--drivers/acpi/arm64/amba.c (renamed from drivers/acpi/acpi_amba.c)2
-rw-r--r--drivers/acpi/arm64/init.c2
-rw-r--r--drivers/acpi/arm64/init.h1
-rw-r--r--drivers/acpi/arm64/iort.c5
-rw-r--r--drivers/acpi/battery.c24
-rw-r--r--drivers/acpi/bus.c33
-rw-r--r--drivers/acpi/hed.c15
-rw-r--r--drivers/acpi/internal.h16
-rw-r--r--drivers/acpi/nfit/core.c42
-rw-r--r--drivers/acpi/prmt.c8
-rw-r--r--drivers/acpi/processor_core.c29
-rw-r--r--drivers/acpi/processor_pdc.c97
-rw-r--r--drivers/acpi/resource.c6
-rw-r--r--drivers/acpi/scan.c4
-rw-r--r--drivers/acpi/thermal.c470
-rw-r--r--drivers/acpi/video_detect.c27
-rw-r--r--drivers/acpi/x86/s2idle.c99
-rw-r--r--drivers/acpi/x86/utils.c35
-rw-r--r--drivers/android/binderfs.c8
-rw-r--r--drivers/auxdisplay/hd44780_common.c10
-rw-r--r--drivers/base/core.c4
-rw-r--r--drivers/base/cpu.c13
-rw-r--r--drivers/base/memory.c40
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/base/regmap/Kconfig12
-rw-r--r--drivers/base/regmap/regcache-maple.c16
-rw-r--r--drivers/base/regmap/regcache-rbtree.c12
-rw-r--r--drivers/base/regmap/regcache.c38
-rw-r--r--drivers/base/regmap/regmap-kunit.c40
-rw-r--r--drivers/base/regmap/regmap-mmio.c24
-rw-r--r--drivers/base/regmap/regmap.c122
-rw-r--r--drivers/block/amiflop.c1
-rw-r--r--drivers/block/drbd/drbd_nl.c9
-rw-r--r--drivers/block/floppy.c2
-rw-r--r--drivers/block/loop.c6
-rw-r--r--drivers/block/nbd.c9
-rw-r--r--drivers/block/swim3.c2
-rw-r--r--drivers/block/ublk_drv.c366
-rw-r--r--drivers/bluetooth/btbcm.c5
-rw-r--r--drivers/bluetooth/btintel.c229
-rw-r--r--drivers/bluetooth/btintel.h10
-rw-r--r--drivers/bluetooth/btmtk.c133
-rw-r--r--drivers/bluetooth/btmtk.h42
-rw-r--r--drivers/bluetooth/btmtkuart.c1
-rw-r--r--drivers/bluetooth/btnxpuart.c257
-rw-r--r--drivers/bluetooth/btqca.c96
-rw-r--r--drivers/bluetooth/btqca.h31
-rw-r--r--drivers/bluetooth/btrtl.c233
-rw-r--r--drivers/bluetooth/btrtl.h13
-rw-r--r--drivers/bluetooth/btusb.c372
-rw-r--r--drivers/bluetooth/hci_h5.c2
-rw-r--r--drivers/bluetooth/hci_ldisc.c3
-rw-r--r--drivers/bluetooth/hci_nokia.c6
-rw-r--r--drivers/bluetooth/hci_qca.c428
-rw-r--r--drivers/char/hw_random/Kconfig37
-rw-r--r--drivers/char/hw_random/amd-rng.c1
-rw-r--r--drivers/char/hw_random/arm_smccc_trng.c2
-rw-r--r--drivers/char/hw_random/atmel-rng.c2
-rw-r--r--drivers/char/hw_random/ba431-rng.c10
-rw-r--r--drivers/char/hw_random/bcm2835-rng.c3
-rw-r--r--drivers/char/hw_random/cctrng.c93
-rw-r--r--drivers/char/hw_random/cn10k-rng.c18
-rw-r--r--drivers/char/hw_random/core.c3
-rw-r--r--drivers/char/hw_random/exynos-trng.c8
-rw-r--r--drivers/char/hw_random/imx-rngc.c24
-rw-r--r--drivers/char/hw_random/ingenic-rng.c2
-rw-r--r--drivers/char/hw_random/ingenic-trng.c59
-rw-r--r--drivers/char/hw_random/iproc-rng200.c28
-rw-r--r--drivers/char/hw_random/nomadik-rng.c19
-rw-r--r--drivers/char/hw_random/npcm-rng.c3
-rw-r--r--drivers/char/hw_random/omap-rng.c2
-rw-r--r--drivers/char/hw_random/omap3-rom-rng.c1
-rw-r--r--drivers/char/hw_random/pasemi-rng.c3
-rw-r--r--drivers/char/hw_random/pic32-rng.c76
-rw-r--r--drivers/char/hw_random/stm32-rng.c3
-rw-r--r--drivers/char/hw_random/timeriomem-rng.c25
-rw-r--r--drivers/char/hw_random/xgene-rng.c6
-rw-r--r--drivers/char/hw_random/xiphera-trng.c1
-rw-r--r--drivers/char/mem.c18
-rw-r--r--drivers/char/tpm/eventlog/tpm1.c3
-rw-r--r--drivers/char/tpm/tpm_tis.c93
-rw-r--r--drivers/char/tpm/tpm_tis_core.c60
-rw-r--r--drivers/char/tpm/tpm_tis_core.h1
-rw-r--r--drivers/char/tpm/tpm_tis_spi_main.c91
-rw-r--r--drivers/char/tpm/tpm_tis_synquacer.c18
-rw-r--r--drivers/clk/clk-devres.c13
-rw-r--r--drivers/clk/keystone/syscon-clk.c6
-rw-r--r--drivers/connector/cn_proc.c111
-rw-r--r--drivers/connector/connector.c40
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c6
-rw-r--r--drivers/cpufreq/amd-pstate-ut.c50
-rw-r--r--drivers/cpufreq/armada-37xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/brcmstb-avs-cpufreq.c12
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c13
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c7
-rw-r--r--drivers/cpufreq/cpufreq-dt.c5
-rw-r--r--drivers/cpufreq/cpufreq.c8
-rw-r--r--drivers/cpufreq/cpufreq_stats.c3
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c6
-rw-r--r--drivers/cpufreq/imx-cpufreq-dt.c6
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c6
-rw-r--r--drivers/cpufreq/intel_pstate.c5
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c6
-rw-r--r--drivers/cpufreq/mediatek-cpufreq-hw.c9
-rw-r--r--drivers/cpufreq/mediatek-cpufreq.c2
-rw-r--r--drivers/cpufreq/omap-cpufreq.c6
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c6
-rw-r--r--drivers/cpufreq/powernow-k8.c3
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c2
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq_pmi.c1
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c8
-rw-r--r--drivers/cpufreq/qcom-cpufreq-nvmem.c7
-rw-r--r--drivers/cpufreq/qoriq-cpufreq.c6
-rw-r--r--drivers/cpufreq/raspberrypi-cpufreq.c6
-rw-r--r--drivers/cpufreq/scpi-cpufreq.c7
-rw-r--r--drivers/cpufreq/sti-cpufreq.c2
-rw-r--r--drivers/cpufreq/sun50i-cpufreq-nvmem.c6
-rw-r--r--drivers/cpufreq/tegra186-cpufreq.c6
-rw-r--r--drivers/cpufreq/tegra194-cpufreq.c35
-rw-r--r--drivers/cpufreq/ti-cpufreq.c2
-rw-r--r--drivers/cpufreq/vexpress-spc-cpufreq.c6
-rw-r--r--drivers/cpuidle/governors/gov.h14
-rw-r--r--drivers/cpuidle/governors/menu.c65
-rw-r--r--drivers/cpuidle/governors/teo.c235
-rw-r--r--drivers/crypto/Kconfig7
-rw-r--r--drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c1
-rw-r--r--drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c41
-rw-r--r--drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c172
-rw-r--r--drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c98
-rw-r--r--drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h16
-rw-r--r--drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c27
-rw-r--r--drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c155
-rw-r--r--drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c114
-rw-r--r--drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h19
-rw-r--r--drivers/crypto/amlogic/amlogic-gxl-cipher.c13
-rw-r--r--drivers/crypto/amlogic/amlogic-gxl-core.c61
-rw-r--r--drivers/crypto/amlogic/amlogic-gxl.h5
-rw-r--r--drivers/crypto/aspeed/aspeed-acry.c40
-rw-r--r--drivers/crypto/aspeed/aspeed-hace-crypto.c134
-rw-r--r--drivers/crypto/aspeed/aspeed-hace-hash.c285
-rw-r--r--drivers/crypto/aspeed/aspeed-hace.c9
-rw-r--r--drivers/crypto/aspeed/aspeed-hace.h30
-rw-r--r--drivers/crypto/atmel-aes.c21
-rw-r--r--drivers/crypto/atmel-ecc.c2
-rw-r--r--drivers/crypto/atmel-sha.c28
-rw-r--r--drivers/crypto/atmel-tdes.c20
-rw-r--r--drivers/crypto/bcm/cipher.c6
-rw-r--r--drivers/crypto/caam/caamalg.c386
-rw-r--r--drivers/crypto/caam/caamhash.c47
-rw-r--r--drivers/crypto/caam/caampkc.c25
-rw-r--r--drivers/crypto/caam/caampkc.h3
-rw-r--r--drivers/crypto/caam/ctrl.c111
-rw-r--r--drivers/crypto/caam/intern.h25
-rw-r--r--drivers/crypto/caam/jr.c206
-rw-r--r--drivers/crypto/caam/qi.c1
-rw-r--r--drivers/crypto/caam/regs.h9
-rw-r--r--drivers/crypto/ccp/Makefile3
-rw-r--r--drivers/crypto/ccp/dbc.c250
-rw-r--r--drivers/crypto/ccp/dbc.h56
-rw-r--r--drivers/crypto/ccp/psp-dev.c19
-rw-r--r--drivers/crypto/ccp/psp-dev.h1
-rw-r--r--drivers/crypto/ccp/sp-dev.h7
-rw-r--r--drivers/crypto/ccp/sp-pci.c96
-rw-r--r--drivers/crypto/ccree/cc_driver.c1
-rw-r--r--drivers/crypto/chelsio/chcr_algo.c3
-rw-r--r--drivers/crypto/chelsio/chcr_core.h1
-rw-r--r--drivers/crypto/chelsio/chcr_crypto.h1
-rw-r--r--drivers/crypto/exynos-rng.c4
-rw-r--r--drivers/crypto/gemini/sl3516-ce-cipher.c22
-rw-r--r--drivers/crypto/gemini/sl3516-ce-core.c50
-rw-r--r--drivers/crypto/gemini/sl3516-ce.h8
-rw-r--r--drivers/crypto/hisilicon/hpre/hpre_crypto.c10
-rw-r--r--drivers/crypto/hisilicon/hpre/hpre_main.c5
-rw-r--r--drivers/crypto/hisilicon/qm.c28
-rw-r--r--drivers/crypto/hisilicon/sec/sec_drv.c4
-rw-r--r--drivers/crypto/img-hash.c4
-rw-r--r--drivers/crypto/intel/keembay/keembay-ocs-aes-core.c441
-rw-r--r--drivers/crypto/intel/keembay/keembay-ocs-ecc.c73
-rw-r--r--drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c243
-rw-r--r--drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c23
-rw-r--r--drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h4
-rw-r--r--drivers/crypto/intel/qat/qat_4xxx/adf_drv.c3
-rw-r--r--drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c28
-rw-r--r--drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.h7
-rw-r--r--drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c28
-rw-r--r--drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.h7
-rw-r--r--drivers/crypto/intel/qat/qat_common/Makefile5
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_accel_devices.h14
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_admin.c61
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h2
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_clock.c131
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_clock.h14
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_common_drv.h14
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_dbgfs.c12
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_fw_counters.c264
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_fw_counters.h11
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen2_config.c7
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.h3
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h3
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h2
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen4_timer.c70
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_gen4_timer.h21
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_heartbeat.c336
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_heartbeat.h79
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c194
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.h12
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_init.c28
-rw-r--r--drivers/crypto/intel/qat/qat_common/adf_isr.c6
-rw-r--r--drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h23
-rw-r--r--drivers/crypto/intel/qat/qat_common/icp_qat_hw.h5
-rw-r--r--drivers/crypto/intel/qat/qat_common/qat_compression.c3
-rw-r--r--drivers/crypto/intel/qat/qat_common/qat_uclo.c7
-rw-r--r--drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c13
-rw-r--r--drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h5
-rw-r--r--drivers/crypto/n2_core.c2
-rw-r--r--drivers/crypto/omap-aes-gcm.c37
-rw-r--r--drivers/crypto/omap-aes.c266
-rw-r--r--drivers/crypto/omap-aes.h15
-rw-r--r--drivers/crypto/omap-des.c214
-rw-r--r--drivers/crypto/omap-sham.c281
-rw-r--r--drivers/crypto/qcom-rng.c10
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.c59
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto.h21
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto_ahash.c80
-rw-r--r--drivers/crypto/rockchip/rk3288_crypto_skcipher.c60
-rw-r--r--drivers/crypto/s5p-sss.c1
-rw-r--r--drivers/crypto/sa2ul.c3
-rw-r--r--drivers/crypto/sahara.c1
-rw-r--r--drivers/crypto/starfive/Kconfig2
-rw-r--r--drivers/crypto/starfive/Makefile2
-rw-r--r--drivers/crypto/starfive/jh7110-aes.c1024
-rw-r--r--drivers/crypto/starfive/jh7110-cryp.c53
-rw-r--r--drivers/crypto/starfive/jh7110-cryp.h74
-rw-r--r--drivers/crypto/starfive/jh7110-hash.c290
-rw-r--r--drivers/crypto/stm32/Kconfig2
-rw-r--r--drivers/crypto/stm32/stm32-cryp.c370
-rw-r--r--drivers/crypto/stm32/stm32-hash.c978
-rw-r--r--drivers/crypto/talitos.c4
-rw-r--r--drivers/crypto/virtio/virtio_crypto_akcipher_algs.c35
-rw-r--r--drivers/crypto/virtio/virtio_crypto_skcipher_algs.c25
-rw-r--r--drivers/crypto/xilinx/zynqmp-aes-gcm.c39
-rw-r--r--drivers/crypto/xilinx/zynqmp-sha.c1
-rw-r--r--drivers/dax/device.c22
-rw-r--r--drivers/dax/kmem.c4
-rw-r--r--drivers/devfreq/devfreq.c10
-rw-r--r--drivers/devfreq/imx-bus.c2
-rw-r--r--drivers/devfreq/imx8m-ddrc.c2
-rw-r--r--drivers/devfreq/mtk-cci-devfreq.c1
-rw-r--r--drivers/devfreq/tegra30-devfreq.c2
-rw-r--r--drivers/dma-buf/sw_sync.c18
-rw-r--r--drivers/edac/amd64_edac.c15
-rw-r--r--drivers/edac/i10nm_base.c2
-rw-r--r--drivers/eisa/eisa-bus.c2
-rw-r--r--drivers/firmware/arm_sdei.c19
-rw-r--r--drivers/firmware/efi/libstub/Makefile3
-rw-r--r--drivers/firmware/efi/libstub/arm64-stub.c2
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c2
-rw-r--r--drivers/firmware/efi/libstub/efistub.h3
-rw-r--r--drivers/firmware/efi/libstub/randomalloc.c10
-rw-r--r--drivers/firmware/efi/libstub/x86-5lvl.c95
-rw-r--r--drivers/firmware/efi/libstub/x86-stub.c283
-rw-r--r--drivers/firmware/efi/libstub/x86-stub.h17
-rw-r--r--drivers/firmware/efi/libstub/zboot.c2
-rw-r--r--drivers/firmware/efi/riscv-runtime.c15
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c358
-rw-r--r--drivers/gpio/Kconfig31
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c127
-rw-r--r--drivers/gpio/gpio-104-idio-16.c286
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c2
-rw-r--r--drivers/gpio/gpio-altera-a10sr.c3
-rw-r--r--drivers/gpio/gpio-ath79.c3
-rw-r--r--drivers/gpio/gpio-bcm-kona.c24
-rw-r--r--drivers/gpio/gpio-brcmstb.c4
-rw-r--r--drivers/gpio/gpio-clps711x.c4
-rw-r--r--drivers/gpio/gpio-creg-snps.c2
-rw-r--r--drivers/gpio/gpio-davinci.c2
-rw-r--r--drivers/gpio/gpio-ds4520.c80
-rw-r--r--drivers/gpio/gpio-eic-sprd.c3
-rw-r--r--drivers/gpio/gpio-exar.c2
-rw-r--r--drivers/gpio/gpio-ftgpio010.c4
-rw-r--r--drivers/gpio/gpio-ge.c66
-rw-r--r--drivers/gpio/gpio-grgpio.c2
-rw-r--r--drivers/gpio/gpio-hlwd.c2
-rw-r--r--drivers/gpio/gpio-idio-16.c254
-rw-r--r--drivers/gpio/gpio-idio-16.h79
-rw-r--r--drivers/gpio/gpio-imx-scu.c3
-rw-r--r--drivers/gpio/gpio-ixp4xx.c2
-rw-r--r--drivers/gpio/gpio-logicvc.c3
-rw-r--r--drivers/gpio/gpio-lp3943.c2
-rw-r--r--drivers/gpio/gpio-lpc32xx.c4
-rw-r--r--drivers/gpio/gpio-max3191x.c4
-rw-r--r--drivers/gpio/gpio-max732x.c6
-rw-r--r--drivers/gpio/gpio-max77620.c2
-rw-r--r--drivers/gpio/gpio-mb86s7x.c2
-rw-r--r--drivers/gpio/gpio-mlxbf3.c26
-rw-r--r--drivers/gpio/gpio-mmio.c9
-rw-r--r--drivers/gpio/gpio-mpc5200.c2
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c4
-rw-r--r--drivers/gpio/gpio-msc313.c1
-rw-r--r--drivers/gpio/gpio-mxc.c118
-rw-r--r--drivers/gpio/gpio-mxs.c3
-rw-r--r--drivers/gpio/gpio-omap.c8
-rw-r--r--drivers/gpio/gpio-palmas.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c20
-rw-r--r--drivers/gpio/gpio-pca9570.c2
-rw-r--r--drivers/gpio/gpio-pcf857x.c29
-rw-r--r--drivers/gpio/gpio-pci-idio-16.c294
-rw-r--r--drivers/gpio/gpio-pcie-idio-24.c677
-rw-r--r--drivers/gpio/gpio-pisosr.c28
-rw-r--r--drivers/gpio/gpio-pmic-eic-sprd.c3
-rw-r--r--drivers/gpio/gpio-pxa.c1
-rw-r--r--drivers/gpio/gpio-raspberrypi-exp.c4
-rw-r--r--drivers/gpio/gpio-rc5t583.c2
-rw-r--r--drivers/gpio/gpio-rcar.c1
-rw-r--r--drivers/gpio/gpio-rockchip.c2
-rw-r--r--drivers/gpio/gpio-sama5d2-piobu.c1
-rw-r--r--drivers/gpio/gpio-sch.c2
-rw-r--r--drivers/gpio/gpio-sifive.c48
-rw-r--r--drivers/gpio/gpio-sim.c300
-rw-r--r--drivers/gpio/gpio-sprd.c2
-rw-r--r--drivers/gpio/gpio-stp-xway.c3
-rw-r--r--drivers/gpio/gpio-syscon.c3
-rw-r--r--drivers/gpio/gpio-tegra.c2
-rw-r--r--drivers/gpio/gpio-tegra186.c2
-rw-r--r--drivers/gpio/gpio-timberdale.c2
-rw-r--r--drivers/gpio/gpio-tps65218.c2
-rw-r--r--drivers/gpio/gpio-tps6586x.c2
-rw-r--r--drivers/gpio/gpio-tps65910.c2
-rw-r--r--drivers/gpio/gpio-tqmx86.c2
-rw-r--r--drivers/gpio/gpio-ts4800.c3
-rw-r--r--drivers/gpio/gpio-ts4900.c2
-rw-r--r--drivers/gpio/gpio-uniphier.c1
-rw-r--r--drivers/gpio/gpio-vf610.c4
-rw-r--r--drivers/gpio/gpio-vx855.c2
-rw-r--r--drivers/gpio/gpio-wcd934x.c3
-rw-r--r--drivers/gpio/gpio-ws16c48.c552
-rw-r--r--drivers/gpio/gpio-xilinx.c4
-rw-r--r--drivers/gpio/gpio-xra1403.c6
-rw-r--r--drivers/gpio/gpio-zevio.c2
-rw-r--r--drivers/gpio/gpiolib-acpi.c2
-rw-r--r--drivers/gpio/gpiolib-cdev.c107
-rw-r--r--drivers/gpio/gpiolib-of.c26
-rw-r--r--drivers/gpio/gpiolib.c203
-rw-r--r--drivers/gpio/gpiolib.h20
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c5
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_utils.h2
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c24
-rw-r--r--drivers/gpu/drm/bridge/samsung-dsim.c27
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.h7
-rw-r--r--drivers/gpu/drm/i915/i915_driver.c33
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c6
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_devfreq.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_bo.h8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h12
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c35
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c6
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_shader.c3
-rw-r--r--drivers/gpu/ipu-v3/ipu-image-convert.c15
-rw-r--r--drivers/hid/bpf/entrypoints/Makefile2
-rw-r--r--drivers/hsi/controllers/omap_ssi_core.c1
-rw-r--r--drivers/hwmon/Kconfig24
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/ad7418.c4
-rw-r--r--drivers/hwmon/ads7828.c5
-rw-r--r--drivers/hwmon/adt7475.c3
-rw-r--r--drivers/hwmon/as370-hwmon.c3
-rw-r--r--drivers/hwmon/aspeed-pwm-tacho.c3
-rw-r--r--drivers/hwmon/asus-ec-sensors.c2
-rw-r--r--drivers/hwmon/bt1-pvt.c9
-rw-r--r--drivers/hwmon/g762.c1
-rw-r--r--drivers/hwmon/gxp-fan-ctrl.c2
-rw-r--r--drivers/hwmon/hp-wmi-sensors.c22
-rw-r--r--drivers/hwmon/hs3001.c242
-rw-r--r--drivers/hwmon/ina2xx.c3
-rw-r--r--drivers/hwmon/it87.c74
-rw-r--r--drivers/hwmon/k10temp.c8
-rw-r--r--drivers/hwmon/lan966x-hwmon.c24
-rw-r--r--drivers/hwmon/lm63.c4
-rw-r--r--drivers/hwmon/lm75.c3
-rw-r--r--drivers/hwmon/lm85.c4
-rw-r--r--drivers/hwmon/lm90.c4
-rw-r--r--drivers/hwmon/lochnagar-hwmon.c1
-rw-r--r--drivers/hwmon/ltq-cputemp.c3
-rw-r--r--drivers/hwmon/max31730.c1
-rw-r--r--drivers/hwmon/max6621.c2
-rw-r--r--drivers/hwmon/max6639.c6
-rw-r--r--drivers/hwmon/max6697.c3
-rw-r--r--drivers/hwmon/mcp3021.c1
-rw-r--r--drivers/hwmon/mlxreg-fan.c12
-rw-r--r--drivers/hwmon/nct6775-core.c361
-rw-r--r--drivers/hwmon/nct6775-platform.c2
-rw-r--r--drivers/hwmon/nct6775.h30
-rw-r--r--drivers/hwmon/nsa320-hwmon.c4
-rw-r--r--drivers/hwmon/oxp-sensors.c29
-rw-r--r--drivers/hwmon/peci/dimmtemp.c26
-rw-r--r--drivers/hwmon/pmbus/Kconfig7
-rw-r--r--drivers/hwmon/pmbus/acbel-fsg032.c38
-rw-r--r--drivers/hwmon/pmbus/dps920ab.c2
-rw-r--r--drivers/hwmon/pmbus/ibm-cffps.c4
-rw-r--r--drivers/hwmon/pmbus/ir38064.c4
-rw-r--r--drivers/hwmon/pmbus/max20730.c68
-rw-r--r--drivers/hwmon/pmbus/mp2975.c429
-rw-r--r--drivers/hwmon/pmbus/mp5023.c2
-rw-r--r--drivers/hwmon/pmbus/mpq7932.c2
-rw-r--r--drivers/hwmon/pmbus/pli1209bc.c26
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c4
-rw-r--r--drivers/hwmon/pmbus/q54sj108a2.c2
-rw-r--r--drivers/hwmon/pmbus/tps53679.c4
-rw-r--r--drivers/hwmon/pmbus/ucd9000.c4
-rw-r--r--drivers/hwmon/pmbus/ucd9200.c4
-rw-r--r--drivers/hwmon/sbtsi_temp.c1
-rw-r--r--drivers/hwmon/scpi-hwmon.c2
-rw-r--r--drivers/hwmon/sht3x.c387
-rw-r--r--drivers/hwmon/sis5595.c35
-rw-r--r--drivers/hwmon/smm665.c706
-rw-r--r--drivers/hwmon/tmp421.c2
-rw-r--r--drivers/hwmon/tmp464.c2
-rw-r--r--drivers/hwmon/tmp513.c7
-rw-r--r--drivers/hwmon/tps23861.c2
-rw-r--r--drivers/hwmon/ultra45_env.c3
-rw-r--r--drivers/hwmon/vexpress-hwmon.c1
-rw-r--r--drivers/hwmon/via686a.c18
-rw-r--r--drivers/hwmon/vt8231.c11
-rw-r--r--drivers/hwmon/w83773g.c2
-rw-r--r--drivers/idle/intel_idle.c10
-rw-r--r--drivers/infiniband/core/cache.c6
-rw-r--r--drivers/infiniband/hw/mlx4/main.c218
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h2
-rw-r--r--drivers/infiniband/hw/mlx5/Makefile1
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c2
-rw-r--r--drivers/infiniband/hw/mlx5/devx.c2
-rw-r--r--drivers/infiniband/hw/mlx5/macsec.c364
-rw-r--r--drivers/infiniband/hw/mlx5/macsec.h29
-rw-r--r--drivers/infiniband/hw/mlx5/main.c43
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h17
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c3
-rw-r--r--drivers/iommu/amd/iommu.c2
-rw-r--r--drivers/iommu/amd/iommu_v2.c10
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c29
-rw-r--r--drivers/iommu/hyperv-iommu.c4
-rw-r--r--drivers/iommu/intel/irq_remapping.c2
-rw-r--r--drivers/iommu/intel/svm.c8
-rw-r--r--drivers/irqchip/Kconfig1
-rw-r--r--drivers/irqchip/irq-bcm6345-l1.c1
-rw-r--r--drivers/irqchip/irq-bcm7038-l1.c1
-rw-r--r--drivers/irqchip/irq-brcmstb-l2.c1
-rw-r--r--drivers/irqchip/irq-gic-pm.c2
-rw-r--r--drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c2
-rw-r--r--drivers/irqchip/irq-i8259.c2
-rw-r--r--drivers/irqchip/irq-imx-intmux.c3
-rw-r--r--drivers/irqchip/irq-imx-irqsteer.c3
-rw-r--r--drivers/irqchip/irq-imx-mu-msi.c4
-rw-r--r--drivers/irqchip/irq-keystone.c2
-rw-r--r--drivers/irqchip/irq-loongson-eiointc.c2
-rw-r--r--drivers/irqchip/irq-loongson-htvec.c1
-rw-r--r--drivers/irqchip/irq-loongson-pch-pic.c2
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c3
-rw-r--r--drivers/irqchip/irq-madera.c4
-rw-r--r--drivers/irqchip/irq-meson-gpio.c5
-rw-r--r--drivers/irqchip/irq-mips-gic.c2
-rw-r--r--drivers/irqchip/irq-mvebu-sei.c3
-rw-r--r--drivers/irqchip/irq-orion.c3
-rw-r--r--drivers/irqchip/irq-pruss-intc.c6
-rw-r--r--drivers/irqchip/irq-qcom-mpm.c2
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c1
-rw-r--r--drivers/irqchip/irq-st.c2
-rw-r--r--drivers/irqchip/irq-stm32-exti.c3
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c1
-rw-r--r--drivers/irqchip/irq-tb10x.c1
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c4
-rw-r--r--drivers/irqchip/irq-ti-sci-intr.c4
-rw-r--r--drivers/irqchip/irq-uniphier-aidet.c1
-rw-r--r--drivers/irqchip/irq-xtensa-pic.c1
-rw-r--r--drivers/irqchip/irqchip.c2
-rw-r--r--drivers/irqchip/qcom-pdc.c1
-rw-r--r--drivers/leds/trigger/ledtrig-netdev.c18
-rw-r--r--drivers/md/Kconfig11
-rw-r--r--drivers/md/dm-crypt.c1
-rw-r--r--drivers/md/dm-raid.c1
-rw-r--r--drivers/md/md-bitmap.c347
-rw-r--r--drivers/md/md-bitmap.h1
-rw-r--r--drivers/md/md-cluster.c8
-rw-r--r--drivers/md/md-faulty.c2
-rw-r--r--drivers/md/md-linear.c1
-rw-r--r--drivers/md/md-multipath.c1
-rw-r--r--drivers/md/md.c228
-rw-r--r--drivers/md/md.h13
-rw-r--r--drivers/md/raid0.c98
-rw-r--r--drivers/md/raid1.c86
-rw-r--r--drivers/md/raid1.h1
-rw-r--r--drivers/md/raid10.c85
-rw-r--r--drivers/md/raid10.h1
-rw-r--r--drivers/md/raid5-cache.c14
-rw-r--r--drivers/md/raid5.c72
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c2
-rw-r--r--drivers/mfd/Kconfig23
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/cs42l43-i2c.c98
-rw-r--r--drivers/mfd/cs42l43-sdw.c239
-rw-r--r--drivers/mfd/cs42l43.c1188
-rw-r--r--drivers/mfd/cs42l43.h28
-rw-r--r--drivers/mfd/tps65086.c17
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/misc/ibmvmc.c2
-rw-r--r--drivers/misc/lkdtm/bugs.c51
-rw-r--r--drivers/misc/ocxl/link.c8
-rw-r--r--drivers/mmc/core/block.c11
-rw-r--r--drivers/mmc/core/bus.c3
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c6
-rw-r--r--drivers/mmc/core/pwrseq_sd8787.c6
-rw-r--r--drivers/mmc/core/pwrseq_simple.c6
-rw-r--r--drivers/mmc/core/sd.c14
-rw-r--r--drivers/mmc/core/sd_ops.c1
-rw-r--r--drivers/mmc/core/sd_ops.h2
-rw-r--r--drivers/mmc/host/Kconfig5
-rw-r--r--drivers/mmc/host/alcor.c6
-rw-r--r--drivers/mmc/host/atmel-mci.c140
-rw-r--r--drivers/mmc/host/au1xmmc.c5
-rw-r--r--drivers/mmc/host/bcm2835.c6
-rw-r--r--drivers/mmc/host/cavium-octeon.c7
-rw-r--r--drivers/mmc/host/cavium-thunderx.c1
-rw-r--r--drivers/mmc/host/cb710-mmc.c5
-rw-r--r--drivers/mmc/host/davinci_mmc.c9
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c6
-rw-r--r--drivers/mmc/host/dw_mmc-hi3798cv200.c6
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c6
-rw-r--r--drivers/mmc/host/jz4740_mmc.c6
-rw-r--r--drivers/mmc/host/litex_mmc.c5
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c11
-rw-r--r--drivers/mmc/host/meson-mx-sdhc-mmc.c6
-rw-r--r--drivers/mmc/host/meson-mx-sdio.c6
-rw-r--r--drivers/mmc/host/mmci.c39
-rw-r--r--drivers/mmc/host/moxart-mmc.c8
-rw-r--r--drivers/mmc/host/mtk-sd.c10
-rw-r--r--drivers/mmc/host/mvsdio.c6
-rw-r--r--drivers/mmc/host/mxcmmc.c10
-rw-r--r--drivers/mmc/host/mxs-mmc.c7
-rw-r--r--drivers/mmc/host/omap.c6
-rw-r--r--drivers/mmc/host/omap_hsmmc.c11
-rw-r--r--drivers/mmc/host/owl-mmc.c9
-rw-r--r--drivers/mmc/host/pxamci.c12
-rw-r--r--drivers/mmc/host/renesas_sdhi.h2
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c26
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c5
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c5
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c9
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c8
-rw-r--r--drivers/mmc/host/sdhci-acpi.c6
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c13
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c18
-rw-r--r--drivers/mmc/host/sdhci-cadence.c19
-rw-r--r--drivers/mmc/host/sdhci-dove.c8
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c15
-rw-r--r--drivers/mmc/host/sdhci-esdhc-mcf.c6
-rw-r--r--drivers/mmc/host/sdhci-iproc.c16
-rw-r--r--drivers/mmc/host/sdhci-milbeaut.c8
-rw-r--r--drivers/mmc/host/sdhci-msm.c7
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c14
-rw-r--r--drivers/mmc/host/sdhci-of-aspeed.c15
-rw-r--r--drivers/mmc/host/sdhci-of-at91.c10
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c93
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c2
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c4
-rw-r--r--drivers/mmc/host/sdhci-of-sparx5.c19
-rw-r--r--drivers/mmc/host/sdhci-omap.c7
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c4
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c211
-rw-r--r--drivers/mmc/host/sdhci-pci.h4
-rw-r--r--drivers/mmc/host/sdhci-pic32.c6
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c16
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h8
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c20
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c6
-rw-r--r--drivers/mmc/host/sdhci-s3c.c7
-rw-r--r--drivers/mmc/host/sdhci-spear.c10
-rw-r--r--drivers/mmc/host/sdhci-sprd.c156
-rw-r--r--drivers/mmc/host/sdhci-st.c15
-rw-r--r--drivers/mmc/host/sdhci-tegra.c7
-rw-r--r--drivers/mmc/host/sdhci-xenon.c6
-rw-r--r--drivers/mmc/host/sdhci_am654.c14
-rw-r--r--drivers/mmc/host/sdhci_f_sdh30.c10
-rw-r--r--drivers/mmc/host/sh_mmcif.c7
-rw-r--r--drivers/mmc/host/sunplus-mmc.c9
-rw-r--r--drivers/mmc/host/sunxi-mmc.c6
-rw-r--r--drivers/mmc/host/uniphier-sd.c19
-rw-r--r--drivers/mmc/host/usdhi6rol0.c6
-rw-r--r--drivers/mmc/host/via-sdmmc.c2
-rw-r--r--drivers/mmc/host/wbsd.c9
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c7
-rw-r--r--drivers/net/Kconfig24
-rw-r--r--drivers/net/arcnet/arcnet.c2
-rw-r--r--drivers/net/bonding/bond_alb.c8
-rw-r--r--drivers/net/bonding/bond_debugfs.c15
-rw-r--r--drivers/net/bonding/bond_main.c139
-rw-r--r--drivers/net/bonding/bond_sysfs.c4
-rw-r--r--drivers/net/can/Kconfig9
-rw-r--r--drivers/net/can/bxcan.c1
-rw-r--r--drivers/net/can/c_can/c_can_platform.c4
-rw-r--r--drivers/net/can/dev/rx-offload.c36
-rw-r--r--drivers/net/can/flexcan/flexcan-core.c16
-rw-r--r--drivers/net/can/grcan.c3
-rw-r--r--drivers/net/can/ifi_canfd/ifi_canfd.c1
-rw-r--r--drivers/net/can/kvaser_pciefd.c307
-rw-r--r--drivers/net/can/m_can/m_can.c57
-rw-r--r--drivers/net/can/m_can/m_can.h5
-rw-r--r--drivers/net/can/m_can/m_can_platform.c21
-rw-r--r--drivers/net/can/m_can/tcan4x5x-core.c142
-rw-r--r--drivers/net/can/m_can/tcan4x5x-regmap.c1
-rw-r--r--drivers/net/can/rcar/rcar_canfd.c1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c6
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c1
-rw-r--r--drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c6
-rw-r--r--drivers/net/can/sun4i_can.c23
-rw-r--r--drivers/net/can/ti_hecc.c5
-rw-r--r--drivers/net/can/usb/Kconfig1
-rw-r--r--drivers/net/can/usb/esd_usb.c275
-rw-r--r--drivers/net/can/usb/gs_usb.c187
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c13
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.h2
-rw-r--r--drivers/net/can/usb/ucan.c2
-rw-r--r--drivers/net/can/vxcan.c7
-rw-r--r--drivers/net/can/xilinx_can.c25
-rw-r--r--drivers/net/dsa/Kconfig3
-rw-r--r--drivers/net/dsa/b53/b53_common.c6
-rw-r--r--drivers/net/dsa/b53/b53_mdio.c1
-rw-r--r--drivers/net/dsa/b53/b53_mmap.c1
-rw-r--r--drivers/net/dsa/b53/b53_serdes.c2
-rw-r--r--drivers/net/dsa/b53/b53_serdes.h2
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek.c3
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek.h2
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c9
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek_ptp.c1
-rw-r--r--drivers/net/dsa/lan9303-core.c7
-rw-r--r--drivers/net/dsa/microchip/ksz8.h2
-rw-r--r--drivers/net/dsa/microchip/ksz8863_smi.c3
-rw-r--r--drivers/net/dsa/microchip/ksz9477.h2
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c4
-rw-r--r--drivers/net/dsa/mt7530-mmio.c3
-rw-r--r--drivers/net/dsa/mt7530.c10
-rw-r--r--drivers/net/dsa/mt7530.h2
-rw-r--r--drivers/net/dsa/mv88e6060.c45
-rw-r--r--drivers/net/dsa/mv88e6xxx/Makefile3
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c426
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h33
-rw-r--r--drivers/net/dsa/mv88e6xxx/pcs-6185.c190
-rw-r--r--drivers/net/dsa/mv88e6xxx/pcs-6352.c390
-rw-r--r--drivers/net/dsa/mv88e6xxx/pcs-639x.c943
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c30
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c1106
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h108
-rw-r--r--drivers/net/dsa/ocelot/felix.c6
-rw-r--r--drivers/net/dsa/ocelot/felix_vsc9959.c12
-rw-r--r--drivers/net/dsa/ocelot/seville_vsc9953.c3
-rw-r--r--drivers/net/dsa/qca/ar9331.c2
-rw-r--r--drivers/net/dsa/qca/qca8k-8xxx.c198
-rw-r--r--drivers/net/dsa/qca/qca8k-common.c48
-rw-r--r--drivers/net/dsa/qca/qca8k-leds.c1
-rw-r--r--drivers/net/dsa/qca/qca8k.h6
-rw-r--r--drivers/net/dsa/realtek/realtek-mdio.c4
-rw-r--r--drivers/net/dsa/realtek/realtek-smi.c3
-rw-r--r--drivers/net/dsa/realtek/rtl8366rb.c28
-rw-r--r--drivers/net/dsa/rzn1_a5psw.c236
-rw-r--r--drivers/net/dsa/rzn1_a5psw.h8
-rw-r--r--drivers/net/dsa/sja1105/sja1105_flower.c8
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c7
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx-core.c1
-rw-r--r--drivers/net/dsa/xrs700x/xrs700x.c2
-rw-r--r--drivers/net/ethernet/8390/ne2k-pci.c16
-rw-r--r--drivers/net/ethernet/adi/adin1110.c8
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c4
-rw-r--r--drivers/net/ethernet/agere/et131x.c3
-rw-r--r--drivers/net/ethernet/alacritech/slicoss.c4
-rw-r--r--drivers/net/ethernet/altera/Kconfig1
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c2
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.h1
-rw-r--r--drivers/net/ethernet/amd/atarilance.c2
-rw-r--r--drivers/net/ethernet/amd/pds_core/auxbus.c2
-rw-r--r--drivers/net/ethernet/amd/pds_core/core.c11
-rw-r--r--drivers/net/ethernet/amd/pds_core/dev.c9
-rw-r--r--drivers/net/ethernet/amd/pds_core/devlink.c3
-rw-r--r--drivers/net/ethernet/amd/pds_core/main.c6
-rw-r--r--drivers/net/ethernet/amd/sunlance.c2
-rw-r--r--drivers/net/ethernet/apm/xgene-v2/main.h1
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c6
-rw-r--r--drivers/net/ethernet/apple/macmace.c2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c12
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c2
-rw-r--r--drivers/net/ethernet/arc/emac_main.c2
-rw-r--r--drivers/net/ethernet/atheros/ag71xx.c3
-rw-r--r--drivers/net/ethernet/atheros/alx/ethtool.c5
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig12
-rw-r--r--drivers/net/ethernet/broadcom/Makefile1
-rw-r--r--drivers/net/ethernet/broadcom/asp2/Makefile2
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp.c1437
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp.h586
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c503
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c1415
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h257
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c3
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c21
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c32
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c17
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c311
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h27
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c26
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c49
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h644
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c6
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c6
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c4
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c13
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c13
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c18
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c18
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h1
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c2
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c6
-rw-r--r--drivers/net/ethernet/cortina/gemini.c8
-rw-r--r--drivers/net/ethernet/davicom/dm9051.c9
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c3
-rw-r--r--drivers/net/ethernet/engleder/tsnep.h1
-rw-r--r--drivers/net/ethernet/engleder/tsnep_main.c3
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c5
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c16
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c50
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c12
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.h1
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c2
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c1
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h1
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c22
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c1
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h1
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ierb.c2
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ptp.c2
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_qos.c8
-rw-r--r--drivers/net/ethernet/freescale/fec.h18
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c314
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c10
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx_phy.c9
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c60
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c1
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_port.c1
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.c6
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.h4
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c7
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet.h24
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fcc.c5
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fec.c15
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-scc.c9
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c10
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-fec.c7
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c7
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c8
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c2
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c9
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c4
-rw-r--r--drivers/net/ethernet/fungible/funeth/funeth_txrx.h1
-rw-r--r--drivers/net/ethernet/google/gve/gve.h113
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.c89
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.h10
-rw-r--r--drivers/net/ethernet/google/gve/gve_desc.h4
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c20
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx_dqo.c126
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx_dqo.c404
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hisi_femac.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c5
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/Makefile4
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h8
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c576
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h3
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c668
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h17
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c121
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h1
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c164
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h13
-rw-r--r--drivers/net/ethernet/hisilicon/hns_mdio.c10
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c1
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c1
-rw-r--r--drivers/net/ethernet/ibm/emac/core.h1
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c2
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c2
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c2
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c2
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c3
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000.h1
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.h3
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h3
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c7
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c8
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.c49
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.h3
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c116
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_dcb.c20
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ddp.c6
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c4
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_diag.c6
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_hmc.c21
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c54
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c77
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_nvm.c52
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h17
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_status.h43
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c4
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h9
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c253
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c101
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h6
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.c4
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_client.h2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c18
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c75
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h31
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h107
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c285
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_nl.c50
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ddp.c120
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ddp.h10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c50
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch_br.c1346
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch_br.h120
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fw_update.c45
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hw_autogen.h3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.c1838
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.h34
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c129
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c181
-rw-r--r--drivers/net/ethernet/intel/ice/ice_protocol_type.h9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.c438
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.h10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.h3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c39
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.h25
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c8
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c309
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.h37
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tc_lib.c78
-rw-r--r--drivers/net/ethernet/intel/ice/ice_trace.h90
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c499
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib_private.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c186
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl.c11
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c84
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.h8
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vsi_vlan_ops.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c221
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c19
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c24
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h19
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.h3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h11
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c76
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c174
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h6
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h3
-rw-r--r--drivers/net/ethernet/korina.c2
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c4
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c2
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h2
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c10
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c2
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_cp_version.h11
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c9
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h6
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c37
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h4
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.c37
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h26
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc.h4
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/ptp.c155
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/ptp.h3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rpm.c17
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.c2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c9
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c35
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c20
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c6
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c26
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h22
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c19
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c177
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c470
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/qos.c398
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/qos.h11
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_flower.c20
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_rxtx.c3
-rw-r--r--drivers/net/ethernet/marvell/sky2.c3
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_path.c36
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c694
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.h376
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe.c56
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe.h22
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe_offload.c2
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe_regs.h2
-rw-r--r--drivers/net/ethernet/mediatek/mtk_star_emac.c1
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed.c17
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_debugfs.c24
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_regs.h2
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_wo.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/Kconfig1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/catas.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c155
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c66
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c15
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/intf.c363
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c118
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h18
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c223
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/debugfs.c34
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/dev.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/health.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/params.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c237
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h59
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/qos.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c65
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/trap.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c62
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h77
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c773
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c176
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h26
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c1394
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h47
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_stats.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c15
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c30
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.h17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c136
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c360
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c195
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec.c369
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c325
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h67
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c202
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h129
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c665
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.c51
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c59
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c39
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/hwmon.c418
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/hwmon.h24
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c78
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c32
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c449
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h74
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c2411
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h64
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c51
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h26
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c74
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c49
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c119
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/thermal.c114
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/thermal.h20
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Makefile2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c40
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_env.c45
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/i2c.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h175
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/resources.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c368
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c98
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_port_range.c200
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c626
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c193
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.c2
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c1
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.c65
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.h15
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c38
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c4
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.h10
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c35
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c24
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c6
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_api.c4
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_api.h3
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_api_client.h3
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_tc.c18
-rw-r--r--drivers/net/ethernet/microchip/vcap/vcap_tc.h2
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c35
-rw-r--r--drivers/net/ethernet/microsoft/mana/hw_channel.c24
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c142
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c15
-rw-r--r--drivers/net/ethernet/mscc/ocelot.h2
-rw-r--r--drivers/net/ethernet/mscc/ocelot_fdma.c1
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c28
-rw-r--r--drivers/net/ethernet/mscc/ocelot_vcap.h1
-rw-r--r--drivers/net/ethernet/mscc/ocelot_vsc7514.c3
-rw-r--r--drivers/net/ethernet/neterion/s2io.c17
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/conntrack.c43
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/offload.c64
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c57
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h1
-rw-r--r--drivers/net/ethernet/ni/nixge.c5
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic.h1
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c160
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_dev.h1
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c70
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.h5
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_vf.c45
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede.h3
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_filter.c12
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.c2
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c1
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c1
-rw-r--r--drivers/net/ethernet/qualcomm/qca_uart.c3
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c4
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c3
-rw-r--r--drivers/net/ethernet/renesas/rswitch.c32
-rw-r--r--drivers/net/ethernet/renesas/rswitch.h1
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c2
-rw-r--r--drivers/net/ethernet/sfc/Makefile2
-rw-r--r--drivers/net/ethernet/sfc/bitfield.h2
-rw-r--r--drivers/net/ethernet/sfc/ef10.c4
-rw-r--r--drivers/net/ethernet/sfc/ef100_nic.c2
-rw-r--r--drivers/net/ethernet/sfc/ef100_tx.c6
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.h2
-rw-r--r--drivers/net/ethernet/sfc/efx.c1
-rw-r--r--drivers/net/ethernet/sfc/efx.h2
-rw-r--r--drivers/net/ethernet/sfc/efx_channels.c30
-rw-r--r--drivers/net/ethernet/sfc/efx_common.c7
-rw-r--r--drivers/net/ethernet/sfc/falcon/selftest.c2
-rw-r--r--drivers/net/ethernet/sfc/farch_regs.h2929
-rw-r--r--drivers/net/ethernet/sfc/filter.h7
-rw-r--r--drivers/net/ethernet/sfc/io.h86
-rw-r--r--drivers/net/ethernet/sfc/mae.c916
-rw-r--r--drivers/net/ethernet/sfc/mae.h16
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c7
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h14
-rw-r--r--drivers/net/ethernet/sfc/mcdi_functions.c24
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port_common.c5
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h63
-rw-r--r--drivers/net/ethernet/sfc/nic.c158
-rw-r--r--drivers/net/ethernet/sfc/nic.h178
-rw-r--r--drivers/net/ethernet/sfc/nic_common.h13
-rw-r--r--drivers/net/ethernet/sfc/ptp.c231
-rw-r--r--drivers/net/ethernet/sfc/selftest.c9
-rw-r--r--drivers/net/ethernet/sfc/siena/io.h2
-rw-r--r--drivers/net/ethernet/sfc/siena/selftest.c2
-rw-r--r--drivers/net/ethernet/sfc/tc.c1076
-rw-r--r--drivers/net/ethernet/sfc/tc.h144
-rw-r--r--drivers/net/ethernet/sfc/tc_conntrack.c533
-rw-r--r--drivers/net/ethernet/sfc/tc_conntrack.h55
-rw-r--r--drivers/net/ethernet/sfc/tc_counters.c8
-rw-r--r--drivers/net/ethernet/sfc/tc_counters.h4
-rw-r--r--drivers/net/ethernet/sfc/tx.c45
-rw-r--r--drivers/net/ethernet/sfc/tx_tso.c2
-rw-r--r--drivers/net/ethernet/sfc/vfdi.h252
-rw-r--r--drivers/net/ethernet/sfc/workarounds.h7
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c5
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.c7
-rw-r--r--drivers/net/ethernet/socionext/netsec.c2
-rw-r--r--drivers/net/ethernet/socionext/sni_ave.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h78
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c65
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c27
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c245
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c57
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c23
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c7
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c50
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c53
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c123
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c47
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c417
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c6
-rw-r--r--drivers/net/ethernet/sun/ldmvsw.c3
-rw-r--r--drivers/net/ethernet/sun/niu.c2
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c2
-rw-r--r--drivers/net/ethernet/sun/sungem.c1
-rw-r--r--drivers/net/ethernet/sun/sunhme.c3
-rw-r--r--drivers/net/ethernet/sun/sunqe.c2
-rw-r--r--drivers/net/ethernet/ti/Kconfig25
-rw-r--r--drivers/net/ethernet/ti/Makefile11
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c1
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h1
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-qos.c6
-rw-r--r--drivers/net/ethernet/ti/cpsw-common.c1
-rw-r--r--drivers/net/ethernet/ti/cpsw-phy-sel.c1
-rw-r--r--drivers/net/ethernet/ti/cpsw.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw_new.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw_priv.c8
-rw-r--r--drivers/net/ethernet/ti/cpsw_priv.h1
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c1
-rw-r--r--drivers/net/ethernet/ti/icssg/icss_iep.c965
-rw-r--r--drivers/net/ethernet/ti/icssg/icss_iep.h41
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_classifier.c367
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_config.c457
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_config.h200
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_ethtool.c209
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c120
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_mii_rt.h151
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.c2336
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.h286
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_queues.c50
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_stats.c57
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_stats.h158
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_switch_map.h234
-rw-r--r--drivers/net/ethernet/ti/netcp.h2
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c3
-rw-r--r--drivers/net/ethernet/via/via-rhine.c2
-rw-r--r--drivers/net/ethernet/via/via-velocity.c2
-rw-r--r--drivers/net/ethernet/wangxun/Kconfig1
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.c68
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.h2
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.c2
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_type.h34
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c35
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_main.c64
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c88
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_type.h19
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c39
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h2
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_main.c56
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c188
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac.h1
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_mdio.c2
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c3
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c4
-rw-r--r--drivers/net/gtp.c3
-rw-r--r--drivers/net/hyperv/hyperv_net.h1
-rw-r--r--drivers/net/ieee802154/ca8210.c1
-rw-r--r--drivers/net/ipa/ipa_main.c2
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c3
-rw-r--r--drivers/net/macsec.c29
-rw-r--r--drivers/net/macvlan.c34
-rw-r--r--drivers/net/mdio/mdio-bcm-unimac.c2
-rw-r--r--drivers/net/mdio/mdio-bitbang.c4
-rw-r--r--drivers/net/mdio/mdio-xgene.c9
-rw-r--r--drivers/net/mhi_net.c1
-rw-r--r--drivers/net/netconsole.c163
-rw-r--r--drivers/net/netdevsim/Makefile4
-rw-r--r--drivers/net/netdevsim/ethtool.c11
-rw-r--r--drivers/net/netdevsim/macsec.c356
-rw-r--r--drivers/net/netdevsim/netdev.c41
-rw-r--r--drivers/net/netdevsim/netdevsim.h36
-rw-r--r--drivers/net/pcs/Makefile2
-rw-r--r--drivers/net/pcs/pcs-lynx.c2
-rw-r--r--drivers/net/pcs/pcs-mtk-lynxi.c8
-rw-r--r--drivers/net/pcs/pcs-rzn1-miic.c1
-rw-r--r--drivers/net/pcs/pcs-xpcs-wx.c209
-rw-r--r--drivers/net/pcs/pcs-xpcs.c112
-rw-r--r--drivers/net/pcs/pcs-xpcs.h17
-rw-r--r--drivers/net/phy/Kconfig9
-rw-r--r--drivers/net/phy/Makefile3
-rw-r--r--drivers/net/phy/at803x.c135
-rw-r--r--drivers/net/phy/bcm7xxx.c1
-rw-r--r--drivers/net/phy/dp83640.c15
-rw-r--r--drivers/net/phy/marvell-88q2xxx.c263
-rw-r--r--drivers/net/phy/marvell-88x2222.c1
-rw-r--r--drivers/net/phy/marvell.c281
-rw-r--r--drivers/net/phy/mdio_bus.c37
-rw-r--r--drivers/net/phy/mediatek-ge-soc.c437
-rw-r--r--drivers/net/phy/motorcomm.c118
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.c1136
-rw-r--r--drivers/net/phy/phy-c45.c63
-rw-r--r--drivers/net/phy/phy-core.c2
-rw-r--r--drivers/net/phy/phy.c45
-rw-r--r--drivers/net/phy/phy_device.c96
-rw-r--r--drivers/net/phy/phylink.c199
-rw-r--r--drivers/net/phy/sfp-bus.c10
-rw-r--r--drivers/net/phy/sfp.c3
-rw-r--r--drivers/net/phy/sfp.h1
-rw-r--r--drivers/net/phy/smsc.c252
-rw-r--r--drivers/net/phy/stubs.c10
-rw-r--r--drivers/net/ppp/pppoe.c4
-rw-r--r--drivers/net/ppp/pptp.c8
-rw-r--r--drivers/net/tap.c5
-rw-r--r--drivers/net/team/team.c65
-rw-r--r--drivers/net/team/team_mode_activebackup.c8
-rw-r--r--drivers/net/team/team_mode_broadcast.c1
-rw-r--r--drivers/net/team/team_mode_loadbalance.c50
-rw-r--r--drivers/net/team/team_mode_roundrobin.c1
-rw-r--r--drivers/net/tun.c11
-rw-r--r--drivers/net/usb/r8152.c108
-rw-r--r--drivers/net/veth.c12
-rw-r--r--drivers/net/virtio_net.c215
-rw-r--r--drivers/net/vmxnet3/Makefile2
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c236
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c23
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h43
-rw-r--r--drivers/net/vmxnet3/vmxnet3_xdp.c419
-rw-r--r--drivers/net/vmxnet3/vmxnet3_xdp.h47
-rw-r--r--drivers/net/vrf.c5
-rw-r--r--drivers/net/vxlan/vxlan_core.c57
-rw-r--r--drivers/net/vxlan/vxlan_vnifilter.c2
-rw-r--r--drivers/net/wireguard/netlink.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c43
-rw-r--r--drivers/net/wireless/ath/ath11k/ce.h3
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c38
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_tx.c12
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.h3
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c68
-rw-r--r--drivers/net/wireless/ath/ath11k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.c35
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.h5
-rw-r--r--drivers/net/wireless/ath/ath11k/testmode.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/ce.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h35
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.c30
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c13
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_tx.c10
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c594
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/rx_desc.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c280
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h121
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c29
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c53
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c108
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/tx99.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c6
-rw-r--r--drivers/net/wireless/ath/key.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h6
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx_edma.h6
-rw-r--r--drivers/net/wireless/atmel/at76c50x-usb.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.h8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/pub.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/scb.h14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/types.h9
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c39
-rw-r--r--drivers/net/wireless/intel/iwlwifi/Kconfig1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/debug.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dump.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-fh.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mei/main.c70
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/queue/tx.c142
-rw-r--r--drivers/net/wireless/intel/iwlwifi/queue/tx.h26
-rw-r--r--drivers/net/wireless/intersil/orinoco/airport.c2
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_usb.c12
-rw-r--r--drivers/net/wireless/legacy/rndis_wlan.c2
-rw-r--r--drivers/net/wireless/marvell/libertas/if_sdio.c73
-rw-r--r--drivers/net/wireless/marvell/libertas/if_spi.c20
-rw-r--r--drivers/net/wireless/marvell/libertas/mesh.c51
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c1
-rw-r--r--drivers/net/wireless/marvell/mwifiex/debugfs.c19
-rw-r--r--drivers/net/wireless/marvell/mwifiex/decl.h1
-rw-r--r--drivers/net/wireless/marvell/mwifiex/init.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c11
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.h20
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c25
-rw-r--r--drivers/net/wireless/marvell/mwifiex/scan.c7
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sdio.c26
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_rx.c12
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_tx.c15
-rw-r--r--drivers/net/wireless/marvell/mwifiex/tdls.c9
-rw-r--r--drivers/net/wireless/marvell/mwifiex/txrx.c44
-rw-r--r--drivers/net/wireless/marvell/mwifiex/uap_txrx.c45
-rw-r--r--drivers/net/wireless/marvell/mwifiex/util.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/Kconfig8
-rw-r--r--drivers/net/wireless/mediatek/mt76/Makefile10
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/eeprom.c87
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h107
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/Kconfig2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/beacon.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c43
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/main.c25
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/regs.h7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/Kconfig2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c31
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c49
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615_trace.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac.h20
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c182
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h339
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c106
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_trace.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/Kconfig8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/coredump.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c128
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c152
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c20
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c194
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.h7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c233
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c151
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mmio.c47
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h100
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/soc.c163
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/Kconfig4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/Makefile9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h105
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c228
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c343
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.c554
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c806
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c230
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h359
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci.c225
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c34
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c71
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regs.h465
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/sdio.c32
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c14
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/testmode.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/trace.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/usb.c205
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c255
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x.h367
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c (renamed from drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c)128
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h105
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_core.c844
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_debugfs.c168
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_dma.c (renamed from drivers/net/wireless/mediatek/mt76/mt7921/dma.c)336
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_mac.c385
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_regs.h479
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_trace.c14
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_trace.h (renamed from drivers/net/wireless/mediatek/mt76/mt7921/mt7921_trace.h)16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_usb.c309
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/Kconfig2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/dma.c83
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/init.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c300
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.h315
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c114
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.c182
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.h17
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h94
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/pci.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/regs.h21
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/trace.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb_trace.h2
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Kconfig2
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.h4
-rw-r--r--drivers/net/wireless/microchip/wilc1000/sdio.c103
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c148
-rw-r--r--drivers/net/wireless/purelifi/plfxlc/Kconfig2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/Kconfig2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c59
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/core.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c28
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.h2
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c13
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h9
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/ps.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.c25
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.h7
-rw-r--r--drivers/net/wireless/realtek/rtw88/util.c7
-rw-r--r--drivers/net/wireless/realtek/rtw88/util.h3
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.c124
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.h5
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.h9
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c156
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h350
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c83
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c690
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h372
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c200
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h69
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c14
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac_be.c38
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c374
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.h114
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy_be.c77
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.c75
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.h4
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h38
-rw-r--r--drivers/net/wireless/realtek/rtw89/regd.c27
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851b.c20
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a.c21
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b.c20
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.c26
-rw-r--r--drivers/net/wireless/realtek/rtw89/sar.c220
-rw-r--r--drivers/net/wireless/realtek/rtw89/sar.h10
-rw-r--r--drivers/net/wireless/realtek/rtw89/ser.c20
-rw-r--r--drivers/net/wireless/realtek/rtw89/txrx.h47
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.c3
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_coex.c11
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_debugfs.c3
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_hal.c2
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_main.c4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c39
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio_ops.c15
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb.c20
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb_ops.c2
-rw-r--r--drivers/net/wireless/silabs/wfx/bus_sdio.c2
-rw-r--r--drivers/net/wireless/silabs/wfx/main.c7
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c13
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c2
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c18
-rw-r--r--drivers/net/wireless/zydas/zd1201.c6
-rw-r--r--drivers/net/wireless/zydas/zd1211rw/zd_usb.c2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_cldma.c17
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_cldma.h2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_mhccif.h1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_modem_ops.c76
-rw-r--r--drivers/net/wwan/t7xx/t7xx_modem_ops.h2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port.h6
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c8
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_proxy.c18
-rw-r--r--drivers/net/wwan/t7xx/t7xx_reg.h2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_state_monitor.c13
-rw-r--r--drivers/net/wwan/t7xx/t7xx_state_monitor.h2
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/nfc/virtual_ncidev.c13
-rw-r--r--drivers/nvdimm/pfn_devs.c2
-rw-r--r--drivers/nvme/host/ioctl.c1
-rw-r--r--drivers/nvme/target/io-cmd-bdev.c3
-rw-r--r--drivers/of/dynamic.c31
-rw-r--r--drivers/of/kexec.c3
-rw-r--r--drivers/of/platform.c4
-rw-r--r--drivers/of/unittest.c4
-rw-r--r--drivers/opp/core.c117
-rw-r--r--drivers/opp/cpu.c4
-rw-r--r--drivers/parisc/Kconfig3
-rw-r--r--drivers/parisc/Makefile16
-rw-r--r--drivers/parisc/asp.c11
-rw-r--r--drivers/parisc/ccio-dma.c25
-rw-r--r--drivers/parisc/dino.c6
-rw-r--r--drivers/parisc/eisa.c5
-rw-r--r--drivers/parisc/gsc.c15
-rw-r--r--drivers/parisc/hppb.c7
-rw-r--r--drivers/parisc/iosapic.c12
-rw-r--r--drivers/parisc/lasi.c37
-rw-r--r--drivers/parisc/lba_pci.c8
-rw-r--r--drivers/parisc/led.c901
-rw-r--r--drivers/parisc/sba_iommu.c7
-rw-r--r--drivers/parisc/wax.c12
-rw-r--r--drivers/pci/xen-pcifront.c6
-rw-r--r--drivers/perf/Kconfig2
-rw-r--r--drivers/perf/alibaba_uncore_drw_pmu.c27
-rw-r--r--drivers/perf/amlogic/meson_ddr_pmu_core.c2
-rw-r--r--drivers/perf/arm-cci.c5
-rw-r--r--drivers/perf/arm-cmn.c161
-rw-r--r--drivers/perf/arm_dmc620_pmu.c19
-rw-r--r--drivers/perf/arm_dsu_pmu.c2
-rw-r--r--drivers/perf/arm_pmu.c10
-rw-r--r--drivers/perf/arm_pmu_acpi.c137
-rw-r--r--drivers/perf/arm_pmu_platform.c1
-rw-r--r--drivers/perf/arm_pmuv3.c33
-rw-r--r--drivers/perf/arm_smmuv3_pmu.c47
-rw-r--r--drivers/perf/arm_spe_pmu.c3
-rw-r--r--drivers/perf/fsl_imx8_ddr_perf.c48
-rw-r--r--drivers/perf/fsl_imx9_ddr_perf.c4
-rw-r--r--drivers/perf/hisilicon/hisi_pcie_pmu.c17
-rw-r--r--drivers/perf/marvell_cn10k_ddr_pmu.c3
-rw-r--r--drivers/perf/marvell_cn10k_tad_pmu.c3
-rw-r--r--drivers/perf/xgene_pmu.c4
-rw-r--r--drivers/pinctrl/cirrus/Kconfig11
-rw-r--r--drivers/pinctrl/cirrus/Makefile2
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs42l43.c609
-rw-r--r--drivers/pinctrl/pinctrl-amd.c30
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza2.c17
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c15
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzv2m.c13
-rw-r--r--drivers/platform/chrome/chromeos_acpi.c33
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c4
-rw-r--r--drivers/platform/mellanox/mlxbf-tmfifo.c1
-rw-r--r--drivers/platform/x86/eeepc-laptop.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c5
-rw-r--r--drivers/platform/x86/intel/ifs/load.c7
-rw-r--r--drivers/platform/x86/intel/pmc/core.c2
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_if_common.c2
-rw-r--r--drivers/platform/x86/lenovo-ymc.c7
-rw-r--r--drivers/pnp/pnpacpi/core.c3
-rw-r--r--drivers/power/reset/Kconfig7
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/as3722-poweroff.c1
-rw-r--r--drivers/power/reset/at91-poweroff.c4
-rw-r--r--drivers/power/reset/at91-reset.c37
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c4
-rw-r--r--drivers/power/reset/brcm-kona-reset.c8
-rw-r--r--drivers/power/reset/gemini-poweroff.c4
-rw-r--r--drivers/power/reset/gpio-poweroff.c3
-rw-r--r--drivers/power/reset/gpio-restart.c2
-rw-r--r--drivers/power/reset/keystone-reset.c3
-rw-r--r--drivers/power/reset/msm-poweroff.c6
-rw-r--r--drivers/power/reset/ocelot-reset.c9
-rw-r--r--drivers/power/reset/odroid-go-ultra-poweroff.c3
-rw-r--r--drivers/power/reset/oxnas-restart.c233
-rw-r--r--drivers/power/reset/st-poweroff.c2
-rw-r--r--drivers/power/reset/syscon-poweroff.c3
-rw-r--r--drivers/power/reset/syscon-reboot.c3
-rw-r--r--drivers/power/reset/xgene-reboot.c2
-rw-r--r--drivers/power/supply/axp20x_ac_power.c1
-rw-r--r--drivers/power/supply/axp20x_battery.c1
-rw-r--r--drivers/power/supply/axp20x_usb_power.c1
-rw-r--r--drivers/power/supply/bd99954-charger.c2
-rw-r--r--drivers/power/supply/bq24190_charger.c17
-rw-r--r--drivers/power/supply/cpcap-battery.c2
-rw-r--r--drivers/power/supply/da9150-charger.c2
-rw-r--r--drivers/power/supply/da9150-fg.c1
-rw-r--r--drivers/power/supply/lego_ev3_battery.c2
-rw-r--r--drivers/power/supply/ltc2941-battery-gauge.c2
-rw-r--r--drivers/power/supply/ltc4162-l-charger.c2
-rw-r--r--drivers/power/supply/max14656_charger_detector.c2
-rw-r--r--drivers/power/supply/max17040_battery.c2
-rw-r--r--drivers/power/supply/max8903_charger.c1
-rw-r--r--drivers/power/supply/power_supply_core.c6
-rw-r--r--drivers/power/supply/qcom_pmi8998_charger.c13
-rw-r--r--drivers/power/supply/rn5t618_power.c1
-rw-r--r--drivers/power/supply/rt5033_charger.c2
-rw-r--r--drivers/power/supply/rt9455_charger.c3
-rw-r--r--drivers/power/supply/sbs-battery.c2
-rw-r--r--drivers/power/supply/tps65090-charger.c2
-rw-r--r--drivers/power/supply/tps65217_charger.c1
-rw-r--r--drivers/power/supply/twl4030_charger.c1
-rw-r--r--drivers/powercap/arm_scmi_powercap.c159
-rw-r--r--drivers/powercap/intel_rapl_common.c4
-rw-r--r--drivers/powercap/intel_rapl_msr.c2
-rw-r--r--drivers/ptp/Kconfig11
-rw-r--r--drivers/ptp/Makefile1
-rw-r--r--drivers/ptp/ptp_mock.c175
-rw-r--r--drivers/ptp/ptp_qoriq.c2
-rw-r--r--drivers/regulator/Kconfig53
-rw-r--r--drivers/regulator/Makefile6
-rw-r--r--drivers/regulator/act8945a-regulator.c2
-rw-r--r--drivers/regulator/atc260x-regulator.c7
-rw-r--r--drivers/regulator/aw37503-regulator.c240
-rw-r--r--drivers/regulator/axp20x-regulator.c1
-rw-r--r--drivers/regulator/bd71815-regulator.c1
-rw-r--r--drivers/regulator/bd71828-regulator.c1
-rw-r--r--drivers/regulator/bd718x7-regulator.c22
-rw-r--r--drivers/regulator/cpcap-regulator.c2
-rw-r--r--drivers/regulator/da9062-regulator.c11
-rw-r--r--drivers/regulator/da9121-regulator.c18
-rw-r--r--drivers/regulator/fan53555.c2
-rw-r--r--drivers/regulator/fixed.c1
-rw-r--r--drivers/regulator/helpers.c15
-rw-r--r--drivers/regulator/hi6421-regulator.c20
-rw-r--r--drivers/regulator/lp872x.c2
-rw-r--r--drivers/regulator/lp8755.c1
-rw-r--r--drivers/regulator/lp87565-regulator.c4
-rw-r--r--drivers/regulator/ltc3589.c4
-rw-r--r--drivers/regulator/max20086-regulator.c1
-rw-r--r--drivers/regulator/max5970-regulator.c (renamed from drivers/regulator/max597x-regulator.c)28
-rw-r--r--drivers/regulator/max77541-regulator.c6
-rw-r--r--drivers/regulator/max77650-regulator.c2
-rw-r--r--drivers/regulator/max77826-regulator.c1
-rw-r--r--drivers/regulator/max77857-regulator.c461
-rw-r--r--drivers/regulator/max8893.c4
-rw-r--r--drivers/regulator/mcp16502.c7
-rw-r--r--drivers/regulator/mp5416.c2
-rw-r--r--drivers/regulator/mp886x.c2
-rw-r--r--drivers/regulator/mpq7920.c3
-rw-r--r--drivers/regulator/mt6311-regulator.c1
-rw-r--r--drivers/regulator/mt6315-regulator.c2
-rw-r--r--drivers/regulator/mt6359-regulator.c2
-rw-r--r--drivers/regulator/mtk-dvfsrc-regulator.c3
-rw-r--r--drivers/regulator/pbias-regulator.c1
-rw-r--r--drivers/regulator/pca9450-regulator.c1
-rw-r--r--drivers/regulator/pfuze100-regulator.c3
-rw-r--r--drivers/regulator/pwm-regulator.c2
-rw-r--r--drivers/regulator/qcom-refgen-regulator.c154
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c39
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c3
-rw-r--r--drivers/regulator/qcom_smd-regulator.c1
-rw-r--r--drivers/regulator/qcom_usb_vbus-regulator.c1
-rw-r--r--drivers/regulator/raa215300.c38
-rw-r--r--drivers/regulator/rc5t583-regulator.c1
-rw-r--r--drivers/regulator/rk808-regulator.c3
-rw-r--r--drivers/regulator/rohm-regulator.c2
-rw-r--r--drivers/regulator/rpi-panel-attiny-regulator.c3
-rw-r--r--drivers/regulator/rt5739.c36
-rw-r--r--drivers/regulator/rt5759-regulator.c2
-rw-r--r--drivers/regulator/rtq2208-regulator.c583
-rw-r--r--drivers/regulator/s2mpa01.c1
-rw-r--r--drivers/regulator/stm32-pwr.c3
-rw-r--r--drivers/regulator/stm32-vrefbuf.c2
-rw-r--r--drivers/regulator/sy8824x.c2
-rw-r--r--drivers/regulator/sy8827n.c2
-rw-r--r--drivers/regulator/tps6286x-regulator.c8
-rw-r--r--drivers/regulator/tps6287x-regulator.c6
-rw-r--r--drivers/regulator/tps65086-regulator.c188
-rw-r--r--drivers/regulator/tps65218-regulator.c2
-rw-r--r--drivers/regulator/tps65219-regulator.c2
-rw-r--r--drivers/regulator/tps65910-regulator.c1
-rw-r--r--drivers/regulator/tps6594-regulator.c2
-rw-r--r--drivers/regulator/twl-regulator.c1
-rw-r--r--drivers/regulator/twl6030-regulator.c1
-rw-r--r--drivers/regulator/uniphier-regulator.c2
-rw-r--r--drivers/regulator/vctrl-regulator.c2
-rw-r--r--drivers/regulator/vexpress-regulator.c3
-rw-r--r--drivers/rtc/rtc-ds1685.c2
-rw-r--r--drivers/s390/block/dasd.c7
-rw-r--r--drivers/s390/block/dcssblk.c26
-rw-r--r--drivers/s390/block/scm_blk.c2
-rw-r--r--drivers/s390/char/sclp_cmd.c4
-rw-r--r--drivers/s390/char/sclp_early.c1
-rw-r--r--drivers/s390/char/vmcp.c2
-rw-r--r--drivers/s390/char/zcore.c2
-rw-r--r--drivers/s390/crypto/Makefile2
-rw-r--r--drivers/s390/crypto/ap_bus.c34
-rw-r--r--drivers/s390/crypto/ap_bus.h20
-rw-r--r--drivers/s390/crypto/ap_queue.c47
-rw-r--r--drivers/s390/crypto/pkey_api.c119
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c164
-rw-r--r--drivers/s390/crypto/vfio_ap_private.h6
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c227
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.h134
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.c421
-rw-r--r--drivers/s390/crypto/zcrypt_cex2c.h18
-rw-r--r--drivers/s390/crypto/zcrypt_ep11misc.c347
-rw-r--r--drivers/s390/crypto/zcrypt_ep11misc.h24
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.c64
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.h3
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c14
-rw-r--r--drivers/s390/net/Kconfig5
-rw-r--r--drivers/s390/net/lcs.c39
-rw-r--r--drivers/scsi/raid_class.c48
-rw-r--r--drivers/scsi/scsi_lib.c12
-rw-r--r--drivers/scsi/snic/snic_disc.c3
-rw-r--r--drivers/soc/fsl/qe/qe.c4
-rw-r--r--drivers/soundwire/bus.c32
-rw-r--r--drivers/soundwire/bus_type.c12
-rw-r--r--drivers/spi/Kconfig33
-rw-r--r--drivers/spi/Makefile4
-rw-r--r--drivers/spi/spi-amd.c52
-rw-r--r--drivers/spi/spi-amlogic-spifc-a1.c88
-rw-r--r--drivers/spi/spi-ar934x.c3
-rw-r--r--drivers/spi/spi-armada-3700.c3
-rw-r--r--drivers/spi/spi-aspeed-smc.c14
-rw-r--r--drivers/spi/spi-at91-usart.c8
-rw-r--r--drivers/spi/spi-ath79.c2
-rw-r--r--drivers/spi/spi-atmel.c10
-rw-r--r--drivers/spi/spi-au1550.c74
-rw-r--r--drivers/spi/spi-axi-spi-engine.c62
-rw-r--r--drivers/spi/spi-bcm-qspi.c64
-rw-r--r--drivers/spi/spi-bcm2835.c130
-rw-r--r--drivers/spi/spi-bcm2835aux.c92
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c86
-rw-r--r--drivers/spi/spi-bcm63xx.c68
-rw-r--r--drivers/spi/spi-bcmbca-hsspi.c66
-rw-r--r--drivers/spi/spi-bitbang-txrx.h16
-rw-r--r--drivers/spi/spi-bitbang.c8
-rw-r--r--drivers/spi/spi-butterfly.c18
-rw-r--r--drivers/spi/spi-cadence-quadspi.c112
-rw-r--r--drivers/spi/spi-cadence-xspi.c31
-rw-r--r--drivers/spi/spi-cadence.c95
-rw-r--r--drivers/spi/spi-cavium-octeon.c32
-rw-r--r--drivers/spi/spi-cavium-thunderx.c32
-rw-r--r--drivers/spi/spi-clps711x.c42
-rw-r--r--drivers/spi/spi-coldfire-qspi.c77
-rw-r--r--drivers/spi/spi-cs42l43.c284
-rw-r--r--drivers/spi/spi-davinci.c90
-rw-r--r--drivers/spi/spi-dln2.c94
-rw-r--r--drivers/spi/spi-dw-core.c112
-rw-r--r--drivers/spi/spi-dw-dma.c22
-rw-r--r--drivers/spi/spi-dw-mmio.c10
-rw-r--r--drivers/spi/spi-dw.h4
-rw-r--r--drivers/spi/spi-ep93xx.c187
-rw-r--r--drivers/spi/spi-falcon.c34
-rw-r--r--drivers/spi/spi-fsi.c2
-rw-r--r--drivers/spi/spi-fsl-cpm.c74
-rw-r--r--drivers/spi/spi-fsl-dspi.c34
-rw-r--r--drivers/spi/spi-fsl-espi.c76
-rw-r--r--drivers/spi/spi-fsl-lib.c3
-rw-r--r--drivers/spi/spi-fsl-lib.h3
-rw-r--r--drivers/spi/spi-fsl-lpspi.c89
-rw-r--r--drivers/spi/spi-fsl-qspi.c11
-rw-r--r--drivers/spi/spi-fsl-spi.c80
-rw-r--r--drivers/spi/spi-geni-qcom.c53
-rw-r--r--drivers/spi/spi-gpio.c77
-rw-r--r--drivers/spi/spi-gxp.c7
-rw-r--r--drivers/spi/spi-hisi-kunpeng.c84
-rw-r--r--drivers/spi/spi-hisi-sfc-v3xx.c18
-rw-r--r--drivers/spi/spi-img-spfi.c118
-rw-r--r--drivers/spi/spi-imx.c128
-rw-r--r--drivers/spi/spi-ingenic.c4
-rw-r--r--drivers/spi/spi-intel.c42
-rw-r--r--drivers/spi/spi-iproc-qspi.c9
-rw-r--r--drivers/spi/spi-jcore.c44
-rw-r--r--drivers/spi/spi-lantiq-ssc.c99
-rw-r--r--drivers/spi/spi-loongson-core.c279
-rw-r--r--drivers/spi/spi-loongson-pci.c55
-rw-r--r--drivers/spi/spi-loongson-plat.c47
-rw-r--r--drivers/spi/spi-loongson.h49
-rw-r--r--drivers/spi/spi-loopback-test.c2
-rw-r--r--drivers/spi/spi-lp8841-rtc.c11
-rw-r--r--drivers/spi/spi-meson-spicc.c3
-rw-r--r--drivers/spi/spi-microchip-core.c6
-rw-r--r--drivers/spi/spi-mpc512x-psc.c2
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c2
-rw-r--r--drivers/spi/spi-mt65xx.c2
-rw-r--r--drivers/spi/spi-mt7621.c2
-rw-r--r--drivers/spi/spi-mtk-nor.c3
-rw-r--r--drivers/spi/spi-mtk-snfi.c3
-rw-r--r--drivers/spi/spi-mxs.c2
-rw-r--r--drivers/spi/spi-npcm-fiu.c22
-rw-r--r--drivers/spi/spi-nxp-fspi.c7
-rw-r--r--drivers/spi/spi-omap-uwire.c2
-rw-r--r--drivers/spi/spi-omap2-mcspi.c4
-rw-r--r--drivers/spi/spi-orion.c91
-rw-r--r--drivers/spi/spi-pci1xxxx.c16
-rw-r--r--drivers/spi/spi-pic32-sqi.c86
-rw-r--r--drivers/spi/spi-pic32.c154
-rw-r--r--drivers/spi/spi-pl022.c94
-rw-r--r--drivers/spi/spi-ppc4xx.c44
-rw-r--r--drivers/spi/spi-pxa2xx.c26
-rw-r--r--drivers/spi/spi-qcom-qspi.c82
-rw-r--r--drivers/spi/spi-qup.c167
-rw-r--r--drivers/spi/spi-rb4xx.c36
-rw-r--r--drivers/spi/spi-realtek-rtl.c2
-rw-r--r--drivers/spi/spi-rockchip-sfc.c30
-rw-r--r--drivers/spi/spi-rockchip.c60
-rw-r--r--drivers/spi/spi-rpc-if.c2
-rw-r--r--drivers/spi/spi-rspi.c7
-rw-r--r--drivers/spi/spi-rzv2m-csi.c122
-rw-r--r--drivers/spi/spi-s3c64xx.c138
-rw-r--r--drivers/spi/spi-sc18is602.c53
-rw-r--r--drivers/spi/spi-sh-hspi.c4
-rw-r--r--drivers/spi/spi-sh-msiof.c51
-rw-r--r--drivers/spi/spi-sh-sci.c24
-rw-r--r--drivers/spi/spi-sh.c34
-rw-r--r--drivers/spi/spi-sifive.c80
-rw-r--r--drivers/spi/spi-slave-mt27xx.c2
-rw-r--r--drivers/spi/spi-sn-f-ospi.c6
-rw-r--r--drivers/spi/spi-sprd-adi.c3
-rw-r--r--drivers/spi/spi-sprd.c1
-rw-r--r--drivers/spi/spi-stm32-qspi.c1
-rw-r--r--drivers/spi/spi-stm32.c24
-rw-r--r--drivers/spi/spi-sun6i.c32
-rw-r--r--drivers/spi/spi-tegra114.c19
-rw-r--r--drivers/spi/spi-tegra20-sflash.c6
-rw-r--r--drivers/spi/spi-tegra20-slink.c11
-rw-r--r--drivers/spi/spi-tegra210-quad.c1
-rw-r--r--drivers/spi/spi-ti-qspi.c3
-rw-r--r--drivers/spi/spi-wpcm-fiu.c3
-rw-r--r--drivers/spi/spi-xcomm.c2
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c2
-rw-r--r--drivers/spi/spi-zynq-qspi.c4
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c8
-rw-r--r--drivers/spi/spi.c219
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c48
-rw-r--r--drivers/target/target_core_iblock.c3
-rw-r--r--drivers/thermal/amlogic_thermal.c2
-rw-r--r--drivers/thermal/broadcom/bcm2711_thermal.c2
-rw-r--r--drivers/thermal/broadcom/brcmstb_thermal.c2
-rw-r--r--drivers/thermal/hisi_thermal.c2
-rw-r--r--drivers/thermal/imx8mm_thermal.c1
-rw-r--r--drivers/thermal/imx_sc_thermal.c1
-rw-r--r--drivers/thermal/imx_thermal.c2
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3400_thermal.c44
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3401_thermal.c13
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c2
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.c188
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.h15
-rw-r--r--drivers/thermal/intel/intel_soc_dts_thermal.c17
-rw-r--r--drivers/thermal/intel/intel_tcc_cooling.c2
-rw-r--r--drivers/thermal/k3_bandgap.c2
-rw-r--r--drivers/thermal/k3_j72xx_bandgap.c2
-rw-r--r--drivers/thermal/mediatek/auxadc_thermal.c1
-rw-r--r--drivers/thermal/mediatek/lvts_thermal.c2
-rw-r--r--drivers/thermal/qcom/qcom-spmi-adc-tm5.c1
-rw-r--r--drivers/thermal/qcom/qcom-spmi-temp-alarm.c1
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c2
-rw-r--r--drivers/thermal/rcar_thermal.c2
-rw-r--r--drivers/thermal/rzg2l_thermal.c2
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c2
-rw-r--r--drivers/thermal/sprd_thermal.c2
-rw-r--r--drivers/thermal/st/stm_thermal.c2
-rw-r--r--drivers/thermal/sun8i_thermal.c2
-rw-r--r--drivers/thermal/tegra/tegra30-tsensor.c2
-rw-r--r--drivers/thermal/thermal_core.c22
-rw-r--r--drivers/thermal/thermal_core.h4
-rw-r--r--drivers/thermal/thermal_of.c11
-rw-r--r--drivers/thermal/thermal_trip.c18
-rw-r--r--drivers/thermal/uniphier_thermal.c1
-rw-r--r--drivers/tty/serial/omap-serial.c7
-rw-r--r--drivers/tty/sysrq.c2
-rw-r--r--drivers/tty/tty_io.c4
-rw-r--r--drivers/tty/vt/keyboard.c2
-rw-r--r--drivers/ufs/core/ufs-mcq.c6
-rw-r--r--drivers/ufs/host/ufs-qcom.c2
-rw-r--r--drivers/usb/core/devio.c16
-rw-r--r--drivers/usb/gadget/function/f_fs.c3
-rw-r--r--drivers/usb/gadget/legacy/inode.c3
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.c2
-rw-r--r--drivers/vfio/pci/mlx5/cmd.c4
-rw-r--r--drivers/video/fbdev/core/svgalib.c7
-rw-r--r--drivers/virt/acrn/ioreq.c4
-rw-r--r--drivers/w1/w1_netlink.c6
-rw-r--r--drivers/xen/Kconfig7
-rw-r--r--drivers/xen/grant-table.c2
-rw-r--r--drivers/xen/privcmd.c282
-rw-r--r--drivers/xen/swiotlb-xen.c2
-rw-r--r--drivers/xen/xen-acpi-processor.c7
-rw-r--r--drivers/xen/xen-pciback/conf_space_quirks.h2
-rw-r--r--drivers/xen/xen-pciback/pciback.h3
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c2
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c4
-rw-r--r--drivers/zorro/names.c1
2024 files changed, 77246 insertions, 38252 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 7241d80a7b29..a7459e77df37 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -195,3 +195,5 @@ obj-$(CONFIG_PECI) += peci/
obj-$(CONFIG_HTE) += hte/
obj-$(CONFIG_DRM_ACCEL) += accel/
obj-$(CONFIG_CDX_BUS) += cdx/
+
+obj-$(CONFIG_S390) += s390/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 00dd309b6682..cee82b473dc5 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -581,7 +581,7 @@ config ACPI_VIOT
config ACPI_PRMT
bool "Platform Runtime Mechanism Support"
- depends on EFI && (X86_64 || ARM64)
+ depends on EFI_RUNTIME_WRAPPERS && (X86_64 || ARM64)
default y
help
Platform Runtime Mechanism (PRM) is a firmware interface exposing a
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3fc5a0d54f6e..eaa09bf52f17 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -50,7 +50,6 @@ acpi-$(CONFIG_PCI) += acpi_lpss.o
acpi-y += acpi_apd.o
acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
-acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o
acpi-y += power.o
acpi-y += event.o
acpi-y += evged.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 1ace70b831cd..225dc6818751 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -34,7 +34,7 @@ MODULE_LICENSE("GPL");
static int acpi_ac_add(struct acpi_device *device);
static void acpi_ac_remove(struct acpi_device *device);
-static void acpi_ac_notify(struct acpi_device *device, u32 event);
+static void acpi_ac_notify(acpi_handle handle, u32 event, void *data);
static const struct acpi_device_id ac_device_ids[] = {
{"ACPI0003", 0},
@@ -54,11 +54,9 @@ static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
.ids = ac_device_ids,
- .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
- .notify = acpi_ac_notify,
},
.drv.pm = &acpi_ac_pm,
};
@@ -128,8 +126,9 @@ static enum power_supply_property ac_props[] = {
};
/* Driver Model */
-static void acpi_ac_notify(struct acpi_device *device, u32 event)
+static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
{
+ struct acpi_device *device = data;
struct acpi_ac *ac = acpi_driver_data(device);
if (!ac)
@@ -235,7 +234,7 @@ static int acpi_ac_add(struct acpi_device *device)
result = acpi_ac_get_state(ac);
if (result)
- goto end;
+ goto err_release_ac;
psy_cfg.drv_data = ac;
@@ -248,7 +247,7 @@ static int acpi_ac_add(struct acpi_device *device)
&ac->charger_desc, &psy_cfg);
if (IS_ERR(ac->charger)) {
result = PTR_ERR(ac->charger);
- goto end;
+ goto err_release_ac;
}
pr_info("%s [%s] (%s)\n", acpi_device_name(device),
@@ -256,9 +255,19 @@ static int acpi_ac_add(struct acpi_device *device)
ac->battery_nb.notifier_call = acpi_ac_battery_notify;
register_acpi_notifier(&ac->battery_nb);
-end:
+
+ result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY,
+ acpi_ac_notify);
if (result)
- kfree(ac);
+ goto err_unregister;
+
+ return 0;
+
+err_unregister:
+ power_supply_unregister(ac->charger);
+ unregister_acpi_notifier(&ac->battery_nb);
+err_release_ac:
+ kfree(ac);
return result;
}
@@ -297,6 +306,8 @@ static void acpi_ac_remove(struct acpi_device *device)
ac = acpi_driver_data(device);
+ acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY,
+ acpi_ac_notify);
power_supply_unregister(ac->charger);
unregister_acpi_notifier(&ac->battery_nb);
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 4cf4aef7ce0c..9b55d1593d16 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -51,12 +51,11 @@ acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
return AE_OK;
}
-static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
- const struct acpi_device_id *id)
+int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
{
acpi_status status;
- status = acpi_install_address_space_handler(adev->handle,
+ status = acpi_install_address_space_handler(handle,
ACPI_ADR_SPACE_CMOS,
&acpi_cmos_rtc_space_handler,
NULL, NULL);
@@ -67,18 +66,30 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
return 1;
}
+EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler);
-static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
+void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
{
- if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
+ if (ACPI_FAILURE(acpi_remove_address_space_handler(handle,
ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
pr_err("Error removing CMOS-RTC region handler\n");
}
+EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler);
+
+static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id)
+{
+ return acpi_install_cmos_rtc_space_handler(adev->handle);
+}
+
+static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev)
+{
+ acpi_remove_cmos_rtc_space_handler(adev->handle);
+}
static struct acpi_scan_handler cmos_rtc_handler = {
.ids = acpi_cmos_rtc_ids,
- .attach = acpi_install_cmos_rtc_space_handler,
- .detach = acpi_remove_cmos_rtc_space_handler,
+ .attach = acpi_cmos_rtc_attach_handler,
+ .detach = acpi_cmos_rtc_detach_handler,
};
void __init acpi_cmos_rtc_init(void)
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c
index e648158368a7..e120a96e1eae 100644
--- a/drivers/acpi/acpi_extlog.c
+++ b/drivers/acpi/acpi_extlog.c
@@ -172,7 +172,7 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
fru_text = "";
sec_type = (guid_t *)gdata->section_type;
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
- struct cper_sec_mem_err *mem = (void *)(gdata + 1);
+ struct cper_sec_mem_err *mem = acpi_hest_get_payload(gdata);
if (gdata->error_data_length >= sizeof(*mem))
trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 24f662d8bd39..d0c1a71007d0 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -211,8 +211,7 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
if (!info->length)
continue;
- if (mhp_supports_memmap_on_memory(info->length))
- mhp_flags |= MHP_MEMMAP_ON_MEMORY;
+ mhp_flags |= MHP_MEMMAP_ON_MEMORY;
result = __add_memory(mgid, info->start_addr, info->length,
mhp_flags);
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index f9aa02cac6d1..c711db8a9c33 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -9,9 +9,11 @@
* Copyright (C) 2013, Intel Corporation
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*/
+#define pr_fmt(fmt) "ACPI: " fmt
#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -21,6 +23,8 @@
#include <asm/cpu.h>
+#include <xen/xen.h>
+
#include "internal.h"
DEFINE_PER_CPU(struct acpi_processor *, processors);
@@ -508,54 +512,110 @@ static void acpi_processor_remove(struct acpi_device *device)
}
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
-#ifdef CONFIG_X86
-static bool acpi_hwp_native_thermal_lvt_set;
-static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle,
- u32 lvl,
- void *context,
- void **rv)
+#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
+bool __init processor_physically_present(acpi_handle handle)
+{
+ int cpuid, type;
+ u32 acpi_id;
+ acpi_status status;
+ acpi_object_type acpi_type;
+ unsigned long long tmp;
+ union acpi_object object = {};
+ struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+
+ status = acpi_get_type(handle, &acpi_type);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ switch (acpi_type) {
+ case ACPI_TYPE_PROCESSOR:
+ status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return false;
+ acpi_id = object.processor.proc_id;
+ break;
+ case ACPI_TYPE_DEVICE:
+ status = acpi_evaluate_integer(handle, METHOD_NAME__UID,
+ NULL, &tmp);
+ if (ACPI_FAILURE(status))
+ return false;
+ acpi_id = tmp;
+ break;
+ default:
+ return false;
+ }
+
+ if (xen_initial_domain())
+ /*
+ * When running as a Xen dom0 the number of processors Linux
+ * sees can be different from the real number of processors on
+ * the system, and we still need to execute _PDC or _OSC for
+ * all of them.
+ */
+ return xen_processor_present(acpi_id);
+
+ type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
+ cpuid = acpi_get_cpuid(handle, type, acpi_id);
+
+ return !invalid_logical_cpuid(cpuid);
+}
+
+/* vendor specific UUID indicating an Intel platform */
+static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";
+
+static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
{
- u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";
- u32 capbuf[2];
+ u32 capbuf[2] = {};
struct acpi_osc_context osc_context = {
.uuid_str = sb_uuid_str,
.rev = 1,
.cap.length = 8,
.cap.pointer = capbuf,
};
+ acpi_status status;
- if (acpi_hwp_native_thermal_lvt_set)
- return AE_CTRL_TERMINATE;
+ if (!processor_physically_present(handle))
+ return AE_OK;
- capbuf[0] = 0x0000;
- capbuf[1] = 0x1000; /* set bit 12 */
+ arch_acpi_set_proc_cap_bits(&capbuf[OSC_SUPPORT_DWORD]);
- if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) {
- if (osc_context.ret.pointer && osc_context.ret.length > 1) {
- u32 *capbuf_ret = osc_context.ret.pointer;
+ status = acpi_run_osc(handle, &osc_context);
+ if (ACPI_FAILURE(status))
+ return status;
- if (capbuf_ret[1] & 0x1000) {
- acpi_handle_info(handle,
- "_OSC native thermal LVT Acked\n");
- acpi_hwp_native_thermal_lvt_set = true;
- }
- }
- kfree(osc_context.ret.pointer);
- }
+ kfree(osc_context.ret.pointer);
return AE_OK;
}
-void __init acpi_early_processor_osc(void)
+static bool __init acpi_early_processor_osc(void)
{
- if (boot_cpu_has(X86_FEATURE_HWP)) {
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- acpi_hwp_native_thermal_lvt_osc,
- NULL, NULL, NULL);
- acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID,
- acpi_hwp_native_thermal_lvt_osc,
- NULL, NULL);
+ acpi_status status;
+
+ acpi_proc_quirk_mwait_check();
+
+ status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, acpi_processor_osc, NULL,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ status = acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_osc,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ return true;
+}
+
+void __init acpi_early_processor_control_setup(void)
+{
+ if (acpi_early_processor_osc()) {
+ pr_info("_OSC evaluated successfully for all CPUs\n");
+ } else {
+ pr_info("_OSC evaluation for CPUs failed, trying _PDC\n");
+ acpi_early_processor_set_pdc();
}
}
#endif
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index e9b8e8305e23..33c3b16af556 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -557,6 +557,7 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
static int acpi_tad_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
device_init_wakeup(dev, false);
@@ -577,6 +578,7 @@ static int acpi_tad_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
+ acpi_remove_cmos_rtc_space_handler(handle);
return 0;
}
@@ -589,6 +591,11 @@ static int acpi_tad_probe(struct platform_device *pdev)
unsigned long long caps;
int ret;
+ ret = acpi_install_cmos_rtc_space_handler(handle);
+ if (ret < 0) {
+ dev_info(dev, "Unable to install space handler\n");
+ return -ENODEV;
+ }
/*
* Initialization failure messages are mostly about firmware issues, so
* print them at the "info" level.
@@ -596,22 +603,27 @@ static int acpi_tad_probe(struct platform_device *pdev)
status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps);
if (ACPI_FAILURE(status)) {
dev_info(dev, "Unable to get capabilities\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto remove_handler;
}
if (!(caps & ACPI_TAD_AC_WAKE)) {
dev_info(dev, "Unsupported capabilities\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto remove_handler;
}
if (!acpi_has_method(handle, "_PRW")) {
dev_info(dev, "Missing _PRW\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto remove_handler;
}
dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
- if (!dd)
- return -ENOMEM;
+ if (!dd) {
+ ret = -ENOMEM;
+ goto remove_handler;
+ }
dd->capabilities = caps;
dev_set_drvdata(dev, dd);
@@ -653,6 +665,11 @@ static int acpi_tad_probe(struct platform_device *pdev)
fail:
acpi_tad_remove(pdev);
+ /* Don't fallthrough because cmos rtc space handler is removed in acpi_tad_remove() */
+ return ret;
+
+remove_handler:
+ acpi_remove_cmos_rtc_space_handler(handle);
return ret;
}
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 62f4364e4460..948e31f7ce6e 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -77,7 +77,7 @@ static DEFINE_MUTEX(video_list_lock);
static LIST_HEAD(video_bus_head);
static int acpi_video_bus_add(struct acpi_device *device);
static void acpi_video_bus_remove(struct acpi_device *device);
-static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
+static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data);
/*
* Indices in the _BCL method response: the first two items are special,
@@ -104,7 +104,6 @@ static struct acpi_driver acpi_video_bus = {
.ops = {
.add = acpi_video_bus_add,
.remove = acpi_video_bus_remove,
- .notify = acpi_video_bus_notify,
},
};
@@ -1527,8 +1526,9 @@ static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
acpi_osi_is_win8() ? 0 : 1);
}
-static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
+static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
{
+ struct acpi_device *device = data;
struct acpi_video_bus *video = acpi_driver_data(device);
struct input_dev *input;
int keycode = 0;
@@ -2027,6 +2027,12 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (error)
goto err_put_video;
+ /*
+ * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0
+ * evaluated to have functional panel brightness control.
+ */
+ acpi_device_fix_up_power_extended(device);
+
pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n",
ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
video->flags.multihead ? "yes" : "no",
@@ -2053,8 +2059,19 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_add_notify_handler(video);
+ error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_video_bus_notify);
+ if (error)
+ goto err_remove;
+
return 0;
+err_remove:
+ mutex_lock(&video_list_lock);
+ list_del(&video->entry);
+ mutex_unlock(&video_list_lock);
+ acpi_video_bus_remove_notify_handler(video);
+ acpi_video_bus_unregister_backlight(video);
err_put_video:
acpi_video_bus_put_devices(video);
kfree(video->attached_array);
@@ -2075,6 +2092,9 @@ static void acpi_video_bus_remove(struct acpi_device *device)
video = acpi_driver_data(device);
+ acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_video_bus_notify);
+
mutex_lock(&video_list_lock);
list_del(&video->entry);
mutex_unlock(&video_list_lock);
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 22f1f7a9e5a3..911875c5a5f1 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -287,4 +287,6 @@ struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name);
void acpi_db_uint32_to_hex_string(u32 value, char *buffer);
+void acpi_db_generate_interrupt(char *gsiv_arg);
+
#endif /* __ACDEBUG_H__ */
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 778241173ed4..f4c90fc99be2 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -129,6 +129,7 @@ ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
+ACPI_GLOBAL(struct acpi_ged_handler_info *, acpi_gbl_ged_handler_list);
/* Owner ID support */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 12d4a024f029..82563b44af35 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -543,6 +543,14 @@ struct acpi_field_info {
u32 pkg_length;
};
+/* Information about the interrupt ID and _EVT of a GED device */
+
+struct acpi_ged_handler_info {
+ struct acpi_ged_handler_info *next;
+ u32 int_id; /* The interrupt ID that triggers the execution ofthe evt_method. */
+ struct acpi_namespace_node *evt_method; /* The _EVT method to be executed when an interrupt with ID = int_ID is received */
+};
+
/*****************************************************************************
*
* Generic "state" object for stacks
@@ -560,25 +568,28 @@ struct acpi_field_info {
u8 descriptor_type; /* To differentiate various internal objs */\
u8 flags; \
u16 value; \
- u16 state;
+ u16 state
/* There are 2 bytes available here until the next natural alignment boundary */
struct acpi_common_state {
-ACPI_STATE_COMMON};
+ ACPI_STATE_COMMON;
+};
/*
* Update state - used to traverse complex objects such as packages
*/
struct acpi_update_state {
- ACPI_STATE_COMMON union acpi_operand_object *object;
+ ACPI_STATE_COMMON;
+ union acpi_operand_object *object;
};
/*
* Pkg state - used to traverse nested package structures
*/
struct acpi_pkg_state {
- ACPI_STATE_COMMON u32 index;
+ ACPI_STATE_COMMON;
+ u32 index;
union acpi_operand_object *source_object;
union acpi_operand_object *dest_object;
struct acpi_walk_state *walk_state;
@@ -591,7 +602,8 @@ struct acpi_pkg_state {
* Allows nesting of these constructs
*/
struct acpi_control_state {
- ACPI_STATE_COMMON u16 opcode;
+ ACPI_STATE_COMMON;
+ u16 opcode;
union acpi_parse_object *predicate_op;
u8 *aml_predicate_start; /* Start of if/while predicate */
u8 *package_end; /* End of if/while block */
@@ -602,11 +614,13 @@ struct acpi_control_state {
* Scope state - current scope during namespace lookups
*/
struct acpi_scope_state {
- ACPI_STATE_COMMON struct acpi_namespace_node *node;
+ ACPI_STATE_COMMON;
+ struct acpi_namespace_node *node;
};
struct acpi_pscope_state {
- ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */
+ ACPI_STATE_COMMON;
+ u32 arg_count; /* Number of fixed arguments */
union acpi_parse_object *op; /* Current op being parsed */
u8 *arg_end; /* Current argument end */
u8 *pkg_end; /* Current package end */
@@ -618,7 +632,8 @@ struct acpi_pscope_state {
* states are created when there are nested control methods executing.
*/
struct acpi_thread_state {
- ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */
+ ACPI_STATE_COMMON;
+ u8 current_sync_level; /* Mutex Sync (nested acquire) level */
struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */
union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */
acpi_thread_id thread_id; /* Running thread ID */
@@ -629,8 +644,8 @@ struct acpi_thread_state {
* AML arguments
*/
struct acpi_result_values {
- ACPI_STATE_COMMON
- union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM];
+ ACPI_STATE_COMMON;
+ union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM];
};
typedef
@@ -652,7 +667,8 @@ struct acpi_global_notify_handler {
* handler/dispatcher.
*/
struct acpi_notify_info {
- ACPI_STATE_COMMON u8 handler_list_id;
+ ACPI_STATE_COMMON;
+ u8 handler_list_id;
struct acpi_namespace_node *node;
union acpi_operand_object *handler_list_head;
struct acpi_global_notify_handler *global;
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index e64aabe3d33a..2e442f5a3123 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -440,6 +440,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
METHOD_NO_RETURN_VALUE}},
+ {{"_DSC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
{{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */
PACKAGE_INFO(ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1,
diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c
index 9eb68e0751c7..3d99a9048585 100644
--- a/drivers/acpi/acpica/dbcmds.c
+++ b/drivers/acpi/acpica/dbcmds.c
@@ -1010,6 +1010,64 @@ void acpi_db_display_resources(char *object_arg)
acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_db_generate_ged
+ *
+ * PARAMETERS: ged_arg - Raw GED number, ascii string
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Simulate firing of a GED
+ *
+ ******************************************************************************/
+
+void acpi_db_generate_interrupt(char *gsiv_arg)
+{
+ u32 gsiv_number;
+ struct acpi_ged_handler_info *ged_info = acpi_gbl_ged_handler_list;
+
+ if (!ged_info) {
+ acpi_os_printf("No GED handling present\n");
+ }
+
+ gsiv_number = strtoul(gsiv_arg, NULL, 0);
+
+ while (ged_info) {
+
+ if (ged_info->int_id == gsiv_number) {
+ struct acpi_object_list arg_list;
+ union acpi_object arg0;
+ acpi_handle evt_handle = ged_info->evt_method;
+ acpi_status status;
+
+ acpi_os_printf("Evaluate GED _EVT (GSIV=%d)\n",
+ gsiv_number);
+
+ if (!evt_handle) {
+ acpi_os_printf("Undefined _EVT method\n");
+ return;
+ }
+
+ arg0.integer.type = ACPI_TYPE_INTEGER;
+ arg0.integer.value = gsiv_number;
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg0;
+
+ status =
+ acpi_evaluate_object(evt_handle, NULL, &arg_list,
+ NULL);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_printf("Could not evaluate _EVT\n");
+ return;
+ }
+
+ }
+ ged_info = ged_info->next;
+ }
+}
+
#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c
index b8a48923064f..861b12c334ab 100644
--- a/drivers/acpi/acpica/dbinput.c
+++ b/drivers/acpi/acpica/dbinput.c
@@ -106,6 +106,7 @@ enum acpi_ex_debugger_commands {
CMD_THREADS,
CMD_TEST,
+ CMD_INTERRUPT,
#endif
};
@@ -185,6 +186,7 @@ static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
{"THREADS", 3},
{"TEST", 1},
+ {"INTERRUPT", 1},
#endif
{NULL, 0}
};
@@ -318,6 +320,7 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
{1, " Gpes", "Display info on all GPE devices\n"},
{1, " Sci", "Generate an SCI\n"},
{1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"},
+ {1, " Interrupt <GSIV>", "Simulate an interrupt\n"},
#endif
{0, NULL, NULL}
};
@@ -1064,6 +1067,11 @@ acpi_db_command_dispatch(char *input_buffer,
acpi_os_printf("Event command not implemented\n");
break;
+ case CMD_INTERRUPT:
+
+ acpi_db_generate_interrupt(acpi_gbl_db_args[1]);
+ break;
+
case CMD_GPE:
acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index d3841ded3a81..75338a13c802 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -146,8 +146,8 @@ acpi_ds_result_push(union acpi_operand_object *object,
if (!object) {
ACPI_ERROR((AE_INFO,
- "Null Object! Obj=%p State=%p Num=%u",
- object, walk_state, walk_state->result_count));
+ "Null Object! State=%p Num=%u",
+ walk_state, walk_state->result_count));
return (AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c
index 5d99b1a76c83..5241f4c01c76 100644
--- a/drivers/acpi/acpica/exserial.c
+++ b/drivers/acpi/acpica/exserial.c
@@ -343,8 +343,7 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
/* Copy the input buffer data to the transfer buffer */
buffer = buffer_desc->buffer.pointer;
- data_length = (buffer_length < source_desc->buffer.length ?
- buffer_length : source_desc->buffer.length);
+ data_length = ACPI_MIN(buffer_length, source_desc->buffer.length);
memcpy(buffer, source_desc->buffer.pointer, data_length);
/* Lock entire transaction if requested */
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 09029fe545f1..39e31030e5f4 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -603,7 +603,7 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
/* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY,
AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
- AML_FLAGS_EXEC_0A_0T_1R),
+ AML_FLAGS_EXEC_0A_0T_1R | AML_NO_OPERAND_RESOLVE),
/* ACPI 5.0 opcodes */
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index 1bbba8585fa6..c5f6c85a3a09 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -37,7 +37,12 @@ void acpi_ut_init_stack_ptr_trace(void)
{
acpi_size current_sp;
+#pragma GCC diagnostic push
+#if defined(__GNUC__) && __GNUC__ >= 12
+#pragma GCC diagnostic ignored "-Wdangling-pointer="
+#endif
acpi_gbl_entry_stack_pointer = &current_sp;
+#pragma GCC diagnostic pop
}
/*******************************************************************************
diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile
index f81fe24894b2..143debc1ba4a 100644
--- a/drivers/acpi/arm64/Makefile
+++ b/drivers/acpi/arm64/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_ACPI_AGDI) += agdi.o
obj-$(CONFIG_ACPI_IORT) += iort.o
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
obj-$(CONFIG_ACPI_APMT) += apmt.o
+obj-$(CONFIG_ARM_AMBA) += amba.o
obj-y += dma.o init.o
diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/arm64/amba.c
index f5b443ab01c2..b2a7631d7ac7 100644
--- a/drivers/acpi/acpi_amba.c
+++ b/drivers/acpi/arm64/amba.c
@@ -17,7 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "internal.h"
+#include "init.h"
static const struct acpi_device_id amba_id_list[] = {
{"ARMH0061", 0}, /* PL061 GPIO Device */
diff --git a/drivers/acpi/arm64/init.c b/drivers/acpi/arm64/init.c
index d3ce53dda122..d0c8aed90fd1 100644
--- a/drivers/acpi/arm64/init.c
+++ b/drivers/acpi/arm64/init.c
@@ -10,4 +10,6 @@ void __init acpi_arm_init(void)
acpi_apmt_init();
if (IS_ENABLED(CONFIG_ACPI_IORT))
acpi_iort_init();
+ if (IS_ENABLED(CONFIG_ARM_AMBA))
+ acpi_amba_init();
}
diff --git a/drivers/acpi/arm64/init.h b/drivers/acpi/arm64/init.h
index a1715a2a34e9..dcc277977194 100644
--- a/drivers/acpi/arm64/init.h
+++ b/drivers/acpi/arm64/init.h
@@ -4,3 +4,4 @@
void __init acpi_agdi_init(void);
void __init acpi_apmt_init(void);
void __init acpi_iort_init(void);
+void __init acpi_amba_init(void);
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 56d887323ae5..6496ff5a6ba2 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -1708,7 +1708,10 @@ static void __init arm_smmu_v3_pmcg_init_resources(struct resource *res,
static struct acpi_platform_list pmcg_plat_info[] __initdata = {
/* HiSilicon Hip08 Platform */
{"HISI ", "HIP08 ", 0, ACPI_SIG_IORT, greater_than_or_equal,
- "Erratum #162001800", IORT_SMMU_V3_PMCG_HISI_HIP08},
+ "Erratum #162001800, Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP08},
+ /* HiSilicon Hip09 Platform */
+ {"HISI ", "HIP09 ", 0, ACPI_SIG_IORT, greater_than_or_equal,
+ "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09},
{ }
};
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 9c67ed02d797..969bf81e8d54 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1034,8 +1034,9 @@ static void acpi_battery_refresh(struct acpi_battery *battery)
}
/* Driver Interface */
-static void acpi_battery_notify(struct acpi_device *device, u32 event)
+static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
{
+ struct acpi_device *device = data;
struct acpi_battery *battery = acpi_driver_data(device);
struct power_supply *old;
@@ -1212,13 +1213,22 @@ static int acpi_battery_add(struct acpi_device *device)
device_init_wakeup(&device->dev, 1);
- return result;
+ result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY,
+ acpi_battery_notify);
+ if (result)
+ goto fail_pm;
+
+ return 0;
+fail_pm:
+ device_init_wakeup(&device->dev, 0);
+ unregister_pm_notifier(&battery->pm_nb);
fail:
sysfs_remove_battery(battery);
mutex_destroy(&battery->lock);
mutex_destroy(&battery->sysfs_lock);
kfree(battery);
+
return result;
}
@@ -1228,10 +1238,16 @@ static void acpi_battery_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return;
- device_init_wakeup(&device->dev, 0);
+
battery = acpi_driver_data(device);
+
+ acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY,
+ acpi_battery_notify);
+
+ device_init_wakeup(&device->dev, 0);
unregister_pm_notifier(&battery->pm_nb);
sysfs_remove_battery(battery);
+
mutex_destroy(&battery->lock);
mutex_destroy(&battery->sysfs_lock);
kfree(battery);
@@ -1264,11 +1280,9 @@ static struct acpi_driver acpi_battery_driver = {
.name = "battery",
.class = ACPI_BATTERY_CLASS,
.ids = battery_device_ids,
- .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = acpi_battery_add,
.remove = acpi_battery_remove,
- .notify = acpi_battery_notify,
},
.drv.pm = &acpi_battery_pm,
};
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2fc2b43a4ed3..f41dda2d3493 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -554,6 +554,30 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device,
acpi_os_wait_events_complete();
}
+int acpi_dev_install_notify_handler(struct acpi_device *adev,
+ u32 handler_type,
+ acpi_notify_handler handler)
+{
+ acpi_status status;
+
+ status = acpi_install_notify_handler(adev->handle, handler_type,
+ handler, adev);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_install_notify_handler);
+
+void acpi_dev_remove_notify_handler(struct acpi_device *adev,
+ u32 handler_type,
+ acpi_notify_handler handler)
+{
+ acpi_remove_notify_handler(adev->handle, handler_type, handler);
+ acpi_os_wait_events_complete();
+}
+EXPORT_SYMBOL_GPL(acpi_dev_remove_notify_handler);
+
/* Handle events targeting \_SB device (at present only graceful shutdown) */
#define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81
@@ -1005,8 +1029,10 @@ static int acpi_device_probe(struct device *dev)
return -ENOSYS;
ret = acpi_drv->ops.add(acpi_dev);
- if (ret)
+ if (ret) {
+ acpi_dev->driver_data = NULL;
return ret;
+ }
pr_debug("Driver [%s] successfully bound to device [%s]\n",
acpi_drv->name, acpi_dev->pnp.bus_id);
@@ -1296,9 +1322,6 @@ static int __init acpi_bus_init(void)
goto error1;
}
- /* Set capability bits for _OSC under processor scope */
- acpi_early_processor_osc();
-
/*
* _OSC method may exist in module level code,
* so it must be run after ACPI_FULL_INITIALIZATION
@@ -1314,7 +1337,7 @@ static int __init acpi_bus_init(void)
acpi_sysfs_init();
- acpi_early_processor_set_pdc();
+ acpi_early_processor_control_setup();
/*
* Maybe EC region is required at bus_scan/acpi_get_devices. So it
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index 78d44e3fe129..46c6f8c35b43 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -42,22 +42,32 @@ EXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier);
* it is used by HEST Generic Hardware Error Source with notify type
* SCI.
*/
-static void acpi_hed_notify(struct acpi_device *device, u32 event)
+static void acpi_hed_notify(acpi_handle handle, u32 event, void *data)
{
blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL);
}
static int acpi_hed_add(struct acpi_device *device)
{
+ int err;
+
/* Only one hardware error device */
if (hed_handle)
return -EINVAL;
hed_handle = device->handle;
- return 0;
+
+ err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_hed_notify);
+ if (err)
+ hed_handle = NULL;
+
+ return err;
}
static void acpi_hed_remove(struct acpi_device *device)
{
+ acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_hed_notify);
hed_handle = NULL;
}
@@ -68,7 +78,6 @@ static struct acpi_driver acpi_hed_driver = {
.ops = {
.add = acpi_hed_add,
.remove = acpi_hed_remove,
- .notify = acpi_hed_notify,
},
};
module_acpi_driver(acpi_hed_driver);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index f4148dc50b9c..866c7c4ed233 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -28,11 +28,6 @@ void acpi_processor_init(void);
void acpi_platform_init(void);
void acpi_pnp_init(void);
void acpi_int340x_thermal_init(void);
-#ifdef CONFIG_ARM_AMBA
-void acpi_amba_init(void);
-#else
-static inline void acpi_amba_init(void) {}
-#endif
int acpi_sysfs_init(void);
void acpi_gpe_apply_masked_gpes(void);
void acpi_container_init(void);
@@ -128,7 +123,6 @@ int __acpi_device_uevent_modalias(const struct acpi_device *adev,
/* --------------------------------------------------------------------------
Power Resource
-------------------------------------------------------------------------- */
-int acpi_power_init(void);
void acpi_power_resources_list_free(struct list_head *list);
int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
struct list_head *list);
@@ -152,15 +146,13 @@ int acpi_wakeup_device_init(void);
Processor
-------------------------------------------------------------------------- */
#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
+void acpi_early_processor_control_setup(void);
void acpi_early_processor_set_pdc(void);
-#else
-static inline void acpi_early_processor_set_pdc(void) {}
-#endif
-#ifdef CONFIG_X86
-void acpi_early_processor_osc(void);
+void acpi_proc_quirk_mwait_check(void);
+bool processor_physically_present(acpi_handle handle);
#else
-static inline void acpi_early_processor_osc(void) {}
+static inline void acpi_early_processor_control_setup(void) {}
#endif
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 07204d482968..f0e6738ae3c9 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -3282,6 +3282,23 @@ static void acpi_nfit_put_table(void *table)
acpi_put_table(table);
}
+static void acpi_nfit_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_device *adev = data;
+
+ device_lock(&adev->dev);
+ __acpi_nfit_notify(&adev->dev, handle, event);
+ device_unlock(&adev->dev);
+}
+
+static void acpi_nfit_remove_notify_handler(void *data)
+{
+ struct acpi_device *adev = data;
+
+ acpi_dev_remove_notify_handler(adev, ACPI_DEVICE_NOTIFY,
+ acpi_nfit_notify);
+}
+
void acpi_nfit_shutdown(void *data)
{
struct acpi_nfit_desc *acpi_desc = data;
@@ -3368,12 +3385,18 @@ static int acpi_nfit_add(struct acpi_device *adev)
if (rc)
return rc;
- return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
-}
-static void acpi_nfit_remove(struct acpi_device *adev)
-{
- /* see acpi_nfit_unregister */
+ rc = devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc);
+ if (rc)
+ return rc;
+
+ rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
+ acpi_nfit_notify);
+ if (rc)
+ return rc;
+
+ return devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler,
+ adev);
}
static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle)
@@ -3446,13 +3469,6 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event)
}
EXPORT_SYMBOL_GPL(__acpi_nfit_notify);
-static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
-{
- device_lock(&adev->dev);
- __acpi_nfit_notify(&adev->dev, adev->handle, event);
- device_unlock(&adev->dev);
-}
-
static const struct acpi_device_id acpi_nfit_ids[] = {
{ "ACPI0012", 0 },
{ "", 0 },
@@ -3464,8 +3480,6 @@ static struct acpi_driver acpi_nfit_driver = {
.ids = acpi_nfit_ids,
.ops = {
.add = acpi_nfit_add,
- .remove = acpi_nfit_remove,
- .notify = acpi_nfit_notify,
},
};
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c
index 3d4c4620f9f9..7020584096bf 100644
--- a/drivers/acpi/prmt.c
+++ b/drivers/acpi/prmt.c
@@ -53,7 +53,7 @@ static LIST_HEAD(prm_module_list);
struct prm_handler_info {
guid_t guid;
- void *handler_addr;
+ efi_status_t (__efiapi *handler_addr)(u64, void *);
u64 static_data_buffer_addr;
u64 acpi_param_buffer_addr;
@@ -260,9 +260,9 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
context.static_data_buffer = handler->static_data_buffer_addr;
context.mmio_ranges = module->mmio_info;
- status = efi_call_virt_pointer(handler, handler_addr,
- handler->acpi_param_buffer_addr,
- &context);
+ status = efi_call_acpi_prm_handler(handler->handler_addr,
+ handler->acpi_param_buffer_addr,
+ &context);
if (status == EFI_SUCCESS) {
buffer->prm_status = PRM_HANDLER_SUCCESS;
} else {
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index d6606a9f2da6..7dd6dbaa98c3 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -132,6 +132,30 @@ static int map_rintc_hartid(struct acpi_subtable_header *entry,
return -EINVAL;
}
+/*
+ * Retrieve LoongArch CPU physical id
+ */
+static int map_core_pic_id(struct acpi_subtable_header *entry,
+ int device_declaration, u32 acpi_id, phys_cpuid_t *phys_id)
+{
+ struct acpi_madt_core_pic *core_pic =
+ container_of(entry, struct acpi_madt_core_pic, header);
+
+ if (!(core_pic->flags & ACPI_MADT_ENABLED))
+ return -ENODEV;
+
+ /* device_declaration means Device object in DSDT, in LoongArch
+ * system, logical processor acpi_id is required in _UID property
+ * of DSDT table, so we should check device_declaration here
+ */
+ if (device_declaration && (core_pic->processor_id == acpi_id)) {
+ *phys_id = core_pic->core_id;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
int type, u32 acpi_id)
{
@@ -165,6 +189,9 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
} else if (header->type == ACPI_MADT_TYPE_RINTC) {
if (!map_rintc_hartid(header, type, acpi_id, &phys_id))
break;
+ } else if (header->type == ACPI_MADT_TYPE_CORE_PIC) {
+ if (!map_core_pic_id(header, type, acpi_id, &phys_id))
+ break;
}
entry += header->length;
}
@@ -216,6 +243,8 @@ static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
map_x2apic_id(header, type, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
map_gicc_mpidr(header, type, acpi_id, &phys_id);
+ else if (header->type == ACPI_MADT_TYPE_CORE_PIC)
+ map_core_pic_id(header, type, acpi_id, &phys_id);
exit:
kfree(buffer.pointer);
diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c
index 18fb04523f93..1a8591e9a9bf 100644
--- a/drivers/acpi/processor_pdc.c
+++ b/drivers/acpi/processor_pdc.c
@@ -9,71 +9,19 @@
#define pr_fmt(fmt) "ACPI: " fmt
-#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
-#include <xen/xen.h>
-
#include "internal.h"
-static bool __init processor_physically_present(acpi_handle handle)
-{
- int cpuid, type;
- u32 acpi_id;
- acpi_status status;
- acpi_object_type acpi_type;
- unsigned long long tmp;
- union acpi_object object = { 0 };
- struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
-
- status = acpi_get_type(handle, &acpi_type);
- if (ACPI_FAILURE(status))
- return false;
-
- switch (acpi_type) {
- case ACPI_TYPE_PROCESSOR:
- status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status))
- return false;
- acpi_id = object.processor.proc_id;
- break;
- case ACPI_TYPE_DEVICE:
- status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp);
- if (ACPI_FAILURE(status))
- return false;
- acpi_id = tmp;
- break;
- default:
- return false;
- }
-
- if (xen_initial_domain())
- /*
- * When running as a Xen dom0 the number of processors Linux
- * sees can be different from the real number of processors on
- * the system, and we still need to execute _PDC for all of
- * them.
- */
- return xen_processor_present(acpi_id);
-
- type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
- cpuid = acpi_get_cpuid(handle, type, acpi_id);
-
- return !invalid_logical_cpuid(cpuid);
-}
-
static void acpi_set_pdc_bits(u32 *buf)
{
buf[0] = ACPI_PDC_REVISION_ID;
buf[1] = 1;
- /* Enable coordination with firmware's _TSD info */
- buf[2] = ACPI_PDC_SMP_T_SWCOORD;
-
/* Twiddle arch-specific bits needed for _PDC */
- arch_acpi_set_pdc_bits(buf);
+ arch_acpi_set_proc_cap_bits(&buf[2]);
}
static struct acpi_object_list *acpi_processor_alloc_pdc(void)
@@ -123,20 +71,6 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;
- if (boot_option_idle_override == IDLE_NOMWAIT) {
- /*
- * If mwait is disabled for CPU C-states, the C2C3_FFH access
- * mode will be disabled in the parameter of _PDC object.
- * Of course C1_FFH access mode will also be disabled.
- */
- union acpi_object *obj;
- u32 *buffer = NULL;
-
- obj = pdc_in->pointer;
- buffer = (u32 *)(obj->buffer.pointer);
- buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
-
- }
status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
if (ACPI_FAILURE(status))
@@ -174,36 +108,9 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-static int __init set_no_mwait(const struct dmi_system_id *id)
-{
- pr_notice("%s detected - disabling mwait for CPU C-states\n",
- id->ident);
- boot_option_idle_override = IDLE_NOMWAIT;
- return 0;
-}
-
-static const struct dmi_system_id processor_idle_dmi_table[] __initconst = {
- {
- set_no_mwait, "Extensa 5220", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
- DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
- {},
-};
-
-static void __init processor_dmi_check(void)
-{
- /*
- * Check whether the system is DMI table. If yes, OSPM
- * should not use mwait for CPU-states.
- */
- dmi_check_system(processor_idle_dmi_table);
-}
-
void __init acpi_early_processor_set_pdc(void)
{
- processor_dmi_check();
+ acpi_proc_quirk_mwait_check();
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index a4d9f149b48d..32cfa3f4efd3 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -501,9 +501,13 @@ static const struct dmi_system_id maingear_laptop[] = {
static const struct dmi_system_id pcspecialist_laptop[] = {
{
.ident = "PCSpecialist Elimina Pro 16 M",
+ /*
+ * Some models have product-name "Elimina Pro 16 M",
+ * others "GM6BGEQ". Match on board-name to match both.
+ */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Elimina Pro 16 M"),
+ DMI_MATCH(DMI_BOARD_NAME, "GM6BGEQ"),
},
},
{ }
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 87e385542576..531a9e3df717 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -795,6 +795,9 @@ static const char * const acpi_ignore_dep_ids[] = {
/* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
static const char * const acpi_honor_dep_ids[] = {
"INT3472", /* Camera sensor PMIC / clk and regulator info */
+ "INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
+ "INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
+ "INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */
NULL
};
@@ -2616,7 +2619,6 @@ void __init acpi_scan_init(void)
acpi_watchdog_init();
acpi_pnp_init();
acpi_int340x_thermal_init();
- acpi_amba_init();
acpi_init_lpit();
acpi_scan_add_handler(&generic_device_handler);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index f9f6ebb08fdb..419590f41ed5 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -82,10 +82,6 @@ static int tzp;
module_param(tzp, int, 0444);
MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
-static int nocrt;
-module_param(nocrt, int, 0);
-MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
-
static int off;
module_param(off, int, 0);
MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
@@ -96,35 +92,27 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static struct workqueue_struct *acpi_thermal_pm_queue;
-struct acpi_thermal_critical {
- unsigned long temperature;
- bool valid;
-};
-
-struct acpi_thermal_hot {
+struct acpi_thermal_trip {
unsigned long temperature;
bool valid;
};
struct acpi_thermal_passive {
+ struct acpi_thermal_trip trip;
struct acpi_handle_list devices;
- unsigned long temperature;
unsigned long tc1;
unsigned long tc2;
unsigned long tsp;
- bool valid;
};
struct acpi_thermal_active {
+ struct acpi_thermal_trip trip;
struct acpi_handle_list devices;
- unsigned long temperature;
- bool valid;
- bool enabled;
};
struct acpi_thermal_trips {
- struct acpi_thermal_critical critical;
- struct acpi_thermal_hot hot;
+ struct acpi_thermal_trip critical;
+ struct acpi_thermal_trip hot;
struct acpi_thermal_passive passive;
struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
};
@@ -137,6 +125,7 @@ struct acpi_thermal {
unsigned long polling_frequency;
volatile u8 zombie;
struct acpi_thermal_trips trips;
+ struct thermal_trip *trip_table;
struct acpi_handle_list devices;
struct thermal_zone_device *thermal_zone;
int kelvin_offset; /* in millidegrees */
@@ -190,7 +179,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
return 0;
}
-static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
+static int acpi_thermal_temp(struct acpi_thermal *tz, int temp_deci_k)
+{
+ if (temp_deci_k == THERMAL_TEMP_INVALID)
+ return THERMAL_TEMP_INVALID;
+
+ return deci_kelvin_to_millicelsius_with_offset(temp_deci_k,
+ tz->kelvin_offset);
+}
+
+static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
{
acpi_status status;
unsigned long long tmp;
@@ -255,9 +253,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
}
/* Passive (optional) */
- if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.valid) ||
+ if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.trip.valid) ||
flag == ACPI_TRIPS_INIT) {
- valid = tz->trips.passive.valid;
+ valid = tz->trips.passive.trip.valid;
if (psv == -1) {
status = AE_SUPPORT;
} else if (psv > 0) {
@@ -269,44 +267,44 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
}
if (ACPI_FAILURE(status)) {
- tz->trips.passive.valid = false;
+ tz->trips.passive.trip.valid = false;
} else {
- tz->trips.passive.temperature = tmp;
- tz->trips.passive.valid = true;
+ tz->trips.passive.trip.temperature = tmp;
+ tz->trips.passive.trip.valid = true;
if (flag == ACPI_TRIPS_INIT) {
status = acpi_evaluate_integer(tz->device->handle,
"_TC1", NULL, &tmp);
if (ACPI_FAILURE(status))
- tz->trips.passive.valid = false;
+ tz->trips.passive.trip.valid = false;
else
tz->trips.passive.tc1 = tmp;
status = acpi_evaluate_integer(tz->device->handle,
"_TC2", NULL, &tmp);
if (ACPI_FAILURE(status))
- tz->trips.passive.valid = false;
+ tz->trips.passive.trip.valid = false;
else
tz->trips.passive.tc2 = tmp;
status = acpi_evaluate_integer(tz->device->handle,
"_TSP", NULL, &tmp);
if (ACPI_FAILURE(status))
- tz->trips.passive.valid = false;
+ tz->trips.passive.trip.valid = false;
else
tz->trips.passive.tsp = tmp;
}
}
}
- if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.valid) {
+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.trip.valid) {
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle, "_PSL",
NULL, &devices);
if (ACPI_FAILURE(status)) {
acpi_handle_info(tz->device->handle,
"Invalid passive threshold\n");
- tz->trips.passive.valid = false;
+ tz->trips.passive.trip.valid = false;
} else {
- tz->trips.passive.valid = true;
+ tz->trips.passive.trip.valid = true;
}
if (memcmp(&tz->trips.passive.devices, &devices,
@@ -317,24 +315,24 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
}
}
if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
- if (valid != tz->trips.passive.valid)
+ if (valid != tz->trips.passive.trip.valid)
ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
}
/* Active (optional) */
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
- valid = tz->trips.active[i].valid;
+ valid = tz->trips.active[i].trip.valid;
if (act == -1)
break; /* disable all active trip points */
if (flag == ACPI_TRIPS_INIT || ((flag & ACPI_TRIPS_ACTIVE) &&
- tz->trips.active[i].valid)) {
+ tz->trips.active[i].trip.valid)) {
status = acpi_evaluate_integer(tz->device->handle,
name, NULL, &tmp);
if (ACPI_FAILURE(status)) {
- tz->trips.active[i].valid = false;
+ tz->trips.active[i].trip.valid = false;
if (i == 0)
break;
@@ -342,35 +340,36 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
break;
if (i == 1)
- tz->trips.active[0].temperature = celsius_to_deci_kelvin(act);
+ tz->trips.active[0].trip.temperature =
+ celsius_to_deci_kelvin(act);
else
/*
* Don't allow override higher than
* the next higher trip point
*/
- tz->trips.active[i-1].temperature =
+ tz->trips.active[i-1].trip.temperature =
min_t(unsigned long,
- tz->trips.active[i-2].temperature,
+ tz->trips.active[i-2].trip.temperature,
celsius_to_deci_kelvin(act));
break;
} else {
- tz->trips.active[i].temperature = tmp;
- tz->trips.active[i].valid = true;
+ tz->trips.active[i].trip.temperature = tmp;
+ tz->trips.active[i].trip.valid = true;
}
}
name[2] = 'L';
- if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].valid) {
+ if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].trip.valid) {
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle,
name, NULL, &devices);
if (ACPI_FAILURE(status)) {
acpi_handle_info(tz->device->handle,
"Invalid active%d threshold\n", i);
- tz->trips.active[i].valid = false;
+ tz->trips.active[i].trip.valid = false;
} else {
- tz->trips.active[i].valid = true;
+ tz->trips.active[i].trip.valid = true;
}
if (memcmp(&tz->trips.active[i].devices, &devices,
@@ -381,10 +380,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
}
}
if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
- if (valid != tz->trips.active[i].valid)
+ if (valid != tz->trips.active[i].trip.valid)
ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
- if (!tz->trips.active[i].valid)
+ if (!tz->trips.active[i].trip.valid)
break;
}
@@ -398,24 +397,73 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device");
}
}
+}
+
+static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data)
+{
+ struct acpi_thermal_trip *acpi_trip = trip->priv;
+ struct acpi_thermal *tz = data;
+
+ if (!acpi_trip)
+ return 0;
+
+ if (acpi_trip->valid)
+ trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature);
+ else
+ trip->temperature = THERMAL_TEMP_INVALID;
return 0;
}
+static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal,
+ unsigned long data)
+{
+ struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
+ int flag = data == ACPI_THERMAL_NOTIFY_THRESHOLDS ?
+ ACPI_TRIPS_THRESHOLDS : ACPI_TRIPS_DEVICES;
+
+ __acpi_thermal_trips_update(tz, flag);
+
+ for_each_thermal_trip(tz->thermal_zone, acpi_thermal_adjust_trip, tz);
+}
+
+static void acpi_queue_thermal_check(struct acpi_thermal *tz)
+{
+ if (!work_pending(&tz->thermal_check_work))
+ queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
+}
+
+static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event)
+{
+ struct acpi_device *adev = tz->device;
+
+ /*
+ * Use thermal_zone_device_exec() to carry out the trip points
+ * update, so as to protect thermal_get_trend() from getting stale
+ * trip point temperatures and to prevent thermal_zone_device_update()
+ * invoked from acpi_thermal_check_fn() from producing inconsistent
+ * results.
+ */
+ thermal_zone_device_exec(tz->thermal_zone,
+ acpi_thermal_adjust_thermal_zone, event);
+ acpi_queue_thermal_check(tz);
+ acpi_bus_generate_netlink_event(adev->pnp.device_class,
+ dev_name(&adev->dev), event, 0);
+}
+
static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
{
- int i, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
bool valid;
+ int i;
- if (ret)
- return ret;
+ __acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
valid = tz->trips.critical.valid |
tz->trips.hot.valid |
- tz->trips.passive.valid;
+ tz->trips.passive.trip.valid;
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
- valid = valid || tz->trips.active[i].valid;
+ valid = valid || tz->trips.active[i].trip.valid;
if (!valid) {
pr_warn(FW_BUG "No valid trip found\n");
@@ -443,159 +491,55 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
return 0;
}
-static int thermal_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
+static int thermal_get_trend(struct thermal_zone_device *thermal,
+ int trip_index, enum thermal_trend *trend)
{
struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
- int i;
+ struct acpi_thermal_trip *acpi_trip;
+ int t, i;
- if (!tz || trip < 0)
+ if (!tz || trip_index < 0)
return -EINVAL;
- if (tz->trips.critical.valid) {
- if (!trip) {
- *type = THERMAL_TRIP_CRITICAL;
- return 0;
- }
- trip--;
- }
-
- if (tz->trips.hot.valid) {
- if (!trip) {
- *type = THERMAL_TRIP_HOT;
- return 0;
- }
- trip--;
- }
-
- if (tz->trips.passive.valid) {
- if (!trip) {
- *type = THERMAL_TRIP_PASSIVE;
- return 0;
- }
- trip--;
- }
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) {
- if (!trip) {
- *type = THERMAL_TRIP_ACTIVE;
- return 0;
- }
- trip--;
- }
-
- return -EINVAL;
-}
+ if (tz->trips.critical.valid)
+ trip_index--;
-static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, int *temp)
-{
- struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
- int i;
+ if (tz->trips.hot.valid)
+ trip_index--;
- if (!tz || trip < 0)
+ if (trip_index < 0)
return -EINVAL;
- if (tz->trips.critical.valid) {
- if (!trip) {
- *temp = deci_kelvin_to_millicelsius_with_offset(
- tz->trips.critical.temperature,
- tz->kelvin_offset);
- return 0;
- }
- trip--;
- }
-
- if (tz->trips.hot.valid) {
- if (!trip) {
- *temp = deci_kelvin_to_millicelsius_with_offset(
- tz->trips.hot.temperature,
- tz->kelvin_offset);
- return 0;
- }
- trip--;
- }
-
- if (tz->trips.passive.valid) {
- if (!trip) {
- *temp = deci_kelvin_to_millicelsius_with_offset(
- tz->trips.passive.temperature,
- tz->kelvin_offset);
- return 0;
- }
- trip--;
- }
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
- tz->trips.active[i].valid; i++) {
- if (!trip) {
- *temp = deci_kelvin_to_millicelsius_with_offset(
- tz->trips.active[i].temperature,
- tz->kelvin_offset);
- return 0;
- }
- trip--;
- }
-
- return -EINVAL;
-}
-
-static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
- int *temperature)
-{
- struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
+ acpi_trip = &tz->trips.passive.trip;
+ if (acpi_trip->valid && !trip_index--) {
+ t = tz->trips.passive.tc1 * (tz->temperature -
+ tz->last_temperature) +
+ tz->trips.passive.tc2 * (tz->temperature -
+ acpi_trip->temperature);
+ if (t > 0)
+ *trend = THERMAL_TREND_RAISING;
+ else if (t < 0)
+ *trend = THERMAL_TREND_DROPPING;
+ else
+ *trend = THERMAL_TREND_STABLE;
- if (tz->trips.critical.valid) {
- *temperature = deci_kelvin_to_millicelsius_with_offset(
- tz->trips.critical.temperature,
- tz->kelvin_offset);
return 0;
}
- return -EINVAL;
-}
-
-static int thermal_get_trend(struct thermal_zone_device *thermal,
- int trip, enum thermal_trend *trend)
-{
- struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
- enum thermal_trip_type type;
- int i;
-
- if (thermal_get_trip_type(thermal, trip, &type))
- return -EINVAL;
-
- if (type == THERMAL_TRIP_ACTIVE) {
- int trip_temp;
- int temp = deci_kelvin_to_millicelsius_with_offset(
- tz->temperature, tz->kelvin_offset);
- if (thermal_get_trip_temp(thermal, trip, &trip_temp))
- return -EINVAL;
+ t = acpi_thermal_temp(tz, tz->temperature);
- if (temp > trip_temp) {
- *trend = THERMAL_TREND_RAISING;
- return 0;
- } else {
- /* Fall back on default trend */
- return -EINVAL;
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ acpi_trip = &tz->trips.active[i].trip;
+ if (acpi_trip->valid && !trip_index--) {
+ if (t > acpi_thermal_temp(tz, acpi_trip->temperature)) {
+ *trend = THERMAL_TREND_RAISING;
+ return 0;
+ }
+ break;
}
}
- /*
- * tz->temperature has already been updated by generic thermal layer,
- * before this callback being invoked
- */
- i = tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature) +
- tz->trips.passive.tc2 * (tz->temperature - tz->trips.passive.temperature);
-
- if (i > 0)
- *trend = THERMAL_TREND_RAISING;
- else if (i < 0)
- *trend = THERMAL_TREND_DROPPING;
- else
- *trend = THERMAL_TREND_STABLE;
-
- return 0;
+ return -EINVAL;
}
static void acpi_thermal_zone_device_hot(struct thermal_zone_device *thermal)
@@ -637,7 +581,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
if (tz->trips.hot.valid)
trip++;
- if (tz->trips.passive.valid) {
+ if (tz->trips.passive.trip.valid) {
trip++;
for (i = 0; i < tz->trips.passive.devices.count; i++) {
handle = tz->trips.passive.devices.handles[i];
@@ -662,7 +606,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- if (!tz->trips.active[i].valid)
+ if (!tz->trips.active[i].trip.valid)
break;
trip++;
@@ -709,9 +653,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.get_temp = thermal_get_temp,
- .get_trip_type = thermal_get_trip_type,
- .get_trip_temp = thermal_get_trip_temp,
- .get_crit_temp = thermal_get_crit_temp,
.get_trend = thermal_get_trend,
.hot = acpi_thermal_zone_device_hot,
.critical = acpi_thermal_zone_device_critical,
@@ -745,63 +686,97 @@ static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz)
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
- int trips = 0;
+ struct acpi_thermal_trip *acpi_trip;
+ struct thermal_trip *trip;
+ int passive_delay = 0;
+ int trip_count = 0;
int result;
- acpi_status status;
int i;
if (tz->trips.critical.valid)
- trips++;
+ trip_count++;
if (tz->trips.hot.valid)
- trips++;
+ trip_count++;
+
+ if (tz->trips.passive.trip.valid) {
+ trip_count++;
+ passive_delay = tz->trips.passive.tsp * 100;
+ }
- if (tz->trips.passive.valid)
- trips++;
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++)
+ trip_count++;
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid;
- i++, trips++);
+ trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL);
+ if (!trip)
+ return -ENOMEM;
- if (tz->trips.passive.valid)
- tz->thermal_zone = thermal_zone_device_register("acpitz", trips, 0, tz,
- &acpi_thermal_zone_ops, NULL,
- tz->trips.passive.tsp * 100,
- tz->polling_frequency * 100);
- else
- tz->thermal_zone =
- thermal_zone_device_register("acpitz", trips, 0, tz,
- &acpi_thermal_zone_ops, NULL,
- 0, tz->polling_frequency * 100);
+ tz->trip_table = trip;
- if (IS_ERR(tz->thermal_zone))
- return -ENODEV;
+ if (tz->trips.critical.valid) {
+ trip->type = THERMAL_TRIP_CRITICAL;
+ trip->temperature = acpi_thermal_temp(tz, tz->trips.critical.temperature);
+ trip++;
+ }
+
+ if (tz->trips.hot.valid) {
+ trip->type = THERMAL_TRIP_HOT;
+ trip->temperature = acpi_thermal_temp(tz, tz->trips.hot.temperature);
+ trip++;
+ }
+
+ acpi_trip = &tz->trips.passive.trip;
+ if (acpi_trip->valid) {
+ trip->type = THERMAL_TRIP_PASSIVE;
+ trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature);
+ trip->priv = acpi_trip;
+ trip++;
+ }
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ acpi_trip = &tz->trips.active[i].trip;
+
+ if (!acpi_trip->valid)
+ break;
+
+ trip->type = THERMAL_TRIP_ACTIVE;
+ trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature);
+ trip->priv = acpi_trip;
+ trip++;
+ }
+
+ tz->thermal_zone = thermal_zone_device_register_with_trips("acpitz",
+ tz->trip_table,
+ trip_count,
+ 0, tz,
+ &acpi_thermal_zone_ops,
+ NULL,
+ passive_delay,
+ tz->polling_frequency * 100);
+ if (IS_ERR(tz->thermal_zone)) {
+ result = PTR_ERR(tz->thermal_zone);
+ goto free_trip_table;
+ }
result = acpi_thermal_zone_sysfs_add(tz);
if (result)
goto unregister_tzd;
- status = acpi_bus_attach_private_data(tz->device->handle,
- tz->thermal_zone);
- if (ACPI_FAILURE(status)) {
- result = -ENODEV;
- goto remove_links;
- }
-
result = thermal_zone_device_enable(tz->thermal_zone);
if (result)
- goto acpi_bus_detach;
+ goto remove_links;
dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
thermal_zone_device_id(tz->thermal_zone));
return 0;
-acpi_bus_detach:
- acpi_bus_detach_private_data(tz->device->handle);
remove_links:
acpi_thermal_zone_sysfs_remove(tz);
unregister_tzd:
thermal_zone_device_unregister(tz->thermal_zone);
+free_trip_table:
+ kfree(tz->trip_table);
return result;
}
@@ -810,8 +785,8 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
{
acpi_thermal_zone_sysfs_remove(tz);
thermal_zone_device_unregister(tz->thermal_zone);
+ kfree(tz->trip_table);
tz->thermal_zone = NULL;
- acpi_bus_detach_private_data(tz->device->handle);
}
@@ -819,14 +794,9 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
Driver Interface
-------------------------------------------------------------------------- */
-static void acpi_queue_thermal_check(struct acpi_thermal *tz)
-{
- if (!work_pending(&tz->thermal_check_work))
- queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
-}
-
-static void acpi_thermal_notify(struct acpi_device *device, u32 event)
+static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
{
+ struct acpi_device *device = data;
struct acpi_thermal *tz = acpi_driver_data(device);
if (!tz)
@@ -837,16 +807,8 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
acpi_queue_thermal_check(tz);
break;
case ACPI_THERMAL_NOTIFY_THRESHOLDS:
- acpi_thermal_trips_update(tz, ACPI_TRIPS_THRESHOLDS);
- acpi_queue_thermal_check(tz);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event, 0);
- break;
case ACPI_THERMAL_NOTIFY_DEVICES:
- acpi_thermal_trips_update(tz, ACPI_TRIPS_DEVICES);
- acpi_queue_thermal_check(tz);
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- dev_name(&device->dev), event, 0);
+ acpi_thermal_trips_update(tz, event);
break;
default:
acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
@@ -997,11 +959,20 @@ static int acpi_thermal_add(struct acpi_device *device)
pr_info("%s [%s] (%ld C)\n", acpi_device_name(device),
acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature));
- goto end;
+ result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_thermal_notify);
+ if (result)
+ goto flush_wq;
+
+ return 0;
+
+flush_wq:
+ flush_workqueue(acpi_thermal_pm_queue);
+ acpi_thermal_unregister_thermal_zone(tz);
free_memory:
kfree(tz);
-end:
+
return result;
}
@@ -1012,10 +983,14 @@ static void acpi_thermal_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return;
- flush_workqueue(acpi_thermal_pm_queue);
tz = acpi_driver_data(device);
+ acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
+ acpi_thermal_notify);
+
+ flush_workqueue(acpi_thermal_pm_queue);
acpi_thermal_unregister_thermal_zone(tz);
+
kfree(tz);
}
@@ -1030,7 +1005,7 @@ static int acpi_thermal_suspend(struct device *dev)
static int acpi_thermal_resume(struct device *dev)
{
struct acpi_thermal *tz;
- int i, j, power_state, result;
+ int i, j, power_state;
if (!dev)
return -EINVAL;
@@ -1040,18 +1015,12 @@ static int acpi_thermal_resume(struct device *dev)
return -EINVAL;
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- if (!tz->trips.active[i].valid)
+ if (!tz->trips.active[i].trip.valid)
break;
- tz->trips.active[i].enabled = true;
for (j = 0; j < tz->trips.active[i].devices.count; j++) {
- result = acpi_bus_update_power(
- tz->trips.active[i].devices.handles[j],
- &power_state);
- if (result || (power_state != ACPI_STATE_D0)) {
- tz->trips.active[i].enabled = false;
- break;
- }
+ acpi_bus_update_power(tz->trips.active[i].devices.handles[j],
+ &power_state);
}
}
@@ -1078,7 +1047,6 @@ static struct acpi_driver acpi_thermal_driver = {
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
- .notify = acpi_thermal_notify,
},
.drv.pm = &acpi_thermal_pm,
};
@@ -1094,7 +1062,7 @@ static int thermal_act(const struct dmi_system_id *d) {
static int thermal_nocrt(const struct dmi_system_id *d) {
pr_notice("%s detected: disabling all critical thermal trip point actions.\n",
d->ident);
- nocrt = 1;
+ crt = -1;
return 0;
}
static int thermal_tzp(const struct dmi_system_id *d) {
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 18cc08c858cf..442396f6ed1f 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -446,6 +446,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ /* https://bugzilla.suse.com/show_bug.cgi?id=1208724 */
+ .callback = video_detect_force_native,
+ /* Lenovo Ideapad Z470 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Z470"),
+ },
+ },
+ {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
.callback = video_detect_force_native,
/* Lenovo Ideapad Z570 */
@@ -487,6 +496,24 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ /* https://gitlab.freedesktop.org/drm/amd/-/issues/1838 */
+ .callback = video_detect_force_native,
+ /* Apple iMac12,1 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,1"),
+ },
+ },
+ {
+ /* https://gitlab.freedesktop.org/drm/amd/-/issues/2753 */
+ .callback = video_detect_force_native,
+ /* Apple iMac12,2 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"),
+ },
+ },
+ {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
.callback = video_detect_force_native,
/* Apple MacBook Pro 12,1 */
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index ce62e61a9605..08f7c6708206 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -94,6 +94,11 @@ static struct lpi_constraints *lpi_constraints_table;
static int lpi_constraints_table_size;
static int rev_id;
+#define for_each_lpi_constraint(entry) \
+ for (int i = 0; \
+ entry = &lpi_constraints_table[i], i < lpi_constraints_table_size; \
+ i++)
+
static void lpi_device_get_constraints_amd(void)
{
union acpi_object *out_obj;
@@ -113,6 +118,12 @@ static void lpi_device_get_constraints_amd(void)
union acpi_object *package = &out_obj->package.elements[i];
if (package->type == ACPI_TYPE_PACKAGE) {
+ if (lpi_constraints_table) {
+ acpi_handle_err(lps0_device_handle,
+ "Duplicate constraints list\n");
+ goto free_acpi_buffer;
+ }
+
lpi_constraints_table = kcalloc(package->package.count,
sizeof(*lpi_constraints_table),
GFP_KERNEL);
@@ -123,17 +134,16 @@ static void lpi_device_get_constraints_amd(void)
acpi_handle_debug(lps0_device_handle,
"LPI: constraints list begin:\n");
- for (j = 0; j < package->package.count; ++j) {
+ for (j = 0; j < package->package.count; j++) {
union acpi_object *info_obj = &package->package.elements[j];
struct lpi_device_constraint_amd dev_info = {};
struct lpi_constraints *list;
acpi_status status;
- for (k = 0; k < info_obj->package.count; ++k) {
- union acpi_object *obj = &info_obj->package.elements[k];
+ list = &lpi_constraints_table[lpi_constraints_table_size];
- list = &lpi_constraints_table[lpi_constraints_table_size];
- list->min_dstate = -1;
+ for (k = 0; k < info_obj->package.count; k++) {
+ union acpi_object *obj = &info_obj->package.elements[k];
switch (k) {
case 0:
@@ -149,27 +159,25 @@ static void lpi_device_get_constraints_amd(void)
dev_info.min_dstate = obj->integer.value;
break;
}
+ }
- if (!dev_info.enabled || !dev_info.name ||
- !dev_info.min_dstate)
- continue;
+ acpi_handle_debug(lps0_device_handle,
+ "Name:%s, Enabled: %d, States: %d, MinDstate: %d\n",
+ dev_info.name,
+ dev_info.enabled,
+ dev_info.function_states,
+ dev_info.min_dstate);
- status = acpi_get_handle(NULL, dev_info.name,
- &list->handle);
- if (ACPI_FAILURE(status))
- continue;
+ if (!dev_info.enabled || !dev_info.name ||
+ !dev_info.min_dstate)
+ continue;
- acpi_handle_debug(lps0_device_handle,
- "Name:%s\n", dev_info.name);
+ status = acpi_get_handle(NULL, dev_info.name, &list->handle);
+ if (ACPI_FAILURE(status))
+ continue;
- list->min_dstate = dev_info.min_dstate;
+ list->min_dstate = dev_info.min_dstate;
- if (list->min_dstate < 0) {
- acpi_handle_debug(lps0_device_handle,
- "Incomplete constraint defined\n");
- continue;
- }
- }
lpi_constraints_table_size++;
}
}
@@ -214,7 +222,7 @@ static void lpi_device_get_constraints(void)
if (!package)
continue;
- for (j = 0; j < package->package.count; ++j) {
+ for (j = 0; j < package->package.count; j++) {
union acpi_object *element =
&(package->package.elements[j]);
@@ -246,7 +254,7 @@ static void lpi_device_get_constraints(void)
constraint->min_dstate = -1;
- for (j = 0; j < package_count; ++j) {
+ for (j = 0; j < package_count; j++) {
union acpi_object *info_obj = &info.package[j];
union acpi_object *cnstr_pkg;
union acpi_object *obj;
@@ -291,32 +299,55 @@ free_acpi_buffer:
ACPI_FREE(out_obj);
}
+/**
+ * acpi_get_lps0_constraint - Get the LPS0 constraint for a device.
+ * @adev: Device to get the constraint for.
+ *
+ * The LPS0 constraint is the shallowest (minimum) power state in which the
+ * device can be so as to allow the platform as a whole to achieve additional
+ * energy conservation by utilizing a system-wide low-power state.
+ *
+ * Returns:
+ * - ACPI power state value of the constraint for @adev on success.
+ * - Otherwise, ACPI_STATE_UNKNOWN.
+ */
+int acpi_get_lps0_constraint(struct acpi_device *adev)
+{
+ struct lpi_constraints *entry;
+
+ for_each_lpi_constraint(entry) {
+ if (adev->handle == entry->handle)
+ return entry->min_dstate;
+ }
+
+ return ACPI_STATE_UNKNOWN;
+}
+
static void lpi_check_constraints(void)
{
- int i;
+ struct lpi_constraints *entry;
- for (i = 0; i < lpi_constraints_table_size; ++i) {
- acpi_handle handle = lpi_constraints_table[i].handle;
- struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
+ for_each_lpi_constraint(entry) {
+ struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
if (!adev)
continue;
- acpi_handle_debug(handle,
+ acpi_handle_debug(entry->handle,
"LPI: required min power state:%s current power state:%s\n",
- acpi_power_state_string(lpi_constraints_table[i].min_dstate),
+ acpi_power_state_string(entry->min_dstate),
acpi_power_state_string(adev->power.state));
if (!adev->flags.power_manageable) {
- acpi_handle_info(handle, "LPI: Device not power manageable\n");
- lpi_constraints_table[i].handle = NULL;
+ acpi_handle_info(entry->handle, "LPI: Device not power manageable\n");
+ entry->handle = NULL;
continue;
}
- if (adev->power.state < lpi_constraints_table[i].min_dstate)
- acpi_handle_info(handle,
+ if (adev->power.state < entry->min_dstate)
+ acpi_handle_info(entry->handle,
"LPI: Constraint not met; min power state:%s current power state:%s\n",
- acpi_power_state_string(lpi_constraints_table[i].min_dstate),
+ acpi_power_state_string(entry->min_dstate),
acpi_power_state_string(adev->power.state));
}
}
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index c2b925f8cd4e..63d834dd3811 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -518,3 +518,38 @@ bool acpi_quirk_skip_acpi_ac_and_battery(void)
return false;
}
EXPORT_SYMBOL_GPL(acpi_quirk_skip_acpi_ac_and_battery);
+
+/* This section provides a workaround for a specific x86 system
+ * which requires disabling of mwait to work correctly.
+ */
+static int __init acpi_proc_quirk_set_no_mwait(const struct dmi_system_id *id)
+{
+ pr_notice("%s detected - disabling mwait for CPU C-states\n",
+ id->ident);
+ boot_option_idle_override = IDLE_NOMWAIT;
+ return 0;
+}
+
+static const struct dmi_system_id acpi_proc_quirk_mwait_dmi_table[] __initconst = {
+ {
+ .callback = acpi_proc_quirk_set_no_mwait,
+ .ident = "Extensa 5220",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
+ DMI_MATCH(DMI_BOARD_NAME, "Columbia"),
+ },
+ .driver_data = NULL,
+ },
+ {}
+};
+
+void __init acpi_proc_quirk_mwait_check(void)
+{
+ /*
+ * Check whether the system is DMI table. If yes, OSPM
+ * should not use mwait for CPU-states.
+ */
+ dmi_check_system(acpi_proc_quirk_mwait_dmi_table);
+}
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 76e7d6676657..faebe9f5412a 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -153,7 +153,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
goto err;
inode->i_ino = minor + INODE_OFFSET;
- inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
init_special_inode(inode, S_IFCHR | 0600,
MKDEV(MAJOR(binderfs_dev), minor));
inode->i_fop = &binder_fops;
@@ -432,7 +432,7 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
}
inode->i_ino = SECOND_INODE;
- inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
init_special_inode(inode, S_IFCHR | 0600,
MKDEV(MAJOR(binderfs_dev), minor));
inode->i_fop = &binder_ctl_fops;
@@ -474,7 +474,7 @@ static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_ino = iunique(sb, BINDERFS_MAX_MINOR + INODE_OFFSET);
ret->i_mode = mode;
- ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
+ ret->i_atime = ret->i_mtime = inode_set_ctime_current(ret);
}
return ret;
}
@@ -703,7 +703,7 @@ static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode->i_ino = FIRST_INODE;
inode->i_fop = &simple_dir_operations;
inode->i_mode = S_IFDIR | 0755;
- inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
inode->i_op = &binderfs_dir_inode_operations;
set_nlink(inode, 2);
diff --git a/drivers/auxdisplay/hd44780_common.c b/drivers/auxdisplay/hd44780_common.c
index 3934c2eebf33..7cbf375b0fa5 100644
--- a/drivers/auxdisplay/hd44780_common.c
+++ b/drivers/auxdisplay/hd44780_common.c
@@ -82,7 +82,15 @@ int hd44780_common_clear_display(struct charlcd *lcd)
hdc->write_cmd(hdc, LCD_CMD_DISPLAY_CLEAR);
/* datasheet says to wait 1,64 milliseconds */
long_sleep(2);
- return 0;
+
+ /*
+ * The Hitachi HD44780 controller (and compatible ones) reset the DDRAM
+ * address when executing the DISPLAY_CLEAR command, thus the
+ * following call is not required. However, other controllers do not
+ * (e.g. NewHaven NHD-0220DZW-AG5), thus move the cursor to home
+ * unconditionally to support both.
+ */
+ return hd44780_common_home(lcd);
}
EXPORT_SYMBOL_GPL(hd44780_common_clear_display);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 3dff5037943e..46d1d78c5beb 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -3108,9 +3108,7 @@ void device_initialize(struct device *dev)
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
dev->dma_coherent = dma_default_coherent;
#endif
-#ifdef CONFIG_SWIOTLB
- dev->dma_io_tlb_mem = &io_tlb_default_mem;
-#endif
+ swiotlb_dev_init(dev);
}
EXPORT_SYMBOL_GPL(device_initialize);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index fe6690ecf563..43dab03958f1 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -282,6 +282,16 @@ static ssize_t print_cpus_nohz_full(struct device *dev,
static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
#endif
+#ifdef CONFIG_CRASH_HOTPLUG
+static ssize_t crash_hotplug_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%d\n", crash_hotplug_cpu_support());
+}
+static DEVICE_ATTR_ADMIN_RO(crash_hotplug);
+#endif
+
static void cpu_device_release(struct device *dev)
{
/*
@@ -469,6 +479,9 @@ static struct attribute *cpu_root_attrs[] = {
#ifdef CONFIG_NO_HZ_FULL
&dev_attr_nohz_full.attr,
#endif
+#ifdef CONFIG_CRASH_HOTPLUG
+ &dev_attr_crash_hotplug.attr,
+#endif
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
&dev_attr_modalias.attr,
#endif
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index b456ac213610..f3b9a4d0fa3b 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -105,7 +105,8 @@ EXPORT_SYMBOL(unregister_memory_notifier);
static void memory_block_release(struct device *dev)
{
struct memory_block *mem = to_memory_block(dev);
-
+ /* Verify that the altmap is freed */
+ WARN_ON(mem->altmap);
kfree(mem);
}
@@ -183,7 +184,7 @@ static int memory_block_online(struct memory_block *mem)
{
unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr);
unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
- unsigned long nr_vmemmap_pages = mem->nr_vmemmap_pages;
+ unsigned long nr_vmemmap_pages = 0;
struct zone *zone;
int ret;
@@ -200,6 +201,9 @@ static int memory_block_online(struct memory_block *mem)
* stage helps to keep accounting easier to follow - e.g vmemmaps
* belong to the same zone as the memory they backed.
*/
+ if (mem->altmap)
+ nr_vmemmap_pages = mem->altmap->free;
+
if (nr_vmemmap_pages) {
ret = mhp_init_memmap_on_memory(start_pfn, nr_vmemmap_pages, zone);
if (ret)
@@ -230,7 +234,7 @@ static int memory_block_offline(struct memory_block *mem)
{
unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr);
unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
- unsigned long nr_vmemmap_pages = mem->nr_vmemmap_pages;
+ unsigned long nr_vmemmap_pages = 0;
int ret;
if (!mem->zone)
@@ -240,6 +244,9 @@ static int memory_block_offline(struct memory_block *mem)
* Unaccount before offlining, such that unpopulated zone and kthreads
* can properly be torn down in offline_pages().
*/
+ if (mem->altmap)
+ nr_vmemmap_pages = mem->altmap->free;
+
if (nr_vmemmap_pages)
adjust_present_page_count(pfn_to_page(start_pfn), mem->group,
-nr_vmemmap_pages);
@@ -490,6 +497,16 @@ static ssize_t auto_online_blocks_store(struct device *dev,
static DEVICE_ATTR_RW(auto_online_blocks);
+#ifdef CONFIG_CRASH_HOTPLUG
+#include <linux/kexec.h>
+static ssize_t crash_hotplug_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", crash_hotplug_memory_support());
+}
+static DEVICE_ATTR_RO(crash_hotplug);
+#endif
+
/*
* Some architectures will have custom drivers to do this, and
* will not need to do it from userspace. The fake hot-add code
@@ -726,7 +743,7 @@ void memory_block_add_nid(struct memory_block *mem, int nid,
#endif
static int add_memory_block(unsigned long block_id, unsigned long state,
- unsigned long nr_vmemmap_pages,
+ struct vmem_altmap *altmap,
struct memory_group *group)
{
struct memory_block *mem;
@@ -744,7 +761,7 @@ static int add_memory_block(unsigned long block_id, unsigned long state,
mem->start_section_nr = block_id * sections_per_block;
mem->state = state;
mem->nid = NUMA_NO_NODE;
- mem->nr_vmemmap_pages = nr_vmemmap_pages;
+ mem->altmap = altmap;
INIT_LIST_HEAD(&mem->group_next);
#ifndef CONFIG_NUMA
@@ -783,14 +800,14 @@ static int __init add_boot_memory_block(unsigned long base_section_nr)
if (section_count == 0)
return 0;
return add_memory_block(memory_block_id(base_section_nr),
- MEM_ONLINE, 0, NULL);
+ MEM_ONLINE, NULL, NULL);
}
static int add_hotplug_memory_block(unsigned long block_id,
- unsigned long nr_vmemmap_pages,
+ struct vmem_altmap *altmap,
struct memory_group *group)
{
- return add_memory_block(block_id, MEM_OFFLINE, nr_vmemmap_pages, group);
+ return add_memory_block(block_id, MEM_OFFLINE, altmap, group);
}
static void remove_memory_block(struct memory_block *memory)
@@ -818,7 +835,7 @@ static void remove_memory_block(struct memory_block *memory)
* Called under device_hotplug_lock.
*/
int create_memory_block_devices(unsigned long start, unsigned long size,
- unsigned long vmemmap_pages,
+ struct vmem_altmap *altmap,
struct memory_group *group)
{
const unsigned long start_block_id = pfn_to_block_id(PFN_DOWN(start));
@@ -832,7 +849,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size,
return -EINVAL;
for (block_id = start_block_id; block_id != end_block_id; block_id++) {
- ret = add_hotplug_memory_block(block_id, vmemmap_pages, group);
+ ret = add_hotplug_memory_block(block_id, altmap, group);
if (ret)
break;
}
@@ -889,6 +906,9 @@ static struct attribute *memory_root_attrs[] = {
&dev_attr_block_size_bytes.attr,
&dev_attr_auto_online_blocks.attr,
+#ifdef CONFIG_CRASH_HOTPLUG
+ &dev_attr_crash_hotplug.attr,
+#endif
NULL
};
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 9de524e56307..8e871ba9162f 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -446,8 +446,8 @@ static ssize_t node_read_meminfo(struct device *dev,
"Node %d AnonHugePages: %8lu kB\n"
"Node %d ShmemHugePages: %8lu kB\n"
"Node %d ShmemPmdMapped: %8lu kB\n"
- "Node %d FileHugePages: %8lu kB\n"
- "Node %d FilePmdMapped: %8lu kB\n"
+ "Node %d FileHugePages: %8lu kB\n"
+ "Node %d FilePmdMapped: %8lu kB\n"
#endif
#ifdef CONFIG_UNACCEPTED_MEMORY
"Node %d Unaccepted: %8lu kB\n"
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 0db2021f7477..b1affac70d5d 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -4,7 +4,7 @@
# subsystems should select the appropriate symbols.
config REGMAP
- bool "Register Map support" if KUNIT_ALL_TESTS
+ bool
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
select IRQ_DOMAIN if REGMAP_IRQ
select MDIO_BUS if REGMAP_MDIO
@@ -23,6 +23,16 @@ config REGMAP_KUNIT
default KUNIT_ALL_TESTS
select REGMAP_RAM
+config REGMAP_BUILD
+ bool "Enable regmap build"
+ depends on KUNIT
+ select REGMAP
+ help
+ This option exists purely to allow the regmap KUnit tests to
+ be enabled without having to enable some driver that uses
+ regmap due to unfortunate issues with how KUnit tests are
+ normally enabled.
+
config REGMAP_AC97
tristate
diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c
index 283c2e02a298..41edd6a430eb 100644
--- a/drivers/base/regmap/regcache-maple.c
+++ b/drivers/base/regmap/regcache-maple.c
@@ -74,7 +74,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg,
rcu_read_unlock();
entry = kmalloc((last - index + 1) * sizeof(unsigned long),
- GFP_KERNEL);
+ map->alloc_flags);
if (!entry)
return -ENOMEM;
@@ -92,7 +92,7 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg,
mas_lock(&mas);
mas_set_range(&mas, index, last);
- ret = mas_store_gfp(&mas, entry, GFP_KERNEL);
+ ret = mas_store_gfp(&mas, entry, map->alloc_flags);
mas_unlock(&mas);
@@ -134,7 +134,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
lower = kmemdup(entry, ((min - mas.index) *
sizeof(unsigned long)),
- GFP_KERNEL);
+ map->alloc_flags);
if (!lower) {
ret = -ENOMEM;
goto out_unlocked;
@@ -148,7 +148,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
upper = kmemdup(&entry[max + 1],
((mas.last - max) *
sizeof(unsigned long)),
- GFP_KERNEL);
+ map->alloc_flags);
if (!upper) {
ret = -ENOMEM;
goto out_unlocked;
@@ -162,7 +162,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
/* Insert new nodes with the saved data */
if (lower) {
mas_set_range(&mas, lower_index, lower_last);
- ret = mas_store_gfp(&mas, lower, GFP_KERNEL);
+ ret = mas_store_gfp(&mas, lower, map->alloc_flags);
if (ret != 0)
goto out;
lower = NULL;
@@ -170,7 +170,7 @@ static int regcache_maple_drop(struct regmap *map, unsigned int min,
if (upper) {
mas_set_range(&mas, upper_index, upper_last);
- ret = mas_store_gfp(&mas, upper, GFP_KERNEL);
+ ret = mas_store_gfp(&mas, upper, map->alloc_flags);
if (ret != 0)
goto out;
upper = NULL;
@@ -320,7 +320,7 @@ static int regcache_maple_insert_block(struct regmap *map, int first,
unsigned long *entry;
int i, ret;
- entry = kcalloc(last - first + 1, sizeof(unsigned long), GFP_KERNEL);
+ entry = kcalloc(last - first + 1, sizeof(unsigned long), map->alloc_flags);
if (!entry)
return -ENOMEM;
@@ -331,7 +331,7 @@ static int regcache_maple_insert_block(struct regmap *map, int first,
mas_set_range(&mas, map->reg_defaults[first].reg,
map->reg_defaults[last].reg);
- ret = mas_store_gfp(&mas, entry, GFP_KERNEL);
+ ret = mas_store_gfp(&mas, entry, map->alloc_flags);
mas_unlock(&mas);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 584bcc55f56e..db716ffd083e 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -22,7 +22,7 @@ struct regcache_rbtree_node {
/* block of adjacent registers */
void *block;
/* Which registers are present */
- long *cache_present;
+ unsigned long *cache_present;
/* base register handled by this block */
unsigned int base_reg;
/* number of registers available in the block */
@@ -277,7 +277,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
blk = krealloc(rbnode->block,
blklen * map->cache_word_size,
- GFP_KERNEL);
+ map->alloc_flags);
if (!blk)
return -ENOMEM;
@@ -286,7 +286,7 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
present = krealloc(rbnode->cache_present,
BITS_TO_LONGS(blklen) * sizeof(*present),
- GFP_KERNEL);
+ map->alloc_flags);
if (!present)
return -ENOMEM;
@@ -320,7 +320,7 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
const struct regmap_range *range;
int i;
- rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
+ rbnode = kzalloc(sizeof(*rbnode), map->alloc_flags);
if (!rbnode)
return NULL;
@@ -346,13 +346,13 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
}
rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
- GFP_KERNEL);
+ map->alloc_flags);
if (!rbnode->block)
goto err_free;
rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
sizeof(*rbnode->cache_present),
- GFP_KERNEL);
+ map->alloc_flags);
if (!rbnode->cache_present)
goto err_free_block;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 7d3e47436056..c5d151e9c481 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -558,6 +558,29 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
+/**
+ * regcache_reg_cached - Check if a register is cached
+ *
+ * @map: map to check
+ * @reg: register to check
+ *
+ * Reports if a register is cached.
+ */
+bool regcache_reg_cached(struct regmap *map, unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ map->lock(map->lock_arg);
+
+ ret = regcache_read(map, reg, &val);
+
+ map->unlock(map->lock_arg);
+
+ return ret == 0;
+}
+EXPORT_SYMBOL_GPL(regcache_reg_cached);
+
void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
unsigned int val)
{
@@ -587,14 +610,6 @@ void regcache_set_val(struct regmap *map, void *base, unsigned int idx,
cache[idx] = val;
break;
}
-#ifdef CONFIG_64BIT
- case 8: {
- u64 *cache = base;
-
- cache[idx] = val;
- break;
- }
-#endif
default:
BUG();
}
@@ -627,13 +642,6 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
return cache[idx];
}
-#ifdef CONFIG_64BIT
- case 8: {
- const u64 *cache = base;
-
- return cache[idx];
- }
-#endif
default:
BUG();
}
diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c
index 9ff3018a46aa..264d29b3fced 100644
--- a/drivers/base/regmap/regmap-kunit.c
+++ b/drivers/base/regmap/regmap-kunit.c
@@ -836,6 +836,45 @@ static void cache_drop(struct kunit *test)
regmap_exit(map);
}
+static void cache_present(struct kunit *test)
+{
+ struct regcache_types *t = (struct regcache_types *)test->param_value;
+ struct regmap *map;
+ struct regmap_config config;
+ struct regmap_ram_data *data;
+ unsigned int val;
+ int i;
+
+ config = test_regmap_config;
+ config.cache_type = t->type;
+
+ map = gen_regmap(&config, &data);
+ KUNIT_ASSERT_FALSE(test, IS_ERR(map));
+ if (IS_ERR(map))
+ return;
+
+ for (i = 0; i < BLOCK_TEST_SIZE; i++)
+ data->read[i] = false;
+
+ /* No defaults so no registers cached. */
+ for (i = 0; i < BLOCK_TEST_SIZE; i++)
+ KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, i));
+
+ /* We didn't trigger any reads */
+ for (i = 0; i < BLOCK_TEST_SIZE; i++)
+ KUNIT_ASSERT_FALSE(test, data->read[i]);
+
+ /* Fill the cache */
+ for (i = 0; i < BLOCK_TEST_SIZE; i++)
+ KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
+
+ /* Now everything should be cached */
+ for (i = 0; i < BLOCK_TEST_SIZE; i++)
+ KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, i));
+
+ regmap_exit(map);
+}
+
struct raw_test_types {
const char *name;
@@ -1177,6 +1216,7 @@ static struct kunit_case regmap_test_cases[] = {
KUNIT_CASE_PARAM(cache_sync_readonly, real_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params),
+ KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params),
KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params),
KUNIT_CASE_PARAM(raw_read_defaults, raw_test_types_gen_params),
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 8132b5c101c4..99d7fd85ca7d 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -202,15 +202,6 @@ static int regmap_mmio_noinc_write(void *context, unsigned int reg,
writel(swab32(valp[i]), ctx->regs + reg);
goto out_clk;
}
-#ifdef CONFIG_64BIT
- case 8:
- {
- const u64 *valp = (const u64 *)val;
- for (i = 0; i < val_count; i++)
- writeq(swab64(valp[i]), ctx->regs + reg);
- goto out_clk;
- }
-#endif
default:
ret = -EINVAL;
goto out_clk;
@@ -227,11 +218,6 @@ static int regmap_mmio_noinc_write(void *context, unsigned int reg,
case 4:
writesl(ctx->regs + reg, (const u32 *)val, val_count);
break;
-#ifdef CONFIG_64BIT
- case 8:
- writesq(ctx->regs + reg, (const u64 *)val, val_count);
- break;
-#endif
default:
ret = -EINVAL;
break;
@@ -363,11 +349,6 @@ static int regmap_mmio_noinc_read(void *context, unsigned int reg,
case 4:
readsl(ctx->regs + reg, (u32 *)val, val_count);
break;
-#ifdef CONFIG_64BIT
- case 8:
- readsq(ctx->regs + reg, (u64 *)val, val_count);
- break;
-#endif
default:
ret = -EINVAL;
goto out_clk;
@@ -387,11 +368,6 @@ static int regmap_mmio_noinc_read(void *context, unsigned int reg,
case 4:
swab32_array(val, val_count);
break;
-#ifdef CONFIG_64BIT
- case 8:
- swab64_array(val, val_count);
- break;
-#endif
default:
ret = -EINVAL;
break;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 1bfd1727b4da..884cb51c8f67 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -311,26 +311,6 @@ static void regmap_format_32_native(void *buf, unsigned int val,
memcpy(buf, &v, sizeof(v));
}
-#ifdef CONFIG_64BIT
-static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
-{
- put_unaligned_be64((u64) val << shift, buf);
-}
-
-static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
-{
- put_unaligned_le64((u64) val << shift, buf);
-}
-
-static void regmap_format_64_native(void *buf, unsigned int val,
- unsigned int shift)
-{
- u64 v = (u64) val << shift;
-
- memcpy(buf, &v, sizeof(v));
-}
-#endif
-
static void regmap_parse_inplace_noop(void *buf)
{
}
@@ -411,40 +391,6 @@ static unsigned int regmap_parse_32_native(const void *buf)
return v;
}
-#ifdef CONFIG_64BIT
-static unsigned int regmap_parse_64_be(const void *buf)
-{
- return get_unaligned_be64(buf);
-}
-
-static unsigned int regmap_parse_64_le(const void *buf)
-{
- return get_unaligned_le64(buf);
-}
-
-static void regmap_parse_64_be_inplace(void *buf)
-{
- u64 v = get_unaligned_be64(buf);
-
- memcpy(buf, &v, sizeof(v));
-}
-
-static void regmap_parse_64_le_inplace(void *buf)
-{
- u64 v = get_unaligned_le64(buf);
-
- memcpy(buf, &v, sizeof(v));
-}
-
-static unsigned int regmap_parse_64_native(const void *buf)
-{
- u64 v;
-
- memcpy(&v, buf, sizeof(v));
- return v;
-}
-#endif
-
static void regmap_lock_hwlock(void *__map)
{
struct regmap *map = __map;
@@ -1005,24 +951,6 @@ struct regmap *__regmap_init(struct device *dev,
}
break;
-#ifdef CONFIG_64BIT
- case 64:
- switch (reg_endian) {
- case REGMAP_ENDIAN_BIG:
- map->format.format_reg = regmap_format_64_be;
- break;
- case REGMAP_ENDIAN_LITTLE:
- map->format.format_reg = regmap_format_64_le;
- break;
- case REGMAP_ENDIAN_NATIVE:
- map->format.format_reg = regmap_format_64_native;
- break;
- default:
- goto err_hwlock;
- }
- break;
-#endif
-
default:
goto err_hwlock;
}
@@ -1086,28 +1014,6 @@ struct regmap *__regmap_init(struct device *dev,
goto err_hwlock;
}
break;
-#ifdef CONFIG_64BIT
- case 64:
- switch (val_endian) {
- case REGMAP_ENDIAN_BIG:
- map->format.format_val = regmap_format_64_be;
- map->format.parse_val = regmap_parse_64_be;
- map->format.parse_inplace = regmap_parse_64_be_inplace;
- break;
- case REGMAP_ENDIAN_LITTLE:
- map->format.format_val = regmap_format_64_le;
- map->format.parse_val = regmap_parse_64_le;
- map->format.parse_inplace = regmap_parse_64_le_inplace;
- break;
- case REGMAP_ENDIAN_NATIVE:
- map->format.format_val = regmap_format_64_native;
- map->format.parse_val = regmap_parse_64_native;
- break;
- default:
- goto err_hwlock;
- }
- break;
-#endif
}
if (map->format.format_write) {
@@ -2158,9 +2064,6 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg,
u8 *u8p;
u16 *u16p;
u32 *u32p;
-#ifdef CONFIG_64BIT
- u64 *u64p;
-#endif
int ret;
int i;
@@ -2180,13 +2083,6 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg,
if (write)
lastval = (unsigned int)u32p[val_count - 1];
break;
-#ifdef CONFIG_64BIT
- case 8:
- u64p = val;
- if (write)
- lastval = (unsigned int)u64p[val_count - 1];
- break;
-#endif
default:
return -EINVAL;
}
@@ -2224,11 +2120,6 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg,
case 4:
pr_cont("%x", u32p[i]);
break;
-#ifdef CONFIG_64BIT
- case 8:
- pr_cont("%llx", u64p[i]);
- break;
-#endif
default:
break;
}
@@ -2436,11 +2327,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
case 4:
ival = *(u32 *)(val + (i * val_bytes));
break;
-#ifdef CONFIG_64BIT
- case 8:
- ival = *(u64 *)(val + (i * val_bytes));
- break;
-#endif
default:
ret = -EINVAL;
goto out;
@@ -3205,9 +3091,6 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(val + i);
} else {
-#ifdef CONFIG_64BIT
- u64 *u64 = val;
-#endif
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
@@ -3223,11 +3106,6 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
goto out;
switch (map->format.val_bytes) {
-#ifdef CONFIG_64BIT
- case 8:
- u64[i] = ival;
- break;
-#endif
case 4:
u32[i] = ival;
break;
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index e460c9799d9f..2b98114a9fe0 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1547,7 +1547,6 @@ static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
rel_fdc();
return -EBUSY;
}
- fsync_bdev(bdev);
if (fd_motor_on(drive) == 0) {
rel_fdc();
return -ENODEV;
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index cddae6f4b00f..d3538bd83fb3 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -159,7 +159,7 @@ static int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...)
static int drbd_adm_prepare(struct drbd_config_context *adm_ctx,
struct sk_buff *skb, struct genl_info *info, unsigned flags)
{
- struct drbd_genlmsghdr *d_in = info->userhdr;
+ struct drbd_genlmsghdr *d_in = genl_info_userhdr(info);
const u8 cmd = info->genlhdr->cmd;
int err;
@@ -1396,8 +1396,9 @@ static void drbd_suspend_al(struct drbd_device *device)
static bool should_set_defaults(struct genl_info *info)
{
- unsigned flags = ((struct drbd_genlmsghdr*)info->userhdr)->flags;
- return 0 != (flags & DRBD_GENL_F_SET_DEFAULTS);
+ struct drbd_genlmsghdr *dh = genl_info_userhdr(info);
+
+ return 0 != (dh->flags & DRBD_GENL_F_SET_DEFAULTS);
}
static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
@@ -4276,7 +4277,7 @@ static void device_to_info(struct device_info *info,
int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
{
struct drbd_config_context adm_ctx;
- struct drbd_genlmsghdr *dh = info->userhdr;
+ struct drbd_genlmsghdr *dh = genl_info_userhdr(info);
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 2db9b186b977..ea4eb88a2e45 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3255,7 +3255,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
if (!disk || ITYPE(drive_state[cnt].fd_device) != type)
continue;
- __invalidate_device(disk->part0, true);
+ disk_force_media_change(disk);
}
mutex_unlock(&open_lock);
} else {
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 637c5bda2387..9f2d412fc560 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -603,7 +603,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
goto out_err;
/* and ... switch */
- disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
+ disk_force_media_change(lo->lo_disk);
blk_mq_freeze_queue(lo->lo_queue);
mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
lo->lo_backing_file = file;
@@ -1067,7 +1067,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
/* suppress uevents while reconfiguring the device */
dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1);
- disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
+ disk_force_media_change(lo->lo_disk);
set_disk_ro(lo->lo_disk, (lo->lo_flags & LO_FLAGS_READ_ONLY) != 0);
lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO;
@@ -1171,7 +1171,7 @@ static void __loop_clr_fd(struct loop_device *lo, bool release)
if (!release)
blk_mq_unfreeze_queue(lo->lo_queue);
- disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
+ disk_force_media_change(lo->lo_disk);
if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
int err;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8576d696c7a2..df1cd0f718b8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1434,12 +1434,10 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd)
return ret;
}
-static void nbd_clear_sock_ioctl(struct nbd_device *nbd,
- struct block_device *bdev)
+static void nbd_clear_sock_ioctl(struct nbd_device *nbd)
{
+ blk_mark_disk_dead(nbd->disk);
nbd_clear_sock(nbd);
- __invalidate_device(bdev, true);
- nbd_bdev_reset(nbd);
if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
&nbd->config->runtime_flags))
nbd_config_put(nbd);
@@ -1465,7 +1463,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
case NBD_DISCONNECT:
return nbd_disconnect(nbd);
case NBD_CLEAR_SOCK:
- nbd_clear_sock_ioctl(nbd, bdev);
+ nbd_clear_sock_ioctl(nbd);
return 0;
case NBD_SET_SOCK:
return nbd_add_socket(nbd, arg, false);
@@ -2336,6 +2334,7 @@ static struct genl_family nbd_genl_family __ro_after_init = {
.mcgrps = nbd_mcast_grps,
.n_mcgrps = ARRAY_SIZE(nbd_mcast_grps),
};
+MODULE_ALIAS_GENL_FAMILY(NBD_GENL_FAMILY_NAME);
static int populate_nbd_status(struct nbd_device *nbd, struct sk_buff *reply)
{
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index dc43a63b3469..c2bc85826358 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1277,7 +1277,7 @@ static struct macio_driver swim3_driver =
};
-int swim3_init(void)
+static int swim3_init(void)
{
macio_register_driver(&swim3_driver);
return 0;
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 21d2e71c5514..630ddfe6657b 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -56,16 +56,21 @@
| UBLK_F_USER_RECOVERY_REISSUE \
| UBLK_F_UNPRIVILEGED_DEV \
| UBLK_F_CMD_IOCTL_ENCODE \
- | UBLK_F_USER_COPY)
+ | UBLK_F_USER_COPY \
+ | UBLK_F_ZONED)
/* All UBLK_PARAM_TYPE_* should be included here */
-#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \
- UBLK_PARAM_TYPE_DISCARD | UBLK_PARAM_TYPE_DEVT)
+#define UBLK_PARAM_TYPE_ALL \
+ (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD | \
+ UBLK_PARAM_TYPE_DEVT | UBLK_PARAM_TYPE_ZONED)
struct ublk_rq_data {
struct llist_node node;
struct kref ref;
+ __u64 sector;
+ __u32 operation;
+ __u32 nr_zones;
};
struct ublk_uring_cmd_pdu {
@@ -185,6 +190,266 @@ struct ublk_params_header {
__u32 types;
};
+static inline unsigned int ublk_req_build_flags(struct request *req);
+static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
+ int tag);
+
+static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
+{
+ return ub->dev_info.flags & UBLK_F_USER_COPY;
+}
+
+static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
+{
+ return ub->dev_info.flags & UBLK_F_ZONED;
+}
+
+static inline bool ublk_queue_is_zoned(struct ublk_queue *ubq)
+{
+ return ubq->flags & UBLK_F_ZONED;
+}
+
+#ifdef CONFIG_BLK_DEV_ZONED
+
+static int ublk_get_nr_zones(const struct ublk_device *ub)
+{
+ const struct ublk_param_basic *p = &ub->params.basic;
+
+ /* Zone size is a power of 2 */
+ return p->dev_sectors >> ilog2(p->chunk_sectors);
+}
+
+static int ublk_revalidate_disk_zones(struct ublk_device *ub)
+{
+ return blk_revalidate_disk_zones(ub->ub_disk, NULL);
+}
+
+static int ublk_dev_param_zoned_validate(const struct ublk_device *ub)
+{
+ const struct ublk_param_zoned *p = &ub->params.zoned;
+ int nr_zones;
+
+ if (!ublk_dev_is_zoned(ub))
+ return -EINVAL;
+
+ if (!p->max_zone_append_sectors)
+ return -EINVAL;
+
+ nr_zones = ublk_get_nr_zones(ub);
+
+ if (p->max_active_zones > nr_zones)
+ return -EINVAL;
+
+ if (p->max_open_zones > nr_zones)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ublk_dev_param_zoned_apply(struct ublk_device *ub)
+{
+ const struct ublk_param_zoned *p = &ub->params.zoned;
+
+ disk_set_zoned(ub->ub_disk, BLK_ZONED_HM);
+ blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ub->ub_disk->queue);
+ blk_queue_required_elevator_features(ub->ub_disk->queue,
+ ELEVATOR_F_ZBD_SEQ_WRITE);
+ disk_set_max_active_zones(ub->ub_disk, p->max_active_zones);
+ disk_set_max_open_zones(ub->ub_disk, p->max_open_zones);
+ blk_queue_max_zone_append_sectors(ub->ub_disk->queue, p->max_zone_append_sectors);
+
+ ub->ub_disk->nr_zones = ublk_get_nr_zones(ub);
+
+ return 0;
+}
+
+/* Based on virtblk_alloc_report_buffer */
+static void *ublk_alloc_report_buffer(struct ublk_device *ublk,
+ unsigned int nr_zones, size_t *buflen)
+{
+ struct request_queue *q = ublk->ub_disk->queue;
+ size_t bufsize;
+ void *buf;
+
+ nr_zones = min_t(unsigned int, nr_zones,
+ ublk->ub_disk->nr_zones);
+
+ bufsize = nr_zones * sizeof(struct blk_zone);
+ bufsize =
+ min_t(size_t, bufsize, queue_max_hw_sectors(q) << SECTOR_SHIFT);
+
+ while (bufsize >= sizeof(struct blk_zone)) {
+ buf = kvmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
+ if (buf) {
+ *buflen = bufsize;
+ return buf;
+ }
+ bufsize >>= 1;
+ }
+
+ *buflen = 0;
+ return NULL;
+}
+
+static int ublk_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb, void *data)
+{
+ struct ublk_device *ub = disk->private_data;
+ unsigned int zone_size_sectors = disk->queue->limits.chunk_sectors;
+ unsigned int first_zone = sector >> ilog2(zone_size_sectors);
+ unsigned int done_zones = 0;
+ unsigned int max_zones_per_request;
+ int ret;
+ struct blk_zone *buffer;
+ size_t buffer_length;
+
+ nr_zones = min_t(unsigned int, ub->ub_disk->nr_zones - first_zone,
+ nr_zones);
+
+ buffer = ublk_alloc_report_buffer(ub, nr_zones, &buffer_length);
+ if (!buffer)
+ return -ENOMEM;
+
+ max_zones_per_request = buffer_length / sizeof(struct blk_zone);
+
+ while (done_zones < nr_zones) {
+ unsigned int remaining_zones = nr_zones - done_zones;
+ unsigned int zones_in_request =
+ min_t(unsigned int, remaining_zones, max_zones_per_request);
+ struct request *req;
+ struct ublk_rq_data *pdu;
+ blk_status_t status;
+
+ memset(buffer, 0, buffer_length);
+
+ req = blk_mq_alloc_request(disk->queue, REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req)) {
+ ret = PTR_ERR(req);
+ goto out;
+ }
+
+ pdu = blk_mq_rq_to_pdu(req);
+ pdu->operation = UBLK_IO_OP_REPORT_ZONES;
+ pdu->sector = sector;
+ pdu->nr_zones = zones_in_request;
+
+ ret = blk_rq_map_kern(disk->queue, req, buffer, buffer_length,
+ GFP_KERNEL);
+ if (ret) {
+ blk_mq_free_request(req);
+ goto out;
+ }
+
+ status = blk_execute_rq(req, 0);
+ ret = blk_status_to_errno(status);
+ blk_mq_free_request(req);
+ if (ret)
+ goto out;
+
+ for (unsigned int i = 0; i < zones_in_request; i++) {
+ struct blk_zone *zone = buffer + i;
+
+ /* A zero length zone means no more zones in this response */
+ if (!zone->len)
+ break;
+
+ ret = cb(zone, i, data);
+ if (ret)
+ goto out;
+
+ done_zones++;
+ sector += zone_size_sectors;
+
+ }
+ }
+
+ ret = done_zones;
+
+out:
+ kvfree(buffer);
+ return ret;
+}
+
+static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq,
+ struct request *req)
+{
+ struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
+ struct ublk_io *io = &ubq->ios[req->tag];
+ struct ublk_rq_data *pdu = blk_mq_rq_to_pdu(req);
+ u32 ublk_op;
+
+ switch (req_op(req)) {
+ case REQ_OP_ZONE_OPEN:
+ ublk_op = UBLK_IO_OP_ZONE_OPEN;
+ break;
+ case REQ_OP_ZONE_CLOSE:
+ ublk_op = UBLK_IO_OP_ZONE_CLOSE;
+ break;
+ case REQ_OP_ZONE_FINISH:
+ ublk_op = UBLK_IO_OP_ZONE_FINISH;
+ break;
+ case REQ_OP_ZONE_RESET:
+ ublk_op = UBLK_IO_OP_ZONE_RESET;
+ break;
+ case REQ_OP_ZONE_APPEND:
+ ublk_op = UBLK_IO_OP_ZONE_APPEND;
+ break;
+ case REQ_OP_ZONE_RESET_ALL:
+ ublk_op = UBLK_IO_OP_ZONE_RESET_ALL;
+ break;
+ case REQ_OP_DRV_IN:
+ ublk_op = pdu->operation;
+ switch (ublk_op) {
+ case UBLK_IO_OP_REPORT_ZONES:
+ iod->op_flags = ublk_op | ublk_req_build_flags(req);
+ iod->nr_zones = pdu->nr_zones;
+ iod->start_sector = pdu->sector;
+ return BLK_STS_OK;
+ default:
+ return BLK_STS_IOERR;
+ }
+ case REQ_OP_DRV_OUT:
+ /* We do not support drv_out */
+ return BLK_STS_NOTSUPP;
+ default:
+ return BLK_STS_IOERR;
+ }
+
+ iod->op_flags = ublk_op | ublk_req_build_flags(req);
+ iod->nr_sectors = blk_rq_sectors(req);
+ iod->start_sector = blk_rq_pos(req);
+ iod->addr = io->addr;
+
+ return BLK_STS_OK;
+}
+
+#else
+
+#define ublk_report_zones (NULL)
+
+static int ublk_dev_param_zoned_validate(const struct ublk_device *ub)
+{
+ return -EOPNOTSUPP;
+}
+
+static int ublk_dev_param_zoned_apply(struct ublk_device *ub)
+{
+ return -EOPNOTSUPP;
+}
+
+static int ublk_revalidate_disk_zones(struct ublk_device *ub)
+{
+ return 0;
+}
+
+static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq,
+ struct request *req)
+{
+ return BLK_STS_NOTSUPP;
+}
+
+#endif
+
static inline void __ublk_complete_rq(struct request *req);
static void ublk_complete_rq(struct kref *ref);
@@ -281,6 +546,9 @@ static int ublk_validate_params(const struct ublk_device *ub)
if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9))
return -EINVAL;
+
+ if (ublk_dev_is_zoned(ub) && !p->chunk_sectors)
+ return -EINVAL;
} else
return -EINVAL;
@@ -299,6 +567,11 @@ static int ublk_validate_params(const struct ublk_device *ub)
if (ub->params.types & UBLK_PARAM_TYPE_DEVT)
return -EINVAL;
+ if (ub->params.types & UBLK_PARAM_TYPE_ZONED)
+ return ublk_dev_param_zoned_validate(ub);
+ else if (ublk_dev_is_zoned(ub))
+ return -EINVAL;
+
return 0;
}
@@ -312,6 +585,9 @@ static int ublk_apply_params(struct ublk_device *ub)
if (ub->params.types & UBLK_PARAM_TYPE_DISCARD)
ublk_dev_param_discard_apply(ub);
+ if (ub->params.types & UBLK_PARAM_TYPE_ZONED)
+ return ublk_dev_param_zoned_apply(ub);
+
return 0;
}
@@ -482,6 +758,7 @@ static const struct block_device_operations ub_fops = {
.owner = THIS_MODULE,
.open = ublk_open,
.free_disk = ublk_free_disk,
+ .report_zones = ublk_report_zones,
};
#define UBLK_MAX_PIN_PAGES 32
@@ -596,7 +873,8 @@ static inline bool ublk_need_map_req(const struct request *req)
static inline bool ublk_need_unmap_req(const struct request *req)
{
- return ublk_rq_has_data(req) && req_op(req) == REQ_OP_READ;
+ return ublk_rq_has_data(req) &&
+ (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN);
}
static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req,
@@ -680,8 +958,13 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req)
{
struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag);
struct ublk_io *io = &ubq->ios[req->tag];
+ enum req_op op = req_op(req);
u32 ublk_op;
+ if (!ublk_queue_is_zoned(ubq) &&
+ (op_is_zone_mgmt(op) || op == REQ_OP_ZONE_APPEND))
+ return BLK_STS_IOERR;
+
switch (req_op(req)) {
case REQ_OP_READ:
ublk_op = UBLK_IO_OP_READ;
@@ -699,6 +982,8 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req)
ublk_op = UBLK_IO_OP_WRITE_ZEROES;
break;
default:
+ if (ublk_queue_is_zoned(ubq))
+ return ublk_setup_iod_zoned(ubq, req);
return BLK_STS_IOERR;
}
@@ -751,7 +1036,8 @@ static inline void __ublk_complete_rq(struct request *req)
*
* Both the two needn't unmap.
*/
- if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE)
+ if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE &&
+ req_op(req) != REQ_OP_DRV_IN)
goto exit;
/* for READ request, writing data in iod->addr to rq buffers */
@@ -1114,8 +1400,13 @@ static void ublk_commit_completion(struct ublk_device *ub,
/* find the io request and complete */
req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag);
+ if (WARN_ON_ONCE(unlikely(!req)))
+ return;
- if (req && likely(!blk_should_fake_timeout(req->q)))
+ if (req_op(req) == REQ_OP_ZONE_APPEND)
+ req->__sector = ub_cmd->zone_append_lba;
+
+ if (likely(!blk_should_fake_timeout(req->q)))
ublk_put_req_ref(ubq, req);
}
@@ -1414,11 +1705,6 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
^ (_IOC_NR(cmd_op) == UBLK_IO_NEED_GET_DATA))
goto out;
- if (ublk_support_user_copy(ubq) && ub_cmd->addr) {
- ret = -EINVAL;
- goto out;
- }
-
ret = ublk_check_cmd_op(cmd_op);
if (ret)
goto out;
@@ -1445,6 +1731,10 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
*/
if (!ub_cmd->addr && !ublk_need_get_data(ubq))
goto out;
+ } else if (ub_cmd->addr) {
+ /* User copy requires addr to be unset */
+ ret = -EINVAL;
+ goto out;
}
ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
@@ -1464,7 +1754,15 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
if (!ub_cmd->addr && (!ublk_need_get_data(ubq) ||
req_op(req) == REQ_OP_READ))
goto out;
+ } else if (req_op(req) != REQ_OP_ZONE_APPEND && ub_cmd->addr) {
+ /*
+ * User copy requires addr to be unset when command is
+ * not zone append
+ */
+ ret = -EINVAL;
+ goto out;
}
+
ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
ublk_commit_completion(ub, ub_cmd);
break;
@@ -1537,11 +1835,14 @@ static inline bool ublk_check_ubuf_dir(const struct request *req,
int ubuf_dir)
{
/* copy ubuf to request pages */
- if (req_op(req) == REQ_OP_READ && ubuf_dir == ITER_SOURCE)
+ if ((req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN) &&
+ ubuf_dir == ITER_SOURCE)
return true;
/* copy request pages to ubuf */
- if (req_op(req) == REQ_OP_WRITE && ubuf_dir == ITER_DEST)
+ if ((req_op(req) == REQ_OP_WRITE ||
+ req_op(req) == REQ_OP_ZONE_APPEND) &&
+ ubuf_dir == ITER_DEST)
return true;
return false;
@@ -1881,17 +2182,24 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)
get_device(&ub->cdev_dev);
ub->dev_info.state = UBLK_S_DEV_LIVE;
+
+ if (ublk_dev_is_zoned(ub)) {
+ ret = ublk_revalidate_disk_zones(ub);
+ if (ret)
+ goto out_put_cdev;
+ }
+
ret = add_disk(disk);
+ if (ret)
+ goto out_put_cdev;
+
+ set_bit(UB_STATE_USED, &ub->state);
+
+out_put_cdev:
if (ret) {
- /*
- * Has to drop the reference since ->free_disk won't be
- * called in case of add_disk failure.
- */
ub->dev_info.state = UBLK_S_DEV_DEAD;
ublk_put_device(ub);
- goto out_put_disk;
}
- set_bit(UB_STATE_USED, &ub->state);
out_put_disk:
if (ret)
put_disk(disk);
@@ -2038,9 +2346,16 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
UBLK_F_URING_CMD_COMP_IN_TASK;
/* GET_DATA isn't needed any more with USER_COPY */
- if (ub->dev_info.flags & UBLK_F_USER_COPY)
+ if (ublk_dev_is_user_copy(ub))
ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA;
+ /* Zoned storage support requires user copy feature */
+ if (ublk_dev_is_zoned(ub) &&
+ (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !ublk_dev_is_user_copy(ub))) {
+ ret = -EINVAL;
+ goto out_free_dev_number;
+ }
+
/* We are not ready to support zero copy */
ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
@@ -2433,14 +2748,9 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
if (header->len < header->dev_path_len)
return -EINVAL;
- dev_path = kmalloc(header->dev_path_len + 1, GFP_KERNEL);
- if (!dev_path)
- return -ENOMEM;
-
- ret = -EFAULT;
- if (copy_from_user(dev_path, argp, header->dev_path_len))
- goto exit;
- dev_path[header->dev_path_len] = 0;
+ dev_path = memdup_user_nul(argp, header->dev_path_len);
+ if (IS_ERR(dev_path))
+ return PTR_ERR(dev_path);
ret = -EINVAL;
switch (_IOC_NR(cmd->cmd_op)) {
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index de2ea589aa49..0a5445ac5e1b 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -24,6 +24,7 @@
#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}})
#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}})
#define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}})
+#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}})
#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
#define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
@@ -115,6 +116,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
*
* The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller
* with no configured address.
+ *
+ * The address AA:AA:AA:AA:AA:AA indicates a BCM43430A1 controller
+ * with no configured address.
*/
if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
!bacmp(&bda->bdaddr, BDADDR_BCM20702A1) ||
@@ -124,6 +128,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
!bacmp(&bda->bdaddr, BDADDR_BCM4334B0) ||
!bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
!bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
+ !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) ||
!bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
/* Try falling back to BDADDR EFI variable */
if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index d9349ba48281..2462796a512a 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -10,6 +10,7 @@
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@@ -27,6 +28,11 @@
#define BTINTEL_PPAG_NAME "PPAG"
+enum {
+ DSM_SET_WDISABLE2_DELAY = 1,
+ DSM_SET_RESET_METHOD = 3,
+};
+
/* structure to store the PPAG data read from ACPI table */
struct btintel_ppag {
u32 domain;
@@ -49,6 +55,10 @@ static struct {
u32 fw_build_num;
} coredump_info;
+static const guid_t btintel_guid_dsm =
+ GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,
+ 0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);
+
int btintel_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
@@ -470,6 +480,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
case 0x18: /* Slr */
case 0x19: /* Slr-F */
case 0x1b: /* Mgr */
+ case 0x1c: /* Gale Peak (GaP) */
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
@@ -2390,7 +2401,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
{
struct btintel_ppag ppag;
struct sk_buff *skb;
- struct btintel_loc_aware_reg ppag_cmd;
+ struct hci_ppag_enable_cmd ppag_cmd;
acpi_handle handle;
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
@@ -2398,6 +2409,8 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
case 0x504: /* Hrp2 */
case 0x202: /* Jfp2 */
case 0x201: /* Jfp1 */
+ bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)",
+ ver->cnvr_top & 0xFFF);
return;
}
@@ -2423,27 +2436,142 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
}
if (ppag.domain != 0x12) {
- bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
+ bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
return;
}
- /* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
- if (!(ppag.mode & BIT(0))) {
- bt_dev_dbg(hdev, "PPAG-BT: disabled");
+ /* PPAG mode
+ * BIT 0 : 0 Disabled in EU
+ * 1 Enabled in EU
+ * BIT 1 : 0 Disabled in China
+ * 1 Enabled in China
+ */
+ if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
+ bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
return;
}
- ppag_cmd.mcc = cpu_to_le32(0);
- ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */
- ppag_cmd.delta = cpu_to_le32(0);
- skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
+ ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
+
+ skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
return;
}
+ bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
kfree_skb(skb);
}
+static int btintel_acpi_reset_method(struct hci_dev *hdev)
+{
+ int ret = 0;
+ acpi_status status;
+ union acpi_object *p, *ref;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ bt_dev_err(hdev, "Failed to run _PRR method");
+ ret = -ENODEV;
+ return ret;
+ }
+ p = buffer.pointer;
+
+ if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) {
+ bt_dev_err(hdev, "Invalid arguments");
+ ret = -EINVAL;
+ goto exit_on_error;
+ }
+
+ ref = &p->package.elements[0];
+ if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) {
+ bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type);
+ ret = -EINVAL;
+ goto exit_on_error;
+ }
+
+ status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ bt_dev_err(hdev, "Failed to run_RST method");
+ ret = -ENODEV;
+ goto exit_on_error;
+ }
+
+exit_on_error:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
+ struct intel_version_tlv *ver_tlv)
+{
+ struct btintel_data *data = hci_get_priv(hdev);
+ acpi_handle handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
+ u8 reset_payload[4] = {0x01, 0x00, 0x01, 0x00};
+ union acpi_object *obj, argv4;
+ enum {
+ RESET_TYPE_WDISABLE2,
+ RESET_TYPE_VSEC
+ };
+
+ handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
+
+ if (!handle) {
+ bt_dev_dbg(hdev, "No support for bluetooth device in ACPI firmware");
+ return;
+ }
+
+ if (!acpi_has_method(handle, "_PRR")) {
+ bt_dev_err(hdev, "No support for _PRR ACPI method");
+ return;
+ }
+
+ switch (ver_tlv->cnvi_top & 0xfff) {
+ case 0x910: /* GalePeak2 */
+ reset_payload[2] = RESET_TYPE_VSEC;
+ break;
+ default:
+ /* WDISABLE2 is the default reset method */
+ reset_payload[2] = RESET_TYPE_WDISABLE2;
+
+ if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
+ BIT(DSM_SET_WDISABLE2_DELAY))) {
+ bt_dev_err(hdev, "No dsm support to set reset delay");
+ return;
+ }
+ argv4.integer.type = ACPI_TYPE_INTEGER;
+ /* delay required to toggle BT power */
+ argv4.integer.value = 160;
+ obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
+ DSM_SET_WDISABLE2_DELAY, &argv4);
+ if (!obj) {
+ bt_dev_err(hdev, "Failed to call dsm to set reset delay");
+ return;
+ }
+ ACPI_FREE(obj);
+ }
+
+ bt_dev_info(hdev, "DSM reset method type: 0x%02x", reset_payload[2]);
+
+ if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
+ DSM_SET_RESET_METHOD)) {
+ bt_dev_warn(hdev, "No support for dsm to set reset method");
+ return;
+ }
+ argv4.buffer.type = ACPI_TYPE_BUFFER;
+ argv4.buffer.length = sizeof(reset_payload);
+ argv4.buffer.pointer = reset_payload;
+
+ obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
+ DSM_SET_RESET_METHOD, &argv4);
+ if (!obj) {
+ bt_dev_err(hdev, "Failed to call dsm to set reset method");
+ return;
+ }
+ ACPI_FREE(obj);
+ data->acpi_reset_method = btintel_acpi_reset_method;
+}
+
static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver)
{
@@ -2528,6 +2656,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
case 0x18:
case 0x19:
case 0x1b:
+ case 0x1c:
hci_set_msft_opcode(hdev, 0xFC1E);
break;
default:
@@ -2658,6 +2787,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks);
+ /* These variants don't seem to support LE Coded PHY */
+ set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
+
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant);
@@ -2729,6 +2861,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
*/
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
+ /* These variants don't seem to support LE Coded PHY */
+ set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
+
/* Set Valid LE States quirk */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
@@ -2742,6 +2877,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
case 0x18:
case 0x19:
case 0x1b:
+ case 0x1c:
/* Display version information of TLV type */
btintel_version_info_tlv(hdev, &ver_tlv);
@@ -2757,6 +2893,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev,
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
+ btintel_set_dsm_reset_method(hdev, &ver_tlv);
err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
btintel_register_devcoredump_support(hdev);
@@ -2824,6 +2961,80 @@ 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)
+{
+ struct intel_tlv *tlv = (void *)&skb->data[5];
+
+ /* The first event is always an event type TLV */
+ if (tlv->type != INTEL_TLV_TYPE_ID)
+ goto recv_frame;
+
+ switch (tlv->val[0]) {
+ case INTEL_TLV_SYSTEM_EXCEPTION:
+ case INTEL_TLV_FATAL_EXCEPTION:
+ case INTEL_TLV_DEBUG_EXCEPTION:
+ case INTEL_TLV_TEST_EXCEPTION:
+ /* Generate devcoredump from exception */
+ if (!hci_devcd_init(hdev, skb->len)) {
+ hci_devcd_append(hdev, skb);
+ hci_devcd_complete(hdev);
+ } else {
+ bt_dev_err(hdev, "Failed to generate devcoredump");
+ kfree_skb(skb);
+ }
+ return 0;
+ default:
+ bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
+ }
+
+recv_frame:
+ return hci_recv_frame(hdev, skb);
+}
+
+int btintel_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 };
+
+ 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);
+ break;
+ 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);
+ break;
+ }
+ }
+
+ /* 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);
+ }
+ }
+
+ return hci_recv_frame(hdev, skb);
+}
+EXPORT_SYMBOL_GPL(btintel_recv_event);
+
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len)
{
const struct intel_bootup *evt = ptr;
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index d6a1dc8d8a82..3a2d5b4219dd 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -137,10 +137,9 @@ struct intel_offload_use_cases {
__u8 preset[8];
} __packed;
-struct btintel_loc_aware_reg {
- __le32 mcc;
- __le32 sel;
- __le32 delta;
+#define INTEL_OP_PPAG_CMD 0xFE0B
+struct hci_ppag_enable_cmd {
+ __le32 ppag_enable_flags;
} __packed;
#define INTEL_TLV_TYPE_ID 0x01
@@ -166,12 +165,14 @@ enum {
INTEL_BROKEN_SHUTDOWN_LED,
INTEL_ROM_LEGACY,
INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
+ INTEL_ACPI_RESET_ACTIVE,
__INTEL_NUM_FLAGS,
};
struct btintel_data {
DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
+ int (*acpi_reset_method)(struct hci_dev *hdev);
};
#define btintel_set_flag(hdev, nr) \
@@ -220,6 +221,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
const struct firmware *fw, u32 *boot_param);
int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name);
+int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
void btintel_secure_send_result(struct hci_dev *hdev,
const void *ptr, unsigned int len);
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 809762d64fc6..aaabb732082c 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -53,10 +53,61 @@ struct btmtk_section_map {
};
} __packed;
+static void btmtk_coredump(struct hci_dev *hdev)
+{
+ int err;
+
+ err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL);
+ if (err < 0)
+ bt_dev_err(hdev, "Coredump failed (%d)", err);
+}
+
+static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btmediatek_data *data = hci_get_priv(hdev);
+ char buf[80];
+
+ snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
+ data->dev_id);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
+ data->cd_info.fw_version);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Driver: %s\n",
+ data->cd_info.driver_name);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Vendor: MediaTek\n");
+ skb_put_data(skb, buf, strlen(buf));
+}
+
+static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
+{
+ struct btmediatek_data *data = hci_get_priv(hdev);
+
+ switch (state) {
+ case HCI_DEVCOREDUMP_IDLE:
+ data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
+ break;
+ case HCI_DEVCOREDUMP_ACTIVE:
+ data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE;
+ break;
+ case HCI_DEVCOREDUMP_TIMEOUT:
+ case HCI_DEVCOREDUMP_ABORT:
+ case HCI_DEVCOREDUMP_DONE:
+ data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
+ btmtk_reset_sync(hdev);
+ break;
+ }
+}
+
int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
struct btmtk_hci_wmt_params wmt_params;
+ struct btmtk_patch_header *hdr;
struct btmtk_global_desc *globaldesc = NULL;
struct btmtk_section_map *sectionmap;
const struct firmware *fw;
@@ -75,9 +126,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
fw_ptr = fw->data;
fw_bin_ptr = fw_ptr;
+ hdr = (struct btmtk_patch_header *)fw_ptr;
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
section_num = le32_to_cpu(globaldesc->section_num);
+ bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
+ le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
+
for (i = 0; i < section_num; i++) {
first_block = 1;
fw_ptr = fw_bin_ptr;
@@ -280,6 +335,83 @@ int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);
+void btmtk_reset_sync(struct hci_dev *hdev)
+{
+ struct btmediatek_data *reset_work = hci_get_priv(hdev);
+ int err;
+
+ hci_dev_lock(hdev);
+
+ err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
+ if (err)
+ bt_dev_err(hdev, "failed to reset (%d)", err);
+
+ hci_dev_unlock(hdev);
+}
+EXPORT_SYMBOL_GPL(btmtk_reset_sync);
+
+int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
+ u32 fw_version)
+{
+ struct btmediatek_data *data = hci_get_priv(hdev);
+
+ if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
+ return -EOPNOTSUPP;
+
+ data->cd_info.fw_version = fw_version;
+ data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
+ data->cd_info.driver_name = name;
+
+ return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
+ btmtk_coredump_notify);
+}
+EXPORT_SYMBOL_GPL(btmtk_register_coredump);
+
+int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btmediatek_data *data = hci_get_priv(hdev);
+ int err;
+
+ if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
+ return 0;
+
+ switch (data->cd_info.state) {
+ case HCI_DEVCOREDUMP_IDLE:
+ err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
+ if (err < 0)
+ break;
+ data->cd_info.cnt = 0;
+
+ /* It is supposed coredump can be done within 5 seconds */
+ schedule_delayed_work(&hdev->dump.dump_timeout,
+ msecs_to_jiffies(5000));
+ fallthrough;
+ case HCI_DEVCOREDUMP_ACTIVE:
+ default:
+ err = hci_devcd_append(hdev, skb);
+ if (err < 0)
+ break;
+ data->cd_info.cnt++;
+
+ /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
+ if (data->cd_info.cnt > MTK_COREDUMP_NUM &&
+ skb->len > MTK_COREDUMP_END_LEN)
+ if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
+ MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) {
+ bt_dev_info(hdev, "Mediatek coredump end");
+ hci_devcd_complete(hdev);
+ }
+
+ break;
+ }
+
+ if (err < 0)
+ kfree_skb(skb);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(btmtk_process_coredump);
+
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
@@ -289,3 +421,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7622);
MODULE_FIRMWARE(FIRMWARE_MT7663);
MODULE_FIRMWARE(FIRMWARE_MT7668);
MODULE_FIRMWARE(FIRMWARE_MT7961);
+MODULE_FIRMWARE(FIRMWARE_MT7925);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
index 2a88ea8e475e..56f5502baadf 100644
--- a/drivers/bluetooth/btmtk.h
+++ b/drivers/bluetooth/btmtk.h
@@ -5,6 +5,7 @@
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
+#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
#define HCI_EV_WMT 0xe4
#define HCI_WMT_MAX_EVENT_SIZE 64
@@ -21,6 +22,11 @@
#define MT7921_DLSTATUS 0x7c053c10
#define BT_DL_STATE BIT(1)
+#define MTK_COREDUMP_SIZE (1024 * 1000)
+#define MTK_COREDUMP_END "coredump end"
+#define MTK_COREDUMP_END_LEN (sizeof(MTK_COREDUMP_END))
+#define MTK_COREDUMP_NUM 255
+
enum {
BTMTK_WMT_PATCH_DWNLD = 0x1,
BTMTK_WMT_TEST = 0x2,
@@ -119,6 +125,21 @@ struct btmtk_hci_wmt_params {
u32 *status;
};
+typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
+
+struct btmtk_coredump_info {
+ const char *driver_name;
+ u32 fw_version;
+ u16 cnt;
+ int state;
+};
+
+struct btmediatek_data {
+ u32 dev_id;
+ btmtk_reset_sync_func_t reset_sync;
+ struct btmtk_coredump_info cd_info;
+};
+
typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
struct btmtk_hci_wmt_params *);
@@ -131,6 +152,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync);
+
+void btmtk_reset_sync(struct hci_dev *hdev);
+
+int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
+ u32 fw_version);
+
+int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
#else
static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
@@ -151,4 +179,18 @@ static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
return -EOPNOTSUPP;
}
+static void btmtk_reset_sync(struct hci_dev *hdev)
+{
+}
+
+static int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
+ u32 fw_version)
+{
+ return -EOPNOTSUPP;
+}
+
+static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ return -EOPNOTSUPP;
+}
#endif
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index 7680c67cdb35..935feab815d9 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 52ef44688d38..b7e66b7ac570 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -28,17 +28,34 @@
#define BTNXPUART_FW_DOWNLOADING 2
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
#define BTNXPUART_SERDEV_OPEN 4
-
-#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
-#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
-#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
-#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
-#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
-#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
+#define BTNXPUART_IR_IN_PROGRESS 5
+
+/* NXP HW err codes */
+#define BTNXPUART_IR_HW_ERR 0xb0
+
+#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
+#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
+#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
+#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
+#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
+#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin"
+#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se"
+#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin"
+#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se"
+#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
#define CHIP_ID_W9098 0x5c03
#define CHIP_ID_IW416 0x7201
#define CHIP_ID_IW612 0x7601
+#define CHIP_ID_IW624a 0x8000
+#define CHIP_ID_IW624c 0x8001
+#define CHIP_ID_AW693 0x8200
+
+#define FW_SECURE_MASK 0xc0
+#define FW_OPEN 0x00
+#define FW_AUTH_ILLEGAL 0x40
+#define FW_AUTH_PLAIN 0x80
+#define FW_AUTH_ENC 0xc0
#define HCI_NXP_PRI_BAUDRATE 115200
#define HCI_NXP_SEC_BAUDRATE 3000000
@@ -143,6 +160,7 @@ struct btnxpuart_dev {
u32 fw_v1_sent_bytes;
u32 fw_v3_offset_correction;
u32 fw_v1_expected_len;
+ u32 boot_reg_offset;
wait_queue_head_t fw_dnld_done_wait_q;
wait_queue_head_t check_boot_sign_wait_q;
@@ -366,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t)
}
}
-static int ps_init_work(struct hci_dev *hdev)
+static void ps_setup(struct hci_dev *hdev)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
struct ps_data *psdata = &nxpdev->psdata;
- psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
- psdata->ps_state = PS_STATE_AWAKE;
- psdata->target_ps_mode = DEFAULT_PS_MODE;
psdata->hdev = hdev;
- psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
- psdata->c2h_wakeup_gpio = 0xff;
-
- switch (DEFAULT_H2C_WAKEUP_MODE) {
- case WAKEUP_METHOD_DTR:
- psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
- break;
- case WAKEUP_METHOD_BREAK:
- default:
- psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
- break;
- }
- psdata->cur_psmode = PS_MODE_DISABLE;
- psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
INIT_WORK(&psdata->work, ps_work_func);
-
- return 0;
-}
-
-static void ps_init_timer(struct hci_dev *hdev)
-{
- struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
- struct ps_data *psdata = &nxpdev->psdata;
-
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
}
@@ -501,19 +493,31 @@ static void ps_init(struct hci_dev *hdev)
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0);
usleep_range(5000, 10000);
- switch (psdata->h2c_wakeupmode) {
+ psdata->ps_state = PS_STATE_AWAKE;
+ psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
+ psdata->c2h_wakeup_gpio = 0xff;
+
+ psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
+ psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
+ switch (DEFAULT_H2C_WAKEUP_MODE) {
case WAKEUP_METHOD_DTR:
+ psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
break;
case WAKEUP_METHOD_BREAK:
default:
+ psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
serdev_device_break_ctl(nxpdev->serdev, -1);
usleep_range(5000, 10000);
serdev_device_break_ctl(nxpdev->serdev, 0);
usleep_range(5000, 10000);
break;
}
+
+ psdata->cur_psmode = PS_MODE_DISABLE;
+ psdata->target_ps_mode = DEFAULT_PS_MODE;
+
if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
if (psdata->cur_psmode != psdata->target_ps_mode)
@@ -529,6 +533,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
nxpdev->fw_dnld_v1_offset = 0;
nxpdev->fw_v1_sent_bytes = 0;
nxpdev->fw_v1_expected_len = HDR_LEN;
+ nxpdev->boot_reg_offset = 0;
nxpdev->fw_v3_offset_correction = 0;
nxpdev->baudrate_changed = false;
nxpdev->timeout_changed = false;
@@ -538,7 +543,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
serdev_device_set_flow_control(nxpdev->serdev, false);
nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE;
- /* Wait till FW is downloaded and CTS becomes low */
+ /* Wait till FW is downloaded */
err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q,
!test_bit(BTNXPUART_FW_DOWNLOADING,
&nxpdev->tx_state),
@@ -549,16 +554,11 @@ static int nxp_download_firmware(struct hci_dev *hdev)
}
serdev_device_set_flow_control(nxpdev->serdev, true);
- err = serdev_device_wait_for_cts(nxpdev->serdev, 1, 60000);
- if (err < 0) {
- bt_dev_err(hdev, "CTS is still high. FW Download failed.");
- return err;
- }
release_firmware(nxpdev->fw);
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
/* Allow the downloaded FW to initialize */
- usleep_range(800 * USEC_PER_MSEC, 1 * USEC_PER_SEC);
+ msleep(1200);
return 0;
}
@@ -582,6 +582,12 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
struct nxp_bootloader_cmd nxp_cmd5;
struct uart_config uart_config;
+ u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset;
+ u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset;
+ u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset;
+ u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset;
+ u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset;
+ u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset;
if (req_len == sizeof(nxp_cmd5)) {
nxp_cmd5.header = __cpu_to_le32(5);
@@ -594,17 +600,17 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5));
nxpdev->fw_v3_offset_correction += req_len;
} else if (req_len == sizeof(uart_config)) {
- uart_config.clkdiv.address = __cpu_to_le32(CLKDIVADDR);
+ uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr);
uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
- uart_config.uartdiv.address = __cpu_to_le32(UARTDIVADDR);
+ uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr);
uart_config.uartdiv.value = __cpu_to_le32(1);
- uart_config.mcr.address = __cpu_to_le32(UARTMCRADDR);
+ uart_config.mcr.address = __cpu_to_le32(uartmcraddr);
uart_config.mcr.value = __cpu_to_le32(MCR);
- uart_config.re_init.address = __cpu_to_le32(UARTREINITADDR);
+ uart_config.re_init.address = __cpu_to_le32(uartreinitaddr);
uart_config.re_init.value = __cpu_to_le32(INIT);
- uart_config.icr.address = __cpu_to_le32(UARTICRADDR);
+ uart_config.icr.address = __cpu_to_le32(uarticraddr);
uart_config.icr.value = __cpu_to_le32(ICR);
- uart_config.fcr.address = __cpu_to_le32(UARTFCRADDR);
+ uart_config.fcr.address = __cpu_to_le32(uartfcraddr);
uart_config.fcr.value = __cpu_to_le32(FCR);
/* FW expects swapped CRC bytes */
uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config,
@@ -665,6 +671,9 @@ static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name)
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
int err = 0;
+ if (!fw_name)
+ return -ENOENT;
+
if (!strlen(nxpdev->fw_name)) {
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "%s", fw_name);
@@ -690,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb)
goto free_skb;
chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp);
- if (chip_id == 0xffff) {
+ if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) {
nxpdev->fw_dnld_v1_offset = 0;
nxpdev->fw_v1_sent_bytes = 0;
nxpdev->fw_v1_expected_len = HDR_LEN;
@@ -812,8 +821,10 @@ free_skb:
return 0;
}
-static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid)
+static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
+ u8 loader_ver)
{
+ struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
char *fw_name = NULL;
switch (chipid) {
@@ -826,6 +837,24 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid)
case CHIP_ID_IW612:
fw_name = FIRMWARE_IW612;
break;
+ case CHIP_ID_IW624a:
+ case CHIP_ID_IW624c:
+ nxpdev->boot_reg_offset = 1;
+ if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
+ fw_name = FIRMWARE_IW624;
+ else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
+ fw_name = FIRMWARE_SECURE_IW624;
+ else
+ bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
+ break;
+ case CHIP_ID_AW693:
+ if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
+ fw_name = FIRMWARE_AW693;
+ else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
+ fw_name = FIRMWARE_SECURE_AW693;
+ else
+ bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
+ break;
default:
bt_dev_err(hdev, "Unknown chip signature %04x", chipid);
break;
@@ -838,13 +867,15 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb)
struct v3_start_ind *req = skb_pull_data(skb, sizeof(*req));
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
u16 chip_id;
+ u8 loader_ver;
if (!process_boot_signature(nxpdev))
goto free_skb;
chip_id = le16_to_cpu(req->chip_id);
+ loader_ver = req->loader_ver;
if (!nxp_request_firmware(hdev, nxp_get_fw_name_from_chipid(hdev,
- chip_id)))
+ chip_id, loader_ver)))
nxp_send_ack(NXP_ACK_V3, hdev);
free_skb:
@@ -946,45 +977,13 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
return 0;
}
-static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
-{
- struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
- struct sk_buff *skb;
- u8 *status;
- u8 pcmd = 0;
- int err = 0;
-
- skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- status = skb_pull_data(skb, 1);
- if (!status || *status)
- goto free_skb;
-
- set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
- err = nxp_download_firmware(hdev);
- if (err < 0)
- goto free_skb;
- serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
- nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
- if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
- nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
- nxp_set_baudrate_cmd(hdev, NULL);
- }
- hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
- hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL);
-
-free_skb:
- kfree_skb(skb);
- return err;
-}
-
-/* NXP protocol */
static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
{
serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
- serdev_device_set_flow_control(nxpdev->serdev, true);
+ if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
+ serdev_device_set_flow_control(nxpdev->serdev, false);
+ else
+ serdev_device_set_flow_control(nxpdev->serdev, true);
set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state);
return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q,
@@ -993,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
msecs_to_jiffies(1000));
}
+static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
+{
+ static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
+ 0x01, BTNXPUART_IR_HW_ERR };
+ struct sk_buff *skb;
+
+ skb = bt_skb_alloc(3, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+ skb_put_data(skb, ir_hw_err, 3);
+
+ /* Inject Hardware Error to upper stack */
+ return hci_recv_frame(hdev, skb);
+}
+
+/* NXP protocol */
static int nxp_setup(struct hci_dev *hdev)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
int err = 0;
- set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
- init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
- init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
-
if (nxp_check_boot_sign(nxpdev)) {
bt_dev_dbg(hdev, "Need FW Download.");
err = nxp_download_firmware(hdev);
@@ -1012,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev)
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
}
- device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
- &nxpdev->fw_init_baudrate);
- if (!nxpdev->fw_init_baudrate)
- nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
@@ -1026,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev)
ps_init(hdev);
+ if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
+ hci_dev_clear_flag(hdev, HCI_SETUP);
+
+ return 0;
+}
+
+static void nxp_hw_err(struct hci_dev *hdev, u8 code)
+{
+ struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+
+ switch (code) {
+ case BTNXPUART_IR_HW_ERR:
+ set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state);
+ hci_dev_set_flag(hdev, HCI_SETUP);
+ break;
+ default:
+ break;
+ }
+}
+
+static int nxp_shutdown(struct hci_dev *hdev)
+{
+ struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+ struct sk_buff *skb;
+ u8 *status;
+ u8 pcmd = 0;
+
+ if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) {
+ skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ status = skb_pull_data(skb, 1);
+ if (status) {
+ serdev_device_set_flow_control(nxpdev->serdev, false);
+ set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
+ }
+ kfree_skb(skb);
+ }
+
return 0;
}
@@ -1233,7 +1282,8 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
nxpdev->rx_skb = NULL;
return err;
}
- nxpdev->hdev->stat.byte_rx += count;
+ if (!is_fw_downloading(nxpdev))
+ nxpdev->hdev->stat.byte_rx += count;
return count;
}
@@ -1266,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work);
skb_queue_head_init(&nxpdev->txq);
+ init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
+ init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
+
+ device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
+ &nxpdev->fw_init_baudrate);
+ if (!nxpdev->fw_init_baudrate)
+ nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
+
+ set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
+
crc8_populate_msb(crc8_table, POLYNOMIAL8);
/* Initialize and register HCI device */
@@ -1286,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
hdev->flush = btnxpuart_flush;
hdev->setup = nxp_setup;
hdev->send = nxp_enqueue;
+ hdev->hw_error = nxp_hw_err;
+ hdev->shutdown = nxp_shutdown;
SET_HCIDEV_DEV(hdev, &serdev->dev);
if (hci_register_dev(hdev) < 0) {
@@ -1294,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
return -ENODEV;
}
- ps_init_work(hdev);
- ps_init_timer(hdev);
+ ps_setup(hdev);
return 0;
}
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index e7e58a956d15..5a35ac4138c6 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -594,30 +594,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
/* Firmware files to download are based on ROM version.
* ROM version is derived from last two bytes of soc_ver.
*/
- rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
+ if (soc_type == QCA_WCN3988)
+ rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
+ else
+ rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
if (soc_type == QCA_WCN6750)
qca_send_patch_config_cmd(hdev);
/* Download rampatch file */
config.type = TLV_TYPE_PATCH;
- if (qca_is_wcn399x(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
snprintf(config.fwname, sizeof(config.fwname),
"qca/crbtfw%02x.tlv", rom_ver);
- } else if (soc_type == QCA_QCA6390) {
+ break;
+ case QCA_WCN3988:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/apbtfw%02x.tlv", rom_ver);
+ break;
+ case QCA_QCA6390:
snprintf(config.fwname, sizeof(config.fwname),
"qca/htbtfw%02x.tlv", rom_ver);
- } else if (soc_type == QCA_WCN6750) {
+ break;
+ case QCA_WCN6750:
/* Choose mbn file by default.If mbn file is not found
* then choose tlv file
*/
config.type = ELF_TYPE_PATCH;
snprintf(config.fwname, sizeof(config.fwname),
"qca/msbtfw%02x.mbn", rom_ver);
- } else if (soc_type == QCA_WCN6855) {
+ break;
+ case QCA_WCN6855:
snprintf(config.fwname, sizeof(config.fwname),
"qca/hpbtfw%02x.tlv", rom_ver);
- } else {
+ break;
+ case QCA_WCN7850:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/hmtbtfw%02x.tlv", rom_ver);
+ break;
+ default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/rampatch_%08x.bin", soc_ver);
}
@@ -633,30 +651,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
/* Download NVM configuration */
config.type = TLV_TYPE_NVM;
- if (firmware_name)
+ if (firmware_name) {
snprintf(config.fwname, sizeof(config.fwname),
"qca/%s", firmware_name);
- else if (qca_is_wcn399x(soc_type)) {
- if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
+ } else {
+ switch (soc_type) {
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/crnv%02xu.bin", rom_ver);
+ } else {
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/crnv%02x.bin", rom_ver);
+ }
+ break;
+ case QCA_WCN3988:
snprintf(config.fwname, sizeof(config.fwname),
- "qca/crnv%02xu.bin", rom_ver);
- } else {
+ "qca/apnv%02x.bin", rom_ver);
+ break;
+ case QCA_QCA6390:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/htnv%02x.bin", rom_ver);
+ break;
+ case QCA_WCN6750:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/msnv%02x.bin", rom_ver);
+ break;
+ case QCA_WCN6855:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/hpnv%02x.bin", rom_ver);
+ break;
+ case QCA_WCN7850:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/hmtnv%02x.bin", rom_ver);
+ break;
+
+ default:
snprintf(config.fwname, sizeof(config.fwname),
- "qca/crnv%02x.bin", rom_ver);
+ "qca/nvm_%08x.bin", soc_ver);
}
}
- else if (soc_type == QCA_QCA6390)
- snprintf(config.fwname, sizeof(config.fwname),
- "qca/htnv%02x.bin", rom_ver);
- else if (soc_type == QCA_WCN6750)
- snprintf(config.fwname, sizeof(config.fwname),
- "qca/msnv%02x.bin", rom_ver);
- else if (soc_type == QCA_WCN6855)
- snprintf(config.fwname, sizeof(config.fwname),
- "qca/hpnv%02x.bin", rom_ver);
- else
- snprintf(config.fwname, sizeof(config.fwname),
- "qca/nvm_%08x.bin", soc_ver);
err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
if (err < 0) {
@@ -664,16 +700,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return err;
}
- if (soc_type >= QCA_WCN3991) {
+ switch (soc_type) {
+ case QCA_WCN3991:
+ case QCA_QCA6390:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
err = qca_disable_soc_logging(hdev);
if (err < 0)
return err;
+ break;
+ default:
+ break;
}
/* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
* VsMsftOpCode.
*/
switch (soc_type) {
+ case QCA_WCN3988:
case QCA_WCN3990:
case QCA_WCN3991:
case QCA_WCN3998:
@@ -695,6 +740,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
case QCA_WCN3991:
case QCA_WCN6750:
case QCA_WCN6855:
+ case QCA_WCN7850:
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index b884095bcd9d..03bff5c0059d 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -142,12 +142,14 @@ enum qca_btsoc_type {
QCA_INVALID = -1,
QCA_AR3002,
QCA_ROME,
+ QCA_WCN3988,
QCA_WCN3990,
QCA_WCN3998,
QCA_WCN3991,
QCA_QCA6390,
QCA_WCN6750,
QCA_WCN6855,
+ QCA_WCN7850,
};
#if IS_ENABLED(CONFIG_BT_QCA)
@@ -160,20 +162,6 @@ int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
enum qca_btsoc_type);
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
-static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
-{
- return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3991 ||
- soc_type == QCA_WCN3998;
-}
-static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
-{
- return soc_type == QCA_WCN6750;
-}
-static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
-{
- return soc_type == QCA_WCN6855;
-}
-
#else
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
@@ -201,21 +189,6 @@ static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
return -EOPNOTSUPP;
}
-static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
-{
- return false;
-}
-
-static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
-{
- return false;
-}
-
-static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
-{
- return false;
-}
-
static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index d978e7cea873..84c2c2e1122f 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -32,6 +32,8 @@
#define RTL_ROM_LMP_8851B 0x8851
#define RTL_CONFIG_MAGIC 0x8723ab55
+#define RTL_VSC_OP_COREDUMP 0xfcff
+
#define IC_MATCH_FL_LMPSUBV (1 << 0)
#define IC_MATCH_FL_HCIREV (1 << 1)
#define IC_MATCH_FL_HCIVER (1 << 2)
@@ -81,6 +83,7 @@ struct id_table {
bool has_msft_ext;
char *fw_name;
char *cfg_name;
+ char *hw_info;
};
struct btrtl_device_info {
@@ -101,22 +104,25 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB),
.config_needed = false,
.has_rom_version = false,
- .fw_name = "rtl_bt/rtl8723a_fw.bin",
- .cfg_name = NULL },
+ .fw_name = "rtl_bt/rtl8723a_fw",
+ .cfg_name = NULL,
+ .hw_info = "rtl8723au" },
/* 8723BS */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723bs_fw.bin",
- .cfg_name = "rtl_bt/rtl8723bs_config" },
+ .fw_name = "rtl_bt/rtl8723bs_fw",
+ .cfg_name = "rtl_bt/rtl8723bs_config",
+ .hw_info = "rtl8723bs" },
/* 8723B */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
.config_needed = false,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723b_fw.bin",
- .cfg_name = "rtl_bt/rtl8723b_config" },
+ .fw_name = "rtl_bt/rtl8723b_fw",
+ .cfg_name = "rtl_bt/rtl8723b_config",
+ .hw_info = "rtl8723bu" },
/* 8723CS-CG */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -126,8 +132,9 @@ static const struct id_table ic_id_table[] = {
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723cs_cg_fw.bin",
- .cfg_name = "rtl_bt/rtl8723cs_cg_config" },
+ .fw_name = "rtl_bt/rtl8723cs_cg_fw",
+ .cfg_name = "rtl_bt/rtl8723cs_cg_config",
+ .hw_info = "rtl8723cs-cg" },
/* 8723CS-VF */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -137,8 +144,9 @@ static const struct id_table ic_id_table[] = {
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723cs_vf_fw.bin",
- .cfg_name = "rtl_bt/rtl8723cs_vf_config" },
+ .fw_name = "rtl_bt/rtl8723cs_vf_fw",
+ .cfg_name = "rtl_bt/rtl8723cs_vf_config",
+ .hw_info = "rtl8723cs-vf" },
/* 8723CS-XX */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
@@ -148,139 +156,157 @@ static const struct id_table ic_id_table[] = {
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723cs_xx_fw.bin",
- .cfg_name = "rtl_bt/rtl8723cs_xx_config" },
+ .fw_name = "rtl_bt/rtl8723cs_xx_fw",
+ .cfg_name = "rtl_bt/rtl8723cs_xx_config",
+ .hw_info = "rtl8723cs" },
/* 8723D */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723d_fw.bin",
- .cfg_name = "rtl_bt/rtl8723d_config" },
+ .fw_name = "rtl_bt/rtl8723d_fw",
+ .cfg_name = "rtl_bt/rtl8723d_config",
+ .hw_info = "rtl8723du" },
/* 8723DS */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
.config_needed = true,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8723ds_fw.bin",
- .cfg_name = "rtl_bt/rtl8723ds_config" },
+ .fw_name = "rtl_bt/rtl8723ds_fw",
+ .cfg_name = "rtl_bt/rtl8723ds_config",
+ .hw_info = "rtl8723ds" },
/* 8821A */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
.config_needed = false,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8821a_fw.bin",
- .cfg_name = "rtl_bt/rtl8821a_config" },
+ .fw_name = "rtl_bt/rtl8821a_fw",
+ .cfg_name = "rtl_bt/rtl8821a_config",
+ .hw_info = "rtl8821au" },
/* 8821C */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8821c_fw.bin",
- .cfg_name = "rtl_bt/rtl8821c_config" },
+ .fw_name = "rtl_bt/rtl8821c_fw",
+ .cfg_name = "rtl_bt/rtl8821c_config",
+ .hw_info = "rtl8821cu" },
/* 8821CS */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_UART),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8821cs_fw.bin",
- .cfg_name = "rtl_bt/rtl8821cs_config" },
+ .fw_name = "rtl_bt/rtl8821cs_fw",
+ .cfg_name = "rtl_bt/rtl8821cs_config",
+ .hw_info = "rtl8821cs" },
/* 8761A */
{ IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
.config_needed = false,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8761a_fw.bin",
- .cfg_name = "rtl_bt/rtl8761a_config" },
+ .fw_name = "rtl_bt/rtl8761a_fw",
+ .cfg_name = "rtl_bt/rtl8761a_config",
+ .hw_info = "rtl8761au" },
/* 8761B */
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8761b_fw.bin",
- .cfg_name = "rtl_bt/rtl8761b_config" },
+ .fw_name = "rtl_bt/rtl8761b_fw",
+ .cfg_name = "rtl_bt/rtl8761b_config",
+ .hw_info = "rtl8761btv" },
/* 8761BU */
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
.config_needed = false,
.has_rom_version = true,
- .fw_name = "rtl_bt/rtl8761bu_fw.bin",
- .cfg_name = "rtl_bt/rtl8761bu_config" },
+ .fw_name = "rtl_bt/rtl8761bu_fw",
+ .cfg_name = "rtl_bt/rtl8761bu_config",
+ .hw_info = "rtl8761bu" },
/* 8822C with UART interface */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8822cs_fw.bin",
- .cfg_name = "rtl_bt/rtl8822cs_config" },
+ .fw_name = "rtl_bt/rtl8822cs_fw",
+ .cfg_name = "rtl_bt/rtl8822cs_config",
+ .hw_info = "rtl8822cs" },
/* 8822C with UART interface */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8822cs_fw.bin",
- .cfg_name = "rtl_bt/rtl8822cs_config" },
+ .fw_name = "rtl_bt/rtl8822cs_fw",
+ .cfg_name = "rtl_bt/rtl8822cs_config",
+ .hw_info = "rtl8822cs" },
/* 8822C with USB interface */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8822cu_fw.bin",
- .cfg_name = "rtl_bt/rtl8822cu_config" },
+ .fw_name = "rtl_bt/rtl8822cu_fw",
+ .cfg_name = "rtl_bt/rtl8822cu_config",
+ .hw_info = "rtl8822cu" },
/* 8822B */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8822b_fw.bin",
- .cfg_name = "rtl_bt/rtl8822b_config" },
+ .fw_name = "rtl_bt/rtl8822b_fw",
+ .cfg_name = "rtl_bt/rtl8822b_config",
+ .hw_info = "rtl8822bu" },
/* 8852A */
{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8852au_fw.bin",
- .cfg_name = "rtl_bt/rtl8852au_config" },
+ .fw_name = "rtl_bt/rtl8852au_fw",
+ .cfg_name = "rtl_bt/rtl8852au_config",
+ .hw_info = "rtl8852au" },
/* 8852B with UART interface */
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_UART),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8852bs_fw.bin",
- .cfg_name = "rtl_bt/rtl8852bs_config" },
+ .fw_name = "rtl_bt/rtl8852bs_fw",
+ .cfg_name = "rtl_bt/rtl8852bs_config",
+ .hw_info = "rtl8852bs" },
/* 8852B */
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8852bu_fw.bin",
- .cfg_name = "rtl_bt/rtl8852bu_config" },
+ .fw_name = "rtl_bt/rtl8852bu_fw",
+ .cfg_name = "rtl_bt/rtl8852bu_config",
+ .hw_info = "rtl8852bu" },
/* 8852C */
{ IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
- .fw_name = "rtl_bt/rtl8852cu_fw.bin",
- .cfg_name = "rtl_bt/rtl8852cu_config" },
+ .fw_name = "rtl_bt/rtl8852cu_fw",
+ .cfg_name = "rtl_bt/rtl8852cu_config",
+ .hw_info = "rtl8852cu" },
/* 8851B */
{ IC_INFO(RTL_ROM_LMP_8851B, 0xb, 0xc, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = false,
- .fw_name = "rtl_bt/rtl8851bu_fw.bin",
- .cfg_name = "rtl_bt/rtl8851bu_config" },
+ .fw_name = "rtl_bt/rtl8851bu_fw",
+ .cfg_name = "rtl_bt/rtl8851bu_config",
+ .hw_info = "rtl8851bu" },
};
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
@@ -590,6 +616,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
unsigned char **_buf)
{
static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+ struct btrealtek_data *coredump_info = hci_get_priv(hdev);
struct rtl_epatch_header *epatch_info;
unsigned char *buf;
int i, len;
@@ -705,8 +732,10 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data;
num_patches = le16_to_cpu(epatch_info->num_patches);
+
BT_DBG("fw_version=%x, num_patches=%d",
le32_to_cpu(epatch_info->fw_version), num_patches);
+ coredump_info->rtl_dump.fw_version = le32_to_cpu(epatch_info->fw_version);
/* After the rtl_epatch_header there is a funky patch metadata section.
* Assuming 2 patches, the layout is:
@@ -903,6 +932,53 @@ out:
return ret;
}
+static void btrtl_coredump(struct hci_dev *hdev)
+{
+ static const u8 param[] = { 0x00, 0x00 };
+
+ __hci_cmd_send(hdev, RTL_VSC_OP_COREDUMP, sizeof(param), param);
+}
+
+static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btrealtek_data *coredump_info = hci_get_priv(hdev);
+ char buf[80];
+
+ if (coredump_info->rtl_dump.controller)
+ snprintf(buf, sizeof(buf), "Controller Name: %s\n",
+ coredump_info->rtl_dump.controller);
+ else
+ snprintf(buf, sizeof(buf), "Controller Name: Unknown\n");
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
+ coredump_info->rtl_dump.fw_version);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info->rtl_dump.driver_name);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Vendor: Realtek\n");
+ skb_put_data(skb, buf, strlen(buf));
+}
+
+static int btrtl_register_devcoredump_support(struct hci_dev *hdev)
+{
+ int err;
+
+ err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
+
+ return err;
+}
+
+void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
+{
+ struct btrealtek_data *coredump_info = hci_get_priv(hdev);
+
+ coredump_info->rtl_dump.driver_name = driver_name;
+}
+EXPORT_SYMBOL_GPL(btrtl_set_driver_name);
+
static bool rtl_has_chip_type(u16 lmp_subver)
{
switch (lmp_subver) {
@@ -964,15 +1040,16 @@ EXPORT_SYMBOL_GPL(btrtl_free);
struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
const char *postfix)
{
+ struct btrealtek_data *coredump_info = hci_get_priv(hdev);
struct btrtl_device_info *btrtl_dev;
struct sk_buff *skb;
struct hci_rp_read_local_version *resp;
+ struct hci_command_hdr *cmd;
+ char fw_name[40];
char cfg_name[40];
u16 hci_rev, lmp_subver;
u8 hci_ver, lmp_ver, chip_type = 0;
int ret;
- u16 opcode;
- u8 cmd[2];
u8 reg_val[2];
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
@@ -1041,15 +1118,14 @@ next:
btrtl_dev->drop_fw = false;
if (btrtl_dev->drop_fw) {
- opcode = hci_opcode_pack(0x3f, 0x66);
- cmd[0] = opcode & 0xff;
- cmd[1] = opcode >> 8;
-
- skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
if (!skb)
goto err_free;
- skb_put_data(skb, cmd, sizeof(cmd));
+ cmd = skb_put(skb, HCI_COMMAND_HDR_SIZE);
+ cmd->opcode = cpu_to_le16(0xfc66);
+ cmd->plen = 0;
+
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
ret = hdev->send(hdev, skb);
@@ -1079,8 +1155,26 @@ next:
goto err_free;
}
- btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name,
- &btrtl_dev->fw_data);
+ if (!btrtl_dev->ic_info->fw_name) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ btrtl_dev->fw_len = -EIO;
+ if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
+ snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
+ btrtl_dev->ic_info->fw_name);
+ btrtl_dev->fw_len = rtl_load_file(hdev, fw_name,
+ &btrtl_dev->fw_data);
+ }
+
+ if (btrtl_dev->fw_len < 0) {
+ snprintf(fw_name, sizeof(fw_name), "%s.bin",
+ btrtl_dev->ic_info->fw_name);
+ btrtl_dev->fw_len = rtl_load_file(hdev, fw_name,
+ &btrtl_dev->fw_data);
+ }
+
if (btrtl_dev->fw_len < 0) {
rtl_dev_err(hdev, "firmware file %s not found",
btrtl_dev->ic_info->fw_name);
@@ -1113,6 +1207,9 @@ next:
if (btrtl_dev->ic_info->has_msft_ext)
hci_set_msft_opcode(hdev, 0xFCF0);
+ if (btrtl_dev->ic_info)
+ coredump_info->rtl_dump.controller = btrtl_dev->ic_info->hw_info;
+
return btrtl_dev;
err_free:
@@ -1125,6 +1222,8 @@ EXPORT_SYMBOL_GPL(btrtl_initialize);
int btrtl_download_firmware(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev)
{
+ int err = 0;
+
/* Match a set of subver values that correspond to stock firmware,
* which is not compatible with standard btusb.
* If matched, upload an alternative firmware that does conform to
@@ -1133,12 +1232,14 @@ int btrtl_download_firmware(struct hci_dev *hdev,
*/
if (!btrtl_dev->ic_info) {
rtl_dev_info(hdev, "assuming no firmware upload needed");
- return 0;
+ err = 0;
+ goto done;
}
switch (btrtl_dev->ic_info->lmp_subver) {
case RTL_ROM_LMP_8723A:
- return btrtl_setup_rtl8723a(hdev, btrtl_dev);
+ err = btrtl_setup_rtl8723a(hdev, btrtl_dev);
+ break;
case RTL_ROM_LMP_8723B:
case RTL_ROM_LMP_8821A:
case RTL_ROM_LMP_8761A:
@@ -1146,11 +1247,18 @@ int btrtl_download_firmware(struct hci_dev *hdev,
case RTL_ROM_LMP_8852A:
case RTL_ROM_LMP_8703B:
case RTL_ROM_LMP_8851B:
- return btrtl_setup_rtl8723b(hdev, btrtl_dev);
+ err = btrtl_setup_rtl8723b(hdev, btrtl_dev);
+ break;
default:
rtl_dev_info(hdev, "assuming no firmware upload needed");
- return 0;
+ break;
}
+
+done:
+ if (!err)
+ err = btrtl_register_devcoredump_support(hdev);
+
+ return err;
}
EXPORT_SYMBOL_GPL(btrtl_download_firmware);
@@ -1180,6 +1288,10 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
if (btrtl_dev->project_id == CHIP_ID_8852C)
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
+ if (btrtl_dev->project_id == CHIP_ID_8852A ||
+ btrtl_dev->project_id == CHIP_ID_8852C)
+ set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
+
hci_set_aosp_capable(hdev);
break;
default:
@@ -1398,4 +1510,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
+MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index adb4c2c9abc5..a2d9d34f9fb0 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -109,8 +109,16 @@ enum {
__REALTEK_NUM_FLAGS,
};
+struct rtl_dump_info {
+ const char *driver_name;
+ char *controller;
+ u32 fw_version;
+};
+
struct btrealtek_data {
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
+
+ struct rtl_dump_info rtl_dump;
};
#define btrealtek_set_flag(hdev, nr) \
@@ -139,6 +147,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev,
unsigned int *controller_baudrate,
u32 *device_baudrate, bool *flow_control);
+void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
#else
@@ -182,4 +191,8 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
return -ENOENT;
}
+static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
+{
+}
+
#endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 764d176e9735..82597ab4f747 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -175,7 +175,7 @@ static const struct usb_device_id btusb_table[] = {
MODULE_DEVICE_TABLE(usb, btusb_table);
-static const struct usb_device_id blacklist_table[] = {
+static const struct usb_device_id quirks_table[] = {
/* CSR BlueCore devices */
{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },
@@ -476,6 +476,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
+ { USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
BTUSB_INTEL_NO_WBS_SUPPORT |
@@ -625,9 +626,24 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe0e4), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x0489, 0xe0f1), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x0489, 0xe0f6), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
@@ -860,10 +876,26 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct gpio_desc *reset_gpio = data->reset_gpio;
+ struct btintel_data *intel_data = hci_get_priv(hdev);
if (++data->cmd_timeout_cnt < 5)
return;
+ if (intel_data->acpi_reset_method) {
+ if (test_and_set_bit(INTEL_ACPI_RESET_ACTIVE, intel_data->flags)) {
+ bt_dev_err(hdev, "acpi: last reset failed ? Not resetting again");
+ return;
+ }
+
+ bt_dev_err(hdev, "Initiating acpi reset method");
+ /* If ACPI reset method fails, lets try with legacy GPIO
+ * toggling
+ */
+ if (!intel_data->acpi_reset_method(hdev)) {
+ return;
+ }
+ }
+
if (!reset_gpio) {
btusb_reset(hdev);
return;
@@ -887,10 +919,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
gpiod_set_value_cansleep(reset_gpio, 0);
}
+#define RTK_DEVCOREDUMP_CODE_MEMDUMP 0x01
+#define RTK_DEVCOREDUMP_CODE_HW_ERR 0x02
+#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT 0x03
+
+#define RTK_SUB_EVENT_CODE_COREDUMP 0x34
+
+struct rtk_dev_coredump_hdr {
+ u8 type;
+ u8 code;
+ u8 reserved[2];
+} __packed;
+
+static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev,
+ struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ skb_put_data(skb, hdr, sizeof(*hdr));
+ if (len)
+ skb_put_data(skb, buf, len);
+
+ if (!hci_devcd_init(hdev, skb->len)) {
+ hci_devcd_append(hdev, skb);
+ hci_devcd_complete(hdev);
+ } else {
+ bt_dev_err(hdev, "RTL: Failed to generate devcoredump");
+ kfree_skb(skb);
+ }
+}
+
static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct gpio_desc *reset_gpio = data->reset_gpio;
+ struct rtk_dev_coredump_hdr hdr = {
+ .type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT,
+ };
+
+ btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
if (++data->cmd_timeout_cnt < 5)
return;
@@ -917,6 +988,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
gpiod_set_value_cansleep(reset_gpio, 0);
}
+static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code)
+{
+ struct rtk_dev_coredump_hdr hdr = {
+ .type = RTK_DEVCOREDUMP_CODE_HW_ERR,
+ .code = code,
+ };
+
+ bt_dev_err(hdev, "RTL: hw err, trigger devcoredump (%d)", code);
+
+ btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
+}
+
static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2079,7 +2162,7 @@ static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts)
* alternate setting.
*/
spin_lock_irqsave(&data->rxlock, flags);
- kfree_skb(data->sco_skb);
+ dev_kfree_skb_irq(data->sco_skb);
data->sco_skb = NULL;
spin_unlock_irqrestore(&data->rxlock, flags);
@@ -2409,79 +2492,6 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer,
return btusb_recv_bulk(data, buffer, count);
}
-static int btusb_intel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct intel_tlv *tlv = (void *)&skb->data[5];
-
- /* The first event is always an event type TLV */
- if (tlv->type != INTEL_TLV_TYPE_ID)
- goto recv_frame;
-
- switch (tlv->val[0]) {
- case INTEL_TLV_SYSTEM_EXCEPTION:
- case INTEL_TLV_FATAL_EXCEPTION:
- case INTEL_TLV_DEBUG_EXCEPTION:
- case INTEL_TLV_TEST_EXCEPTION:
- /* Generate devcoredump from exception */
- if (!hci_devcd_init(hdev, skb->len)) {
- hci_devcd_append(hdev, skb);
- hci_devcd_complete(hdev);
- } else {
- bt_dev_err(hdev, "Failed to generate devcoredump");
- kfree_skb(skb);
- }
- return 0;
- default:
- bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
- }
-
-recv_frame:
- return hci_recv_frame(hdev, skb);
-}
-
-static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_event_hdr *hdr = (void *)skb->data;
- const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
-
- 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);
- break;
- 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);
- break;
- }
- }
-
- /* 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 btusb_intel_diagnostics(hdev, skb);
- }
- }
-
- return hci_recv_frame(hdev, skb);
-}
-
static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
{
struct urb *urb;
@@ -2562,6 +2572,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
return ret;
}
+static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
+ struct rtk_dev_coredump_hdr hdr = {
+ .code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
+ };
+
+ bt_dev_dbg(hdev, "RTL: received coredump vendor evt, len %u",
+ skb->len);
+
+ btusb_rtl_alloc_devcoredump(hdev, &hdr, skb->data, skb->len);
+ kfree_skb(skb);
+
+ return 0;
+ }
+
+ return hci_recv_frame(hdev, skb);
+}
+
/* UHW CR mapping */
#define MTK_BT_MISC 0x70002510
#define MTK_BT_SUBSYS_RST 0x70002610
@@ -2571,8 +2600,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
#define MTK_EP_RST_OPT 0x74011890
#define MTK_EP_RST_IN_OUT_OPT 0x00010001
#define MTK_BT_RST_DONE 0x00000100
-#define MTK_BT_RESET_WAIT_MS 100
-#define MTK_BT_RESET_NUM_TRIES 10
+#define MTK_BT_RESET_REG_CONNV3 0x70028610
+#define MTK_BT_READ_DEV_ID 0x70010200
+
static void btusb_mtk_wmt_recv(struct urb *urb)
{
@@ -2943,6 +2973,88 @@ static int btusb_mtk_id_get(struct btusb_data *data, u32 reg, u32 *id)
return btusb_mtk_reg_read(data, reg, id);
}
+static u32 btusb_mtk_reset_done(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ u32 val = 0;
+
+ btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
+
+ return val & MTK_BT_RST_DONE;
+}
+
+static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct btmediatek_data *mediatek;
+ u32 val;
+ int err;
+
+ /* It's MediaTek specific bluetooth reset mechanism via USB */
+ if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
+ bt_dev_err(hdev, "last reset failed? Not resetting again");
+ return -EBUSY;
+ }
+
+ err = usb_autopm_get_interface(data->intf);
+ if (err < 0)
+ return err;
+
+ btusb_stop_traffic(data);
+ usb_kill_anchored_urbs(&data->tx_anchor);
+ mediatek = hci_get_priv(hdev);
+
+ if (mediatek->dev_id == 0x7925) {
+ btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+ val |= (1 << 5);
+ btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+ btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+ val &= 0xFFFF00FF;
+ val |= (1 << 13);
+ btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+ btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001);
+ btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
+ val |= (1 << 0);
+ btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
+ btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
+ btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
+ btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+ btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
+ msleep(100);
+ } else {
+ /* It's Device EndPoint Reset Option Register */
+ bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
+ btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
+ btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
+
+ /* Reset the bluetooth chip via USB interface. */
+ btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
+ btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
+ btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
+ btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+ btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
+ /* MT7921 need to delay 20ms between toggle reset bit */
+ msleep(20);
+ btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
+ btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
+ }
+
+ err = readx_poll_timeout(btusb_mtk_reset_done, hdev, val,
+ val & MTK_BT_RST_DONE, 20000, 1000000);
+ if (err < 0)
+ bt_dev_err(hdev, "Reset timeout");
+
+ btusb_mtk_id_get(data, 0x70010200, &val);
+ if (!val)
+ bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
+
+ usb_queue_reset_device(data->intf);
+
+ clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
+
+ return err;
+}
+
static int btusb_mtk_setup(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2953,10 +3065,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
struct sk_buff *skb;
const char *fwname;
int err, status;
- u32 dev_id;
+ u32 dev_id = 0;
char fw_bin_name[64];
u32 fw_version = 0;
u8 param;
+ struct btmediatek_data *mediatek;
calltime = ktime_get();
@@ -2966,7 +3079,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
return err;
}
- if (!dev_id) {
+ if (!dev_id || dev_id != 0x7663) {
err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
if (err < 0) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
@@ -2979,6 +3092,14 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
}
}
+ mediatek = hci_get_priv(hdev);
+ mediatek->dev_id = dev_id;
+ mediatek->reset_sync = btusb_mtk_reset;
+
+ err = btmtk_register_coredump(hdev, btusb_driver.name, fw_version);
+ if (err < 0)
+ bt_dev_err(hdev, "Failed to register coredump (%d)", err);
+
switch (dev_id) {
case 0x7663:
fwname = FIRMWARE_MT7663;
@@ -2988,9 +3109,16 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
break;
case 0x7922:
case 0x7961:
- snprintf(fw_bin_name, sizeof(fw_bin_name),
- "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
- dev_id & 0xffff, (fw_version & 0xff) + 1);
+ case 0x7925:
+ if (dev_id == 0x7925)
+ snprintf(fw_bin_name, sizeof(fw_bin_name),
+ "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+ dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
+ else
+ snprintf(fw_bin_name, sizeof(fw_bin_name),
+ "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+ dev_id & 0xffff, (fw_version & 0xff) + 1);
+
err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
btusb_mtk_hci_wmt_sync);
if (err < 0) {
@@ -3128,67 +3256,11 @@ static int btusb_mtk_shutdown(struct hci_dev *hdev)
return 0;
}
-static void btusb_mtk_cmd_timeout(struct hci_dev *hdev)
-{
- struct btusb_data *data = hci_get_drvdata(hdev);
- u32 val;
- int err, retry = 0;
-
- /* It's MediaTek specific bluetooth reset mechanism via USB */
- if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
- bt_dev_err(hdev, "last reset failed? Not resetting again");
- return;
- }
-
- err = usb_autopm_get_interface(data->intf);
- if (err < 0)
- return;
-
- btusb_stop_traffic(data);
- usb_kill_anchored_urbs(&data->tx_anchor);
-
- /* It's Device EndPoint Reset Option Register */
- bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
- btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
- btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
-
- /* Reset the bluetooth chip via USB interface. */
- btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
- btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
- btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
- btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
- btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
- /* MT7921 need to delay 20ms between toggle reset bit */
- msleep(20);
- btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
- btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
-
- /* Poll the register until reset is completed */
- do {
- btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
- if (val & MTK_BT_RST_DONE) {
- bt_dev_dbg(hdev, "Bluetooth Reset Successfully");
- break;
- }
-
- bt_dev_dbg(hdev, "Polling Bluetooth Reset CR");
- retry++;
- msleep(MTK_BT_RESET_WAIT_MS);
- } while (retry < MTK_BT_RESET_NUM_TRIES);
-
- btusb_mtk_id_get(data, 0x70010200, &val);
- if (!val)
- bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
-
- usb_queue_reset_device(data->intf);
-
- clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
-}
-
static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
+ struct sk_buff *skb_cd;
switch (handle) {
case 0xfc6f: /* Firmware dump from device */
@@ -3196,6 +3268,15 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
* suspend and thus disable auto-suspend.
*/
usb_disable_autosuspend(data->udev);
+
+ /* We need to forward the diagnostic packet to userspace daemon
+ * for backward compatibility, so we have to clone the packet
+ * extraly for the in-kernel coredump support.
+ */
+ skb_cd = skb_clone(skb, GFP_ATOMIC);
+ if (skb_cd)
+ btmtk_process_coredump(hdev, skb_cd);
+
fallthrough;
case 0x05ff: /* Firmware debug logging 1 */
case 0x05fe: /* Firmware debug logging 2 */
@@ -4113,7 +4194,7 @@ static int btusb_probe(struct usb_interface *intf,
if (!id->driver_info) {
const struct usb_device_id *match;
- match = usb_match_id(intf, blacklist_table);
+ match = usb_match_id(intf, quirks_table);
if (match)
id = match;
}
@@ -4196,11 +4277,16 @@ static int btusb_probe(struct usb_interface *intf,
priv_size += sizeof(struct btintel_data);
/* Override the rx handlers */
- data->recv_event = btusb_recv_event_intel;
+ data->recv_event = btintel_recv_event;
data->recv_bulk = btusb_recv_bulk_intel;
} else if (id->driver_info & BTUSB_REALTEK) {
/* Allocate extra space for Realtek device */
priv_size += sizeof(struct btrealtek_data);
+
+ data->recv_event = btusb_recv_event_realtek;
+ } else if (id->driver_info & BTUSB_MEDIATEK) {
+ /* Allocate extra space for Mediatek device */
+ priv_size += sizeof(struct btmediatek_data);
}
data->recv_acl = hci_recv_frame;
@@ -4307,7 +4393,7 @@ static int btusb_probe(struct usb_interface *intf,
hdev->setup = btusb_mtk_setup;
hdev->shutdown = btusb_mtk_shutdown;
hdev->manufacturer = 70;
- hdev->cmd_timeout = btusb_mtk_cmd_timeout;
+ hdev->cmd_timeout = btmtk_reset_sync;
hdev->set_bdaddr = btmtk_set_bdaddr;
set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
@@ -4364,9 +4450,11 @@ static int btusb_probe(struct usb_interface *intf,
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
(id->driver_info & BTUSB_REALTEK)) {
+ btrtl_set_driver_name(hdev, btusb_driver.name);
hdev->setup = btusb_setup_realtek;
hdev->shutdown = btrtl_shutdown_realtek;
hdev->cmd_timeout = btusb_rtl_cmd_timeout;
+ hdev->hw_error = btusb_rtl_hw_error;
/* Realtek devices need to set remote wakeup on auto-suspend */
set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index fefc37b98b4a..71e748a9477e 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -11,7 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/serdev.h>
#include <linux/skbuff.h>
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index efdda2c3fce8..a76eb98c0047 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -770,7 +770,8 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
break;
case HCIUARTGETPROTO:
- if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags) &&
+ test_bit(HCI_UART_PROTO_READY, &hu->flags))
err = hu->proto->id;
else
err = -EUNATCH;
diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c
index 05f7f6de6863..97da0b2bfd17 100644
--- a/drivers/bluetooth/hci_nokia.c
+++ b/drivers/bluetooth/hci_nokia.c
@@ -734,7 +734,11 @@ static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev)
return err;
}
- clk_prepare_enable(sysclk);
+ err = clk_prepare_enable(sysclk);
+ if (err) {
+ dev_err(dev, "could not enable sysclk: %d", err);
+ return err;
+ }
btdev->sysclk_speed = clk_get_rate(sysclk);
clk_disable_unprepare(sysclk);
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index e30c979535b1..4b57e15f9c7a 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -25,7 +25,7 @@
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -117,9 +117,7 @@ enum qca_memdump_states {
QCA_MEMDUMP_TIMEOUT,
};
-struct qca_memdump_data {
- char *memdump_buf_head;
- char *memdump_buf_tail;
+struct qca_memdump_info {
u32 current_seq_no;
u32 received_dump;
u32 ram_dump_size;
@@ -160,13 +158,15 @@ struct qca_data {
struct work_struct ws_tx_vote_off;
struct work_struct ctrl_memdump_evt;
struct delayed_work ctrl_memdump_timeout;
- struct qca_memdump_data *qca_memdump;
+ struct qca_memdump_info *qca_memdump;
unsigned long flags;
struct completion drop_ev_comp;
wait_queue_head_t suspend_wait_q;
enum qca_memdump_states memdump_state;
struct mutex hci_memdump_lock;
+ u16 fw_version;
+ u16 controller_id;
/* For debugging purpose */
u64 ibs_sent_wacks;
u64 ibs_sent_slps;
@@ -233,6 +233,7 @@ static void qca_regulator_disable(struct qca_serdev *qcadev);
static void qca_power_shutdown(struct hci_uart *hu);
static int qca_power_off(struct hci_dev *hdev);
static void qca_controller_memdump(struct work_struct *work);
+static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb);
static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu)
{
@@ -606,9 +607,18 @@ static int qca_open(struct hci_uart *hu)
if (hu->serdev) {
qcadev = serdev_device_get_drvdata(hu->serdev);
- if (qca_is_wcn399x(qcadev->btsoc_type) ||
- qca_is_wcn6750(qcadev->btsoc_type))
+ switch (qcadev->btsoc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
hu->init_speed = qcadev->init_speed;
+ break;
+
+ default:
+ break;
+ }
if (qcadev->oper_speed)
hu->oper_speed = qcadev->oper_speed;
@@ -980,6 +990,28 @@ static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
return hci_recv_frame(hdev, skb);
}
+static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct qca_data *qca = hu->priv;
+ char buf[80];
+
+ snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
+ qca->controller_id);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
+ qca->fw_version);
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Vendor:Qualcomm\n");
+ skb_put_data(skb, buf, strlen(buf));
+
+ snprintf(buf, sizeof(buf), "Driver: %s\n",
+ hu->serdev->dev.driver->name);
+ skb_put_data(skb, buf, strlen(buf));
+}
+
static void qca_controller_memdump(struct work_struct *work)
{
struct qca_data *qca = container_of(work, struct qca_data,
@@ -987,13 +1019,11 @@ static void qca_controller_memdump(struct work_struct *work)
struct hci_uart *hu = qca->hu;
struct sk_buff *skb;
struct qca_memdump_event_hdr *cmd_hdr;
- struct qca_memdump_data *qca_memdump = qca->qca_memdump;
+ struct qca_memdump_info *qca_memdump = qca->qca_memdump;
struct qca_dump_size *dump;
- char *memdump_buf;
- char nullBuff[QCA_DUMP_PACKET_SIZE] = { 0 };
u16 seq_no;
- u32 dump_size;
u32 rx_size;
+ int ret = 0;
enum qca_btsoc_type soc_type = qca_soc_type(hu);
while ((skb = skb_dequeue(&qca->rx_memdump_q))) {
@@ -1009,7 +1039,7 @@ static void qca_controller_memdump(struct work_struct *work)
}
if (!qca_memdump) {
- qca_memdump = kzalloc(sizeof(struct qca_memdump_data),
+ qca_memdump = kzalloc(sizeof(struct qca_memdump_info),
GFP_ATOMIC);
if (!qca_memdump) {
mutex_unlock(&qca->hci_memdump_lock);
@@ -1035,44 +1065,49 @@ static void qca_controller_memdump(struct work_struct *work)
set_bit(QCA_IBS_DISABLED, &qca->flags);
set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
dump = (void *) skb->data;
- dump_size = __le32_to_cpu(dump->dump_size);
- if (!(dump_size)) {
+ qca_memdump->ram_dump_size = __le32_to_cpu(dump->dump_size);
+ if (!(qca_memdump->ram_dump_size)) {
bt_dev_err(hu->hdev, "Rx invalid memdump size");
kfree(qca_memdump);
kfree_skb(skb);
- qca->qca_memdump = NULL;
mutex_unlock(&qca->hci_memdump_lock);
return;
}
- bt_dev_info(hu->hdev, "QCA collecting dump of size:%u",
- dump_size);
queue_delayed_work(qca->workqueue,
&qca->ctrl_memdump_timeout,
- msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)
- );
-
- skb_pull(skb, sizeof(dump_size));
- memdump_buf = vmalloc(dump_size);
- qca_memdump->ram_dump_size = dump_size;
- qca_memdump->memdump_buf_head = memdump_buf;
- qca_memdump->memdump_buf_tail = memdump_buf;
- }
+ msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
+ skb_pull(skb, sizeof(qca_memdump->ram_dump_size));
+ qca_memdump->current_seq_no = 0;
+ qca_memdump->received_dump = 0;
+ ret = hci_devcd_init(hu->hdev, qca_memdump->ram_dump_size);
+ bt_dev_info(hu->hdev, "hci_devcd_init Return:%d",
+ ret);
+ if (ret < 0) {
+ kfree(qca->qca_memdump);
+ qca->qca_memdump = NULL;
+ qca->memdump_state = QCA_MEMDUMP_COLLECTED;
+ cancel_delayed_work(&qca->ctrl_memdump_timeout);
+ clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
+ mutex_unlock(&qca->hci_memdump_lock);
+ return;
+ }
- memdump_buf = qca_memdump->memdump_buf_tail;
+ bt_dev_info(hu->hdev, "QCA collecting dump of size:%u",
+ qca_memdump->ram_dump_size);
+
+ }
/* If sequence no 0 is missed then there is no point in
* accepting the other sequences.
*/
- if (!memdump_buf) {
+ if (!test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) {
bt_dev_err(hu->hdev, "QCA: Discarding other packets");
kfree(qca_memdump);
kfree_skb(skb);
- qca->qca_memdump = NULL;
mutex_unlock(&qca->hci_memdump_lock);
return;
}
-
/* There could be chance of missing some packets from
* the controller. In such cases let us store the dummy
* packets in the buffer.
@@ -1082,8 +1117,8 @@ static void qca_controller_memdump(struct work_struct *work)
* bits, so skip this checking for missing packet.
*/
while ((seq_no > qca_memdump->current_seq_no + 1) &&
- (soc_type != QCA_QCA6390) &&
- seq_no != QCA_LAST_SEQUENCE_NUM) {
+ (soc_type != QCA_QCA6390) &&
+ seq_no != QCA_LAST_SEQUENCE_NUM) {
bt_dev_err(hu->hdev, "QCA controller missed packet:%d",
qca_memdump->current_seq_no);
rx_size = qca_memdump->received_dump;
@@ -1094,43 +1129,38 @@ static void qca_controller_memdump(struct work_struct *work)
qca_memdump->received_dump);
break;
}
- memcpy(memdump_buf, nullBuff, QCA_DUMP_PACKET_SIZE);
- memdump_buf = memdump_buf + QCA_DUMP_PACKET_SIZE;
+ hci_devcd_append_pattern(hu->hdev, 0x00,
+ QCA_DUMP_PACKET_SIZE);
qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE;
qca_memdump->current_seq_no++;
}
- rx_size = qca_memdump->received_dump + skb->len;
+ rx_size = qca_memdump->received_dump + skb->len;
if (rx_size <= qca_memdump->ram_dump_size) {
if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
- (seq_no != qca_memdump->current_seq_no))
+ (seq_no != qca_memdump->current_seq_no)) {
bt_dev_err(hu->hdev,
"QCA memdump unexpected packet %d",
seq_no);
+ }
bt_dev_dbg(hu->hdev,
"QCA memdump packet %d with length %d",
seq_no, skb->len);
- memcpy(memdump_buf, (unsigned char *)skb->data,
- skb->len);
- memdump_buf = memdump_buf + skb->len;
- qca_memdump->memdump_buf_tail = memdump_buf;
- qca_memdump->current_seq_no = seq_no + 1;
- qca_memdump->received_dump += skb->len;
+ hci_devcd_append(hu->hdev, skb);
+ qca_memdump->current_seq_no += 1;
+ qca_memdump->received_dump = rx_size;
} else {
bt_dev_err(hu->hdev,
- "QCA memdump received %d, no space for packet %d",
- qca_memdump->received_dump, seq_no);
+ "QCA memdump received no space for packet %d",
+ qca_memdump->current_seq_no);
}
- qca->qca_memdump = qca_memdump;
- kfree_skb(skb);
+
if (seq_no == QCA_LAST_SEQUENCE_NUM) {
bt_dev_info(hu->hdev,
- "QCA memdump Done, received %d, total %d",
- qca_memdump->received_dump,
- qca_memdump->ram_dump_size);
- memdump_buf = qca_memdump->memdump_buf_head;
- dev_coredumpv(&hu->serdev->dev, memdump_buf,
- qca_memdump->received_dump, GFP_KERNEL);
+ "QCA memdump Done, received %d, total %d",
+ qca_memdump->received_dump,
+ qca_memdump->ram_dump_size);
+ hci_devcd_complete(hu->hdev);
cancel_delayed_work(&qca->ctrl_memdump_timeout);
kfree(qca->qca_memdump);
qca->qca_memdump = NULL;
@@ -1320,12 +1350,20 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
/* Give the controller time to process the request */
- if (qca_is_wcn399x(qca_soc_type(hu)) ||
- qca_is_wcn6750(qca_soc_type(hu)) ||
- qca_is_wcn6855(qca_soc_type(hu)))
+ switch (qca_soc_type(hu)) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
usleep_range(1000, 10000);
- else
+ break;
+
+ default:
msleep(300);
+ }
return 0;
}
@@ -1398,13 +1436,20 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
static int qca_check_speeds(struct hci_uart *hu)
{
- if (qca_is_wcn399x(qca_soc_type(hu)) ||
- qca_is_wcn6750(qca_soc_type(hu)) ||
- qca_is_wcn6855(qca_soc_type(hu))) {
+ switch (qca_soc_type(hu)) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
!qca_get_speed(hu, QCA_OPER_SPEED))
return -EINVAL;
- } else {
+ break;
+
+ default:
if (!qca_get_speed(hu, QCA_INIT_SPEED) ||
!qca_get_speed(hu, QCA_OPER_SPEED))
return -EINVAL;
@@ -1433,14 +1478,29 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
/* Disable flow control for wcn3990 to deassert RTS while
* changing the baudrate of chip and host.
*/
- if (qca_is_wcn399x(soc_type) ||
- qca_is_wcn6750(soc_type) ||
- qca_is_wcn6855(soc_type))
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
hci_uart_set_flow_control(hu, true);
+ break;
- if (soc_type == QCA_WCN3990) {
+ default:
+ break;
+ }
+
+ switch (soc_type) {
+ case QCA_WCN3990:
reinit_completion(&qca->drop_ev_comp);
set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+ break;
+
+ default:
+ break;
}
qca_baudrate = qca_get_baudrate_value(speed);
@@ -1452,12 +1512,23 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
host_set_baudrate(hu, speed);
error:
- if (qca_is_wcn399x(soc_type) ||
- qca_is_wcn6750(soc_type) ||
- qca_is_wcn6855(soc_type))
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
hci_uart_set_flow_control(hu, false);
+ break;
+
+ default:
+ break;
+ }
- if (soc_type == QCA_WCN3990) {
+ switch (soc_type) {
+ case QCA_WCN3990:
/* Wait for the controller to send the vendor event
* for the baudrate change command.
*/
@@ -1469,6 +1540,10 @@ error:
}
clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+ break;
+
+ default:
+ break;
}
}
@@ -1541,8 +1616,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
mutex_lock(&qca->hci_memdump_lock);
if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
bt_dev_err(hu->hdev, "clearing allocated memory due to memdump timeout");
+ hci_devcd_abort(hu->hdev);
if (qca->qca_memdump) {
- vfree(qca->qca_memdump->memdump_buf_head);
kfree(qca->qca_memdump);
qca->qca_memdump = NULL;
}
@@ -1630,12 +1705,20 @@ static int qca_regulator_init(struct hci_uart *hu)
}
}
- if (qca_is_wcn399x(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
/* Forcefully enable wcn399x to enter in to boot mode. */
host_set_baudrate(hu, 2400);
ret = qca_send_power_pulse(hu, false);
if (ret)
return ret;
+ break;
+
+ default:
+ break;
}
/* For wcn6750 need to enable gpio bt_en */
@@ -1652,10 +1735,18 @@ static int qca_regulator_init(struct hci_uart *hu)
qca_set_speed(hu, QCA_INIT_SPEED);
- if (qca_is_wcn399x(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
ret = qca_send_power_pulse(hu, true);
if (ret)
return ret;
+ break;
+
+ default:
+ break;
}
/* Now the device is in ready state to communicate with host.
@@ -1689,11 +1780,18 @@ static int qca_power_on(struct hci_dev *hdev)
if (!hu->serdev)
return 0;
- if (qca_is_wcn399x(soc_type) ||
- qca_is_wcn6750(soc_type) ||
- qca_is_wcn6855(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
ret = qca_regulator_init(hu);
- } else {
+ break;
+
+ default:
qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->bt_en) {
gpiod_set_value_cansleep(qcadev->bt_en, 1);
@@ -1706,6 +1804,17 @@ static int qca_power_on(struct hci_dev *hdev)
return ret;
}
+static void hci_coredump_qca(struct hci_dev *hdev)
+{
+ static const u8 param[] = { 0x26 };
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb))
+ bt_dev_err(hdev, "%s: trigger crash failed (%ld)", __func__, PTR_ERR(skb));
+ kfree_skb(skb);
+}
+
static int qca_setup(struct hci_uart *hu)
{
struct hci_dev *hdev = hu->hdev;
@@ -1716,6 +1825,7 @@ static int qca_setup(struct hci_uart *hu)
const char *firmware_name = qca_get_firmware_name(hu);
int ret;
struct qca_btsoc_version ver;
+ const char *soc_name;
ret = qca_check_speeds(hu);
if (ret)
@@ -1730,10 +1840,30 @@ static int qca_setup(struct hci_uart *hu)
*/
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
- bt_dev_info(hdev, "setting up %s",
- qca_is_wcn399x(soc_type) ? "wcn399x" :
- (soc_type == QCA_WCN6750) ? "wcn6750" :
- (soc_type == QCA_WCN6855) ? "wcn6855" : "ROME/QCA6390");
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ soc_name = "wcn399x";
+ break;
+
+ case QCA_WCN6750:
+ soc_name = "wcn6750";
+ break;
+
+ case QCA_WCN6855:
+ soc_name = "wcn6855";
+ break;
+
+ case QCA_WCN7850:
+ soc_name = "wcn7850";
+ break;
+
+ default:
+ soc_name = "ROME/QCA6390";
+ }
+ bt_dev_info(hdev, "setting up %s", soc_name);
qca->memdump_state = QCA_MEMDUMP_IDLE;
@@ -1744,16 +1874,23 @@ retry:
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
- if (qca_is_wcn399x(soc_type) ||
- qca_is_wcn6750(soc_type) ||
- qca_is_wcn6855(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
hci_set_aosp_capable(hdev);
ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret)
goto out;
- } else {
+ break;
+
+ default:
qca_set_speed(hu, QCA_INIT_SPEED);
}
@@ -1767,9 +1904,17 @@ retry:
qca_baudrate = qca_get_baudrate_value(speed);
}
- if (!(qca_is_wcn399x(soc_type) ||
- qca_is_wcn6750(soc_type) ||
- qca_is_wcn6855(soc_type))) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
+ break;
+
+ default:
/* Get QCA version information */
ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret)
@@ -1820,6 +1965,9 @@ out:
hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
else
hu->hdev->set_bdaddr = qca_set_bdaddr;
+ qca->fw_version = le16_to_cpu(ver.patch_ver);
+ qca->controller_id = le16_to_cpu(ver.rom_ver);
+ hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL);
return ret;
}
@@ -1839,6 +1987,17 @@ static const struct hci_uart_proto qca_proto = {
.dequeue = qca_dequeue,
};
+static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = {
+ .soc_type = QCA_WCN3988,
+ .vregs = (struct qca_vreg []) {
+ { "vddio", 15000 },
+ { "vddxo", 80000 },
+ { "vddrf", 300000 },
+ { "vddch0", 450000 },
+ },
+ .num_vregs = 4,
+};
+
static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = {
.soc_type = QCA_WCN3990,
.vregs = (struct qca_vreg []) {
@@ -1909,6 +2068,20 @@ static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
};
+static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = {
+ .soc_type = QCA_WCN7850,
+ .vregs = (struct qca_vreg []) {
+ { "vddio", 5000 },
+ { "vddaon", 26000 },
+ { "vdddig", 126000 },
+ { "vddrfa0p8", 102000 },
+ { "vddrfa1p2", 257000 },
+ { "vddrfa1p9", 302000 },
+ },
+ .num_vregs = 6,
+ .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
+};
+
static void qca_power_shutdown(struct hci_uart *hu)
{
struct qca_serdev *qcadev;
@@ -1934,11 +2107,18 @@ static void qca_power_shutdown(struct hci_uart *hu)
qcadev = serdev_device_get_drvdata(hu->serdev);
- if (qca_is_wcn399x(soc_type)) {
+ switch (soc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
host_set_baudrate(hu, 2400);
qca_send_power_pulse(hu, false);
qca_regulator_disable(qcadev);
- } else if (soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) {
+ break;
+
+ case QCA_WCN6750:
+ case QCA_WCN6855:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
msleep(100);
qca_regulator_disable(qcadev);
@@ -1946,7 +2126,9 @@ static void qca_power_shutdown(struct hci_uart *hu)
sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
}
- } else if (qcadev->bt_en) {
+ break;
+
+ default:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
}
@@ -2071,11 +2253,19 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->oper_speed)
BT_DBG("UART will pick default operating speed");
- if (data &&
- (qca_is_wcn399x(data->soc_type) ||
- qca_is_wcn6750(data->soc_type) ||
- qca_is_wcn6855(data->soc_type))) {
+ if (data)
qcadev->btsoc_type = data->soc_type;
+ else
+ qcadev->btsoc_type = QCA_ROME;
+
+ switch (qcadev->btsoc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
qcadev->bt_power = devm_kzalloc(&serdev->dev,
sizeof(struct qca_power),
GFP_KERNEL);
@@ -2105,7 +2295,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
GPIOD_IN);
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
- data->soc_type == QCA_WCN6855))
+ data->soc_type == QCA_WCN6855 ||
+ data->soc_type == QCA_WCN7850))
dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
@@ -2119,12 +2310,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
BT_ERR("wcn3990 serdev registration failed");
return err;
}
- } else {
- if (data)
- qcadev->btsoc_type = data->soc_type;
- else
- qcadev->btsoc_type = QCA_ROME;
+ break;
+ default:
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(qcadev->bt_en)) {
@@ -2180,13 +2368,24 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
struct qca_power *power = qcadev->bt_power;
- if ((qca_is_wcn399x(qcadev->btsoc_type) ||
- qca_is_wcn6750(qcadev->btsoc_type) ||
- qca_is_wcn6855(qcadev->btsoc_type)) &&
- power->vregs_on)
- qca_power_shutdown(&qcadev->serdev_hu);
- else if (qcadev->susclk)
- clk_disable_unprepare(qcadev->susclk);
+ switch (qcadev->btsoc_type) {
+ case QCA_WCN3988:
+ case QCA_WCN3990:
+ case QCA_WCN3991:
+ case QCA_WCN3998:
+ case QCA_WCN6750:
+ case QCA_WCN6855:
+ case QCA_WCN7850:
+ if (power->vregs_on) {
+ qca_power_shutdown(&qcadev->serdev_hu);
+ break;
+ }
+ fallthrough;
+
+ default:
+ if (qcadev->susclk)
+ clk_disable_unprepare(qcadev->susclk);
+ }
hci_uart_unregister_device(&qcadev->serdev_hu);
}
@@ -2363,11 +2562,13 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,qca6174-bt" },
{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
{ .compatible = "qcom,qca9377-bt" },
+ { .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988},
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
+ { .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
@@ -2384,6 +2585,18 @@ static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
#endif
+#ifdef CONFIG_DEV_COREDUMP
+static void hciqca_coredump(struct device *dev)
+{
+ struct serdev_device *serdev = to_serdev_device(dev);
+ struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
+ struct hci_uart *hu = &qcadev->serdev_hu;
+ struct hci_dev *hdev = hu->hdev;
+
+ if (hdev->dump.coredump)
+ hdev->dump.coredump(hdev);
+}
+#endif
static struct serdev_device_driver qca_serdev_driver = {
.probe = qca_serdev_probe,
@@ -2394,6 +2607,9 @@ static struct serdev_device_driver qca_serdev_driver = {
.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
.shutdown = qca_serdev_shutdown,
.pm = &qca_pm_ops,
+#ifdef CONFIG_DEV_COREDUMP
+ .coredump = hciqca_coredump,
+#endif
},
};
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index e0b3786ca51b..8de74dcfa18c 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -37,7 +37,7 @@ config HW_RANDOM_TIMERIOMEM
config HW_RANDOM_INTEL
tristate "Intel HW Random Number Generator support"
- depends on (X86 || IA64) && PCI
+ depends on (X86 || IA64 || COMPILE_TEST) && PCI
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -50,7 +50,8 @@ config HW_RANDOM_INTEL
config HW_RANDOM_AMD
tristate "AMD HW Random Number Generator support"
- depends on (X86 || PPC_MAPLE) && PCI
+ depends on (X86 || PPC_MAPLE || COMPILE_TEST)
+ depends on PCI && HAS_IOPORT_MAP
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -63,7 +64,7 @@ config HW_RANDOM_AMD
config HW_RANDOM_ATMEL
tristate "Atmel Random Number Generator support"
- depends on (ARCH_AT91 || COMPILE_TEST) && HAVE_CLK && OF
+ depends on (ARCH_AT91 || COMPILE_TEST)
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -113,7 +114,8 @@ config HW_RANDOM_IPROC_RNG200
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
- depends on X86_32 && PCI
+ depends on (X86_32 || COMPILE_TEST)
+ depends on PCI
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -205,7 +207,7 @@ config HW_RANDOM_OCTEON
config HW_RANDOM_PASEMI
tristate "PA Semi HW Random Number Generator support"
- depends on PPC_PASEMI
+ depends on PPC_PASEMI || (PPC && COMPILE_TEST)
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -228,7 +230,7 @@ config HW_RANDOM_VIRTIO
config HW_RANDOM_MXC_RNGA
tristate "Freescale i.MX RNGA Random Number Generator"
- depends on SOC_IMX31
+ depends on SOC_IMX31 || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -241,7 +243,7 @@ config HW_RANDOM_MXC_RNGA
config HW_RANDOM_IMX_RNGC
tristate "Freescale i.MX RNGC Random Number Generator"
- depends on HAS_IOMEM && HAVE_CLK
+ depends on HAS_IOMEM
depends on SOC_IMX25 || SOC_IMX6SL || SOC_IMX6SLL || SOC_IMX6UL || COMPILE_TEST
default HW_RANDOM
help
@@ -256,8 +258,7 @@ config HW_RANDOM_IMX_RNGC
config HW_RANDOM_INGENIC_RNG
tristate "Ingenic Random Number Generator support"
- depends on HW_RANDOM
- depends on MACH_JZ4780 || MACH_X1000
+ depends on MACH_JZ4780 || MACH_X1000 || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number Generator
@@ -271,8 +272,7 @@ config HW_RANDOM_INGENIC_RNG
config HW_RANDOM_INGENIC_TRNG
tristate "Ingenic True Random Number Generator support"
- depends on HW_RANDOM
- depends on MACH_X1830
+ depends on MACH_X1830 || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the True Random Number Generator
@@ -324,7 +324,7 @@ config HW_RANDOM_POWERNV
config HW_RANDOM_HISI
tristate "Hisilicon Random Number Generator support"
- depends on HW_RANDOM && ARCH_HISI
+ depends on ARCH_HISI || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -348,7 +348,7 @@ config HW_RANDOM_HISTB
config HW_RANDOM_ST
tristate "ST Microelectronics HW Random Number Generator support"
- depends on HW_RANDOM && (ARCH_STI || COMPILE_TEST)
+ depends on ARCH_STI || COMPILE_TEST
help
This driver provides kernel-side support for the Random Number
Generator hardware found on STi series of SoCs.
@@ -358,7 +358,7 @@ config HW_RANDOM_ST
config HW_RANDOM_XGENE
tristate "APM X-Gene True Random Number Generator (TRNG) support"
- depends on HW_RANDOM && ARCH_XGENE
+ depends on ARCH_XGENE || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
@@ -371,7 +371,7 @@ config HW_RANDOM_XGENE
config HW_RANDOM_STM32
tristate "STMicroelectronics STM32 random number generator"
- depends on HW_RANDOM && (ARCH_STM32 || COMPILE_TEST)
+ depends on ARCH_STM32 || COMPILE_TEST
depends on HAS_IOMEM
default HW_RANDOM
help
@@ -385,8 +385,8 @@ config HW_RANDOM_STM32
config HW_RANDOM_PIC32
tristate "Microchip PIC32 Random Number Generator support"
- depends on HW_RANDOM && MACH_PIC32
- default y
+ depends on MACH_PIC32 || COMPILE_TEST
+ default HW_RANDOM if MACH_PIC32
help
This driver provides kernel-side support for the Random Number
Generator hardware found on a PIC32.
@@ -425,7 +425,8 @@ config HW_RANDOM_MESON
config HW_RANDOM_CAVIUM
tristate "Cavium ThunderX Random Number Generator support"
- depends on HW_RANDOM && PCI && ARCH_THUNDER
+ depends on PCI
+ depends on ARCH_THUNDER || (ARM64 && COMPILE_TEST)
default HW_RANDOM
help
This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 0555e3838bce..86162a13681e 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/hw_random.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/char/hw_random/arm_smccc_trng.c b/drivers/char/hw_random/arm_smccc_trng.c
index e34c3ea692b6..7e954341b09f 100644
--- a/drivers/char/hw_random/arm_smccc_trng.c
+++ b/drivers/char/hw_random/arm_smccc_trng.c
@@ -105,8 +105,6 @@ static int smccc_trng_probe(struct platform_device *pdev)
trng->name = "smccc_trng";
trng->read = smccc_trng_read;
- platform_set_drvdata(pdev, trng);
-
return devm_hwrng_register(&pdev->dev, trng);
}
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
index b8effe77d80f..a37367ebcbac 100644
--- a/drivers/char/hw_random/atmel-rng.c
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -15,7 +15,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/hw_random.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/char/hw_random/ba431-rng.c b/drivers/char/hw_random/ba431-rng.c
index 5b7ca0416490..9de7466e6896 100644
--- a/drivers/char/hw_random/ba431-rng.c
+++ b/drivers/char/hw_random/ba431-rng.c
@@ -189,13 +189,9 @@ static int ba431_trng_probe(struct platform_device *pdev)
ba431->rng.cleanup = ba431_trng_cleanup;
ba431->rng.read = ba431_trng_read;
- platform_set_drvdata(pdev, ba431);
-
ret = devm_hwrng_register(&pdev->dev, &ba431->rng);
- if (ret) {
- dev_err(&pdev->dev, "BA431 registration failed (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "BA431 registration failed\n");
dev_info(&pdev->dev, "BA431 TRNG registered\n");
@@ -203,7 +199,7 @@ static int ba431_trng_probe(struct platform_device *pdev)
}
static const struct of_device_id ba431_trng_dt_ids[] = {
- { .compatible = "silex-insight,ba431-rng", .data = NULL },
+ { .compatible = "silex-insight,ba431-rng" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ba431_trng_dt_ids);
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index e98fcac578d6..e19b0f9f48b9 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -8,8 +8,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/clk.h>
diff --git a/drivers/char/hw_random/cctrng.c b/drivers/char/hw_random/cctrng.c
index 302ffa354c2f..1abbff04a015 100644
--- a/drivers/char/hw_random/cctrng.c
+++ b/drivers/char/hw_random/cctrng.c
@@ -455,35 +455,6 @@ static void cc_trng_startwork_handler(struct work_struct *w)
cc_trng_hw_trigger(drvdata);
}
-
-static int cc_trng_clk_init(struct cctrng_drvdata *drvdata)
-{
- struct clk *clk;
- struct device *dev = &(drvdata->pdev->dev);
- int rc = 0;
-
- clk = devm_clk_get_optional(dev, NULL);
- if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk),
- "Error getting clock\n");
-
- drvdata->clk = clk;
-
- rc = clk_prepare_enable(drvdata->clk);
- if (rc) {
- dev_err(dev, "Failed to enable clock\n");
- return rc;
- }
-
- return 0;
-}
-
-static void cc_trng_clk_fini(struct cctrng_drvdata *drvdata)
-{
- clk_disable_unprepare(drvdata->clk);
-}
-
-
static int cctrng_probe(struct platform_device *pdev)
{
struct cctrng_drvdata *drvdata;
@@ -492,6 +463,10 @@ static int cctrng_probe(struct platform_device *pdev)
u32 val;
int irq;
+ /* Compile time assertion checks */
+ BUILD_BUG_ON(CCTRNG_DATA_BUF_WORDS < 6);
+ BUILD_BUG_ON((CCTRNG_DATA_BUF_WORDS & (CCTRNG_DATA_BUF_WORDS-1)) != 0);
+
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
@@ -510,10 +485,8 @@ static int cctrng_probe(struct platform_device *pdev)
drvdata->circ.buf = (char *)drvdata->data_buf;
drvdata->cc_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(drvdata->cc_base)) {
- dev_err(dev, "Failed to ioremap registers");
- return PTR_ERR(drvdata->cc_base);
- }
+ if (IS_ERR(drvdata->cc_base))
+ return dev_err_probe(dev, PTR_ERR(drvdata->cc_base), "Failed to ioremap registers");
/* Then IRQ */
irq = platform_get_irq(pdev, 0);
@@ -522,16 +495,13 @@ static int cctrng_probe(struct platform_device *pdev)
/* parse sampling rate from device tree */
rc = cc_trng_parse_sampling_ratio(drvdata);
- if (rc) {
- dev_err(dev, "Failed to get legal sampling ratio for rosc\n");
- return rc;
- }
+ if (rc)
+ return dev_err_probe(dev, rc, "Failed to get legal sampling ratio for rosc\n");
- rc = cc_trng_clk_init(drvdata);
- if (rc) {
- dev_err(dev, "cc_trng_clk_init failed\n");
- return rc;
- }
+ drvdata->clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(drvdata->clk))
+ return dev_err_probe(dev, PTR_ERR(drvdata->clk),
+ "Failed to get or enable the clock\n");
INIT_WORK(&drvdata->compwork, cc_trng_compwork_handler);
INIT_WORK(&drvdata->startwork, cc_trng_startwork_handler);
@@ -539,10 +509,8 @@ static int cctrng_probe(struct platform_device *pdev)
/* register the driver isr function */
rc = devm_request_irq(dev, irq, cc_isr, IRQF_SHARED, "cctrng", drvdata);
- if (rc) {
- dev_err(dev, "Could not register to interrupt %d\n", irq);
- goto post_clk_err;
- }
+ if (rc)
+ return dev_err_probe(dev, rc, "Could not register to interrupt %d\n", irq);
dev_dbg(dev, "Registered to IRQ: %d\n", irq);
/* Clear all pending interrupts */
@@ -557,17 +525,13 @@ static int cctrng_probe(struct platform_device *pdev)
/* init PM */
rc = cc_trng_pm_init(drvdata);
- if (rc) {
- dev_err(dev, "cc_trng_pm_init failed\n");
- goto post_clk_err;
- }
+ if (rc)
+ return dev_err_probe(dev, rc, "cc_trng_pm_init failed\n");
/* increment device's usage counter */
rc = cc_trng_pm_get(dev);
- if (rc) {
- dev_err(dev, "cc_trng_pm_get returned %x\n", rc);
- goto post_pm_err;
- }
+ if (rc)
+ return dev_err_probe(dev, rc, "cc_trng_pm_get returned %x\n", rc);
/* set pending_hw to verify that HW won't be triggered from read */
atomic_set(&drvdata->pending_hw, 1);
@@ -593,9 +557,6 @@ static int cctrng_probe(struct platform_device *pdev)
post_pm_err:
cc_trng_pm_fini(drvdata);
-post_clk_err:
- cc_trng_clk_fini(drvdata);
-
return rc;
}
@@ -608,8 +569,6 @@ static int cctrng_remove(struct platform_device *pdev)
cc_trng_pm_fini(drvdata);
- cc_trng_clk_fini(drvdata);
-
dev_info(dev, "ARM cctrng device terminated\n");
return 0;
@@ -698,21 +657,7 @@ static struct platform_driver cctrng_driver = {
.remove = cctrng_remove,
};
-static int __init cctrng_mod_init(void)
-{
- /* Compile time assertion checks */
- BUILD_BUG_ON(CCTRNG_DATA_BUF_WORDS < 6);
- BUILD_BUG_ON((CCTRNG_DATA_BUF_WORDS & (CCTRNG_DATA_BUF_WORDS-1)) != 0);
-
- return platform_driver_register(&cctrng_driver);
-}
-module_init(cctrng_mod_init);
-
-static void __exit cctrng_mod_exit(void)
-{
- platform_driver_unregister(&cctrng_driver);
-}
-module_exit(cctrng_mod_exit);
+module_platform_driver(cctrng_driver);
/* Module description */
MODULE_DESCRIPTION("ARM CryptoCell TRNG Driver");
diff --git a/drivers/char/hw_random/cn10k-rng.c b/drivers/char/hw_random/cn10k-rng.c
index 0cd7e1a8e499..31935316a160 100644
--- a/drivers/char/hw_random/cn10k-rng.c
+++ b/drivers/char/hw_random/cn10k-rng.c
@@ -187,10 +187,8 @@ static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, rng);
rng->reg_base = pcim_iomap(pdev, 0, 0);
- if (!rng->reg_base) {
- dev_err(&pdev->dev, "Error while mapping CSRs, exiting\n");
- return -ENOMEM;
- }
+ if (!rng->reg_base)
+ return dev_err_probe(&pdev->dev, -ENOMEM, "Error while mapping CSRs, exiting\n");
rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"cn10k-rng-%s", dev_name(&pdev->dev));
@@ -205,19 +203,12 @@ static int cn10k_rng_probe(struct pci_dev *pdev, const struct pci_device_id *id)
reset_rng_health_state(rng);
err = devm_hwrng_register(&pdev->dev, &rng->ops);
- if (err) {
- dev_err(&pdev->dev, "Could not register hwrng device.\n");
- return err;
- }
+ if (err)
+ return dev_err_probe(&pdev->dev, err, "Could not register hwrng device.\n");
return 0;
}
-static void cn10k_rng_remove(struct pci_dev *pdev)
-{
- /* Nothing to do */
-}
-
static const struct pci_device_id cn10k_rng_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA098) }, /* RNG PF */
{0,},
@@ -229,7 +220,6 @@ static struct pci_driver cn10k_rng_driver = {
.name = "cn10k_rng",
.id_table = cn10k_rng_id_table,
.probe = cn10k_rng_probe,
- .remove = cn10k_rng_remove,
};
module_pci_driver(cn10k_rng_driver);
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index f34d356fe2c0..e3598ec9cfca 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -15,14 +15,13 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/hw_random.h>
-#include <linux/random.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
-#include <linux/sched/signal.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c
index 9cc3d542dd0f..30207b7ac5f4 100644
--- a/drivers/char/hw_random/exynos-trng.c
+++ b/drivers/char/hw_random/exynos-trng.c
@@ -185,14 +185,14 @@ static int exynos_trng_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused exynos_trng_suspend(struct device *dev)
+static int exynos_trng_suspend(struct device *dev)
{
pm_runtime_put_sync(dev);
return 0;
}
-static int __maybe_unused exynos_trng_resume(struct device *dev)
+static int exynos_trng_resume(struct device *dev)
{
int ret;
@@ -205,7 +205,7 @@ static int __maybe_unused exynos_trng_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(exynos_trng_pm_ops, exynos_trng_suspend,
exynos_trng_resume);
static const struct of_device_id exynos_trng_dt_match[] = {
@@ -219,7 +219,7 @@ MODULE_DEVICE_TABLE(of, exynos_trng_dt_match);
static struct platform_driver exynos_trng_driver = {
.driver = {
.name = "exynos-trng",
- .pm = &exynos_trng_pm_ops,
+ .pm = pm_sleep_ptr(&exynos_trng_pm_ops),
.of_match_table = exynos_trng_dt_match,
},
.probe = exynos_trng_probe,
diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c
index bf07f17f78c8..e4b385b01b11 100644
--- a/drivers/char/hw_random/imx-rngc.c
+++ b/drivers/char/hw_random/imx-rngc.c
@@ -239,10 +239,8 @@ static int __init imx_rngc_probe(struct platform_device *pdev)
return PTR_ERR(rngc->base);
rngc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
- if (IS_ERR(rngc->clk)) {
- dev_err(&pdev->dev, "Can not get rng_clk\n");
- return PTR_ERR(rngc->clk);
- }
+ if (IS_ERR(rngc->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rngc->clk), "Cannot get rng_clk\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -272,24 +270,18 @@ static int __init imx_rngc_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev,
irq, imx_rngc_irq, 0, pdev->name, (void *)rngc);
- if (ret) {
- dev_err(rngc->dev, "Can't get interrupt working.\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Can't get interrupt working.\n");
if (self_test) {
ret = imx_rngc_self_test(rngc);
- if (ret) {
- dev_err(rngc->dev, "self test failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "self test failed\n");
}
ret = devm_hwrng_register(&pdev->dev, &rngc->rng);
- if (ret) {
- dev_err(&pdev->dev, "hwrng registration failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "hwrng registration failed\n");
dev_info(&pdev->dev,
"Freescale RNG%c registered (HW revision %d.%02d)\n",
diff --git a/drivers/char/hw_random/ingenic-rng.c b/drivers/char/hw_random/ingenic-rng.c
index 055cfe59f519..4f18c3fa5427 100644
--- a/drivers/char/hw_random/ingenic-rng.c
+++ b/drivers/char/hw_random/ingenic-rng.c
@@ -95,7 +95,7 @@ static int ingenic_rng_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
}
- priv->version = (enum ingenic_rng_version)of_device_get_match_data(&pdev->dev);
+ priv->version = (enum ingenic_rng_version)(uintptr_t)of_device_get_match_data(&pdev->dev);
priv->rng.name = pdev->name;
priv->rng.init = ingenic_rng_init;
diff --git a/drivers/char/hw_random/ingenic-trng.c b/drivers/char/hw_random/ingenic-trng.c
index 0eb80f786f4d..1672320e7d3d 100644
--- a/drivers/char/hw_random/ingenic-trng.c
+++ b/drivers/char/hw_random/ingenic-trng.c
@@ -11,8 +11,8 @@
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -22,8 +22,6 @@
#define TRNG_REG_STATUS_OFFSET 0x08
/* bits within the CFG register */
-#define CFG_RDY_CLR BIT(12)
-#define CFG_INT_MASK BIT(11)
#define CFG_GEN_EN BIT(0)
/* bits within the STATUS register */
@@ -31,7 +29,6 @@
struct ingenic_trng {
void __iomem *base;
- struct clk *clk;
struct hwrng rng;
};
@@ -79,6 +76,7 @@ static int ingenic_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait
static int ingenic_trng_probe(struct platform_device *pdev)
{
struct ingenic_trng *trng;
+ struct clk *clk;
int ret;
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
@@ -86,60 +84,28 @@ static int ingenic_trng_probe(struct platform_device *pdev)
return -ENOMEM;
trng->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(trng->base)) {
- pr_err("%s: Failed to map DTRNG registers\n", __func__);
- ret = PTR_ERR(trng->base);
- return PTR_ERR(trng->base);
- }
+ if (IS_ERR(trng->base))
+ return dev_err_probe(&pdev->dev, PTR_ERR(trng->base),
+ "%s: Failed to map DTRNG registers\n", __func__);
- trng->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(trng->clk)) {
- ret = PTR_ERR(trng->clk);
- pr_crit("%s: Cannot get DTRNG clock\n", __func__);
- return PTR_ERR(trng->clk);
- }
-
- ret = clk_prepare_enable(trng->clk);
- if (ret) {
- pr_crit("%s: Unable to enable DTRNG clock\n", __func__);
- return ret;
- }
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "%s: Cannot get and enable DTRNG clock\n", __func__);
trng->rng.name = pdev->name;
trng->rng.init = ingenic_trng_init;
trng->rng.cleanup = ingenic_trng_cleanup;
trng->rng.read = ingenic_trng_read;
- ret = hwrng_register(&trng->rng);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register hwrng\n");
- goto err_unprepare_clk;
- }
+ ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to register hwrng\n");
platform_set_drvdata(pdev, trng);
dev_info(&pdev->dev, "Ingenic DTRNG driver registered\n");
return 0;
-
-err_unprepare_clk:
- clk_disable_unprepare(trng->clk);
- return ret;
-}
-
-static int ingenic_trng_remove(struct platform_device *pdev)
-{
- struct ingenic_trng *trng = platform_get_drvdata(pdev);
- unsigned int ctrl;
-
- hwrng_unregister(&trng->rng);
-
- ctrl = readl(trng->base + TRNG_REG_CFG_OFFSET);
- ctrl &= ~CFG_GEN_EN;
- writel(ctrl, trng->base + TRNG_REG_CFG_OFFSET);
-
- clk_disable_unprepare(trng->clk);
-
- return 0;
}
static const struct of_device_id ingenic_trng_of_match[] = {
@@ -150,7 +116,6 @@ MODULE_DEVICE_TABLE(of, ingenic_trng_of_match);
static struct platform_driver ingenic_trng_driver = {
.probe = ingenic_trng_probe,
- .remove = ingenic_trng_remove,
.driver = {
.name = "ingenic-trng",
.of_match_table = ingenic_trng_of_match,
diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c
index 06bc060534d8..440fe28bddc0 100644
--- a/drivers/char/hw_random/iproc-rng200.c
+++ b/drivers/char/hw_random/iproc-rng200.c
@@ -12,8 +12,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
@@ -182,6 +181,8 @@ static int iproc_rng200_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
}
+ dev_set_drvdata(dev, priv);
+
priv->rng.name = "iproc-rng200";
priv->rng.read = iproc_rng200_read;
priv->rng.init = iproc_rng200_init;
@@ -199,6 +200,28 @@ static int iproc_rng200_probe(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused iproc_rng200_suspend(struct device *dev)
+{
+ struct iproc_rng200_dev *priv = dev_get_drvdata(dev);
+
+ iproc_rng200_cleanup(&priv->rng);
+
+ return 0;
+}
+
+static int __maybe_unused iproc_rng200_resume(struct device *dev)
+{
+ struct iproc_rng200_dev *priv = dev_get_drvdata(dev);
+
+ iproc_rng200_init(&priv->rng);
+
+ return 0;
+}
+
+static const struct dev_pm_ops iproc_rng200_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(iproc_rng200_suspend, iproc_rng200_resume)
+};
+
static const struct of_device_id iproc_rng200_of_match[] = {
{ .compatible = "brcm,bcm2711-rng200", },
{ .compatible = "brcm,bcm7211-rng200", },
@@ -212,6 +235,7 @@ static struct platform_driver iproc_rng200_driver = {
.driver = {
.name = "iproc-rng200",
.of_match_table = iproc_rng200_of_match,
+ .pm = &iproc_rng200_pm_ops,
},
.probe = iproc_rng200_probe,
};
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index e8f9621e7954..8c6a40d6ce3d 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -13,8 +13,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-static struct clk *rng_clk;
-
static int nmk_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
void __iomem *base = (void __iomem *)rng->priv;
@@ -36,21 +34,17 @@ static struct hwrng nmk_rng = {
static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
{
+ struct clk *rng_clk;
void __iomem *base;
int ret;
- rng_clk = devm_clk_get(&dev->dev, NULL);
- if (IS_ERR(rng_clk)) {
- dev_err(&dev->dev, "could not get rng clock\n");
- ret = PTR_ERR(rng_clk);
- return ret;
- }
-
- clk_prepare_enable(rng_clk);
+ rng_clk = devm_clk_get_enabled(&dev->dev, NULL);
+ if (IS_ERR(rng_clk))
+ return dev_err_probe(&dev->dev, PTR_ERR(rng_clk), "could not get rng clock\n");
ret = amba_request_regions(dev, dev->dev.init_name);
if (ret)
- goto out_clk;
+ return ret;
ret = -ENOMEM;
base = devm_ioremap(&dev->dev, dev->res.start,
resource_size(&dev->res));
@@ -64,15 +58,12 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
out_release:
amba_release_regions(dev);
-out_clk:
- clk_disable_unprepare(rng_clk);
return ret;
}
static void nmk_rng_remove(struct amba_device *dev)
{
amba_release_regions(dev);
- clk_disable_unprepare(rng_clk);
}
static const struct amba_id nmk_rng_ids[] = {
diff --git a/drivers/char/hw_random/npcm-rng.c b/drivers/char/hw_random/npcm-rng.c
index 9903d0357e06..8a304b754217 100644
--- a/drivers/char/hw_random/npcm-rng.c
+++ b/drivers/char/hw_random/npcm-rng.c
@@ -8,12 +8,11 @@
#include <linux/init.h>
#include <linux/random.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
-#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
#define NPCM_RNGCS_REG 0x00 /* Control and status register */
#define NPCM_RNGD_REG 0x04 /* Data register */
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 00ff96703dd2..be03f76a2a80 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -26,8 +26,6 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
index f06e4f95114f..18dc46b1b58e 100644
--- a/drivers/char/hw_random/omap3-rom-rng.c
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -20,7 +20,6 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index 2498d4ef9fe2..6959d6edd44c 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -9,11 +9,10 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/io.h>
#define SDCRNG_CTL_REG 0x00
diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c
index 99c8bd0859a1..888e6f5cec1f 100644
--- a/drivers/char/hw_random/pic32-rng.c
+++ b/drivers/char/hw_random/pic32-rng.c
@@ -12,31 +12,22 @@
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define RNGCON 0x04
-#define TRNGEN BIT(8)
-#define PRNGEN BIT(9)
-#define PRNGCONT BIT(10)
-#define TRNGMOD BIT(11)
-#define SEEDLOAD BIT(12)
-#define RNGPOLY1 0x08
-#define RNGPOLY2 0x0C
-#define RNGNUMGEN1 0x10
-#define RNGNUMGEN2 0x14
+#define TRNGEN BIT(8)
+#define TRNGMOD BIT(11)
#define RNGSEED1 0x18
#define RNGSEED2 0x1C
#define RNGRCNT 0x20
-#define RCNT_MASK 0x7F
+#define RCNT_MASK 0x7F
struct pic32_rng {
void __iomem *base;
struct hwrng rng;
- struct clk *clk;
};
/*
@@ -46,6 +37,15 @@ struct pic32_rng {
*/
#define RNG_TIMEOUT 500
+static int pic32_rng_init(struct hwrng *rng)
+{
+ struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);
+
+ /* enable TRNG in enhanced mode */
+ writel(TRNGEN | TRNGMOD, priv->base + RNGCON);
+ return 0;
+}
+
static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,
bool wait)
{
@@ -67,11 +67,17 @@ static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max,
return -EIO;
}
+static void pic32_rng_cleanup(struct hwrng *rng)
+{
+ struct pic32_rng *priv = container_of(rng, struct pic32_rng, rng);
+
+ writel(0, priv->base + RNGCON);
+}
+
static int pic32_rng_probe(struct platform_device *pdev)
{
struct pic32_rng *priv;
- u32 v;
- int ret;
+ struct clk *clk;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -81,41 +87,16 @@ static int pic32_rng_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- priv->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(priv->clk))
- return PTR_ERR(priv->clk);
-
- ret = clk_prepare_enable(priv->clk);
- if (ret)
- return ret;
-
- /* enable TRNG in enhanced mode */
- v = TRNGEN | TRNGMOD;
- writel(v, priv->base + RNGCON);
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
priv->rng.name = pdev->name;
+ priv->rng.init = pic32_rng_init;
priv->rng.read = pic32_rng_read;
+ priv->rng.cleanup = pic32_rng_cleanup;
- ret = devm_hwrng_register(&pdev->dev, &priv->rng);
- if (ret)
- goto err_register;
-
- platform_set_drvdata(pdev, priv);
-
- return 0;
-
-err_register:
- clk_disable_unprepare(priv->clk);
- return ret;
-}
-
-static int pic32_rng_remove(struct platform_device *pdev)
-{
- struct pic32_rng *rng = platform_get_drvdata(pdev);
-
- writel(0, rng->base + RNGCON);
- clk_disable_unprepare(rng->clk);
- return 0;
+ return devm_hwrng_register(&pdev->dev, &priv->rng);
}
static const struct of_device_id pic32_rng_of_match[] __maybe_unused = {
@@ -126,10 +107,9 @@ MODULE_DEVICE_TABLE(of, pic32_rng_of_match);
static struct platform_driver pic32_rng_driver = {
.probe = pic32_rng_probe,
- .remove = pic32_rng_remove,
.driver = {
.name = "pic32-rng",
- .of_match_table = of_match_ptr(pic32_rng_of_match),
+ .of_match_table = pic32_rng_of_match,
},
};
diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c
index a6731cf0627a..efb6a9f9a11b 100644
--- a/drivers/char/hw_random/stm32-rng.c
+++ b/drivers/char/hw_random/stm32-rng.c
@@ -10,8 +10,9 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index 26f322d19a88..3db9d868efb1 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -113,16 +113,6 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (res->start % 4 != 0 || resource_size(res) < 4) {
- dev_err(&pdev->dev,
- "address must be at least four bytes wide and 32-bit aligned\n");
- return -EINVAL;
- }
-
/* Allocate memory for the device structure (and zero it) */
priv = devm_kzalloc(&pdev->dev,
sizeof(struct timeriomem_rng_private), GFP_KERNEL);
@@ -131,6 +121,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
+ priv->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(priv->io_base))
+ return PTR_ERR(priv->io_base);
+
+ if (res->start % 4 != 0 || resource_size(res) < 4) {
+ dev_err(&pdev->dev,
+ "address must be at least four bytes wide and 32-bit aligned\n");
+ return -EINVAL;
+ }
+
if (pdev->dev.of_node) {
int i;
@@ -158,11 +158,6 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
priv->rng_ops.name = dev_name(&pdev->dev);
priv->rng_ops.read = timeriomem_rng_read;
- priv->io_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->io_base)) {
- return PTR_ERR(priv->io_base);
- }
-
/* Assume random data is already available. */
priv->present = 1;
complete(&priv->completion);
diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c
index 7c8f3cb7c6af..99f4e86ac3e9 100644
--- a/drivers/char/hw_random/xgene-rng.c
+++ b/drivers/char/hw_random/xgene-rng.c
@@ -14,10 +14,10 @@
#include <linux/hw_random.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#include <linux/timer.h>
#define RNG_MAX_DATUM 4
diff --git a/drivers/char/hw_random/xiphera-trng.c b/drivers/char/hw_random/xiphera-trng.c
index 2a9fea72b2e0..2c586d1fe8a9 100644
--- a/drivers/char/hw_random/xiphera-trng.c
+++ b/drivers/char/hw_random/xiphera-trng.c
@@ -7,7 +7,6 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/hw_random.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 0fcc8615fb4f..1052b0f2d4cf 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -692,23 +692,23 @@ static const struct file_operations full_fops = {
static const struct memdev {
const char *name;
- umode_t mode;
const struct file_operations *fops;
fmode_t fmode;
+ umode_t mode;
} devlist[] = {
#ifdef CONFIG_DEVMEM
- [DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+ [DEVMEM_MINOR] = { "mem", &mem_fops, FMODE_UNSIGNED_OFFSET, 0 },
#endif
- [3] = { "null", 0666, &null_fops, FMODE_NOWAIT },
+ [3] = { "null", &null_fops, FMODE_NOWAIT, 0666 },
#ifdef CONFIG_DEVPORT
- [4] = { "port", 0, &port_fops, 0 },
+ [4] = { "port", &port_fops, 0, 0 },
#endif
- [5] = { "zero", 0666, &zero_fops, FMODE_NOWAIT },
- [7] = { "full", 0666, &full_fops, 0 },
- [8] = { "random", 0666, &random_fops, FMODE_NOWAIT },
- [9] = { "urandom", 0666, &urandom_fops, FMODE_NOWAIT },
+ [5] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 },
+ [7] = { "full", &full_fops, 0, 0666 },
+ [8] = { "random", &random_fops, FMODE_NOWAIT, 0666 },
+ [9] = { "urandom", &urandom_fops, FMODE_NOWAIT, 0666 },
#ifdef CONFIG_PRINTK
- [11] = { "kmsg", 0644, &kmsg_fops, 0 },
+ [11] = { "kmsg", &kmsg_fops, 0, 0644 },
#endif
};
diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c
index 8aa9057601d6..12ee42a31c71 100644
--- a/drivers/char/tpm/eventlog/tpm1.c
+++ b/drivers/char/tpm/eventlog/tpm1.c
@@ -251,7 +251,6 @@ static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
{
- int len = 0;
char *eventname;
struct tcpa_event *event = v;
unsigned char *event_entry =
@@ -273,7 +272,7 @@ static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
/* 3rd: event type identifier */
seq_printf(m, " %02x", do_endian_conversion(event->event_type));
- len += get_event_name(eventname, event, event_entry);
+ get_event_name(eventname, event, event_entry);
/* 4th: eventname <= max + \'0' delimiter */
seq_printf(m, " %s\n", eventname);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 7fa3d91042b2..077fdb73740c 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -27,7 +27,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/kernel.h>
-#include <linux/dmi.h>
#include "tpm.h"
#include "tpm_tis_core.h"
@@ -89,8 +88,8 @@ static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr)
tpm_tis_flush(iobase);
}
-static int interrupts;
-module_param(interrupts, int, 0444);
+static bool interrupts;
+module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
static bool itpm;
@@ -103,92 +102,6 @@ module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
#endif
-static int tpm_tis_disable_irq(const struct dmi_system_id *d)
-{
- if (interrupts == -1) {
- pr_notice("tpm_tis: %s detected: disabling interrupts.\n", d->ident);
- interrupts = 0;
- }
-
- return 0;
-}
-
-static const struct dmi_system_id tpm_tis_dmi_table[] = {
- {
- .callback = tpm_tis_disable_irq,
- .ident = "Framework Laptop (12th Gen Intel Core)",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (12th Gen Intel Core)"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "Framework Laptop (13th Gen Intel Core)",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (13th Gen Intel Core)"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "ThinkPad T490s",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T490s"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "ThinkStation P360 Tiny",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P360 Tiny"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "ThinkPad L490",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "ThinkPad L590",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "ThinkStation P620",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P620"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "TUXEDO InfinityBook S 15/17 Gen7",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TUXEDO InfinityBook S 15/17 Gen7"),
- },
- },
- {
- .callback = tpm_tis_disable_irq,
- .ident = "UPX-TGL",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
- DMI_MATCH(DMI_PRODUCT_NAME, "UPX-TGL01"),
- },
- },
- {}
-};
-
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int has_hid(struct acpi_device *dev, const char *hid)
{
@@ -312,8 +225,6 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
int irq = -1;
int rc;
- dmi_check_system(tpm_tis_dmi_table);
-
rc = check_acpi_tpm2(dev);
if (rc)
return rc;
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index b95963095729..1b350412d8a6 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -340,7 +340,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
return size;
}
-static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_try_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
@@ -348,11 +348,6 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
u32 expected;
int rc;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
-
size = recv_data(chip, buf, TPM_HEADER_SIZE);
/* read first 10 bytes, including tag, paramsize, and result */
if (size < TPM_HEADER_SIZE) {
@@ -385,7 +380,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out;
}
status = tpm_tis_status(chip);
- if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ if (status & TPM_STS_DATA_AVAIL) {
dev_err(&chip->dev, "Error left over data\n");
size = -EIO;
goto out;
@@ -399,10 +394,36 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
out:
- tpm_tis_ready(chip);
return size;
}
+static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+ unsigned int try;
+ int rc = 0;
+
+ if (count < TPM_HEADER_SIZE)
+ return -EIO;
+
+ for (try = 0; try < TPM_RETRY; try++) {
+ rc = tpm_tis_try_recv(chip, buf, count);
+
+ if (rc == -EIO)
+ /* Data transfer errors, indicated by EIO, can be
+ * recovered by rereading the response.
+ */
+ tpm_tis_write8(priv, TPM_STS(priv->locality),
+ TPM_STS_RESPONSE_RETRY);
+ else
+ break;
+ }
+
+ tpm_tis_ready(chip);
+
+ return rc;
+}
+
/*
* If interrupts are used (signaled by an irq set in the vendor structure)
* tpm.c can skip polling for the data to be available as the interrupt is
@@ -469,6 +490,12 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
goto out_err;
}
+ rc = tpm_tis_verify_crc(priv, len, buf);
+ if (rc < 0) {
+ dev_err(&chip->dev, "CRC mismatch for command.\n");
+ goto out_err;
+ }
+
return 0;
out_err:
@@ -512,15 +539,16 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
int rc;
u32 ordinal;
unsigned long dur;
+ unsigned int try;
- rc = tpm_tis_send_data(chip, buf, len);
- if (rc < 0)
- return rc;
-
- rc = tpm_tis_verify_crc(priv, len, buf);
- if (rc < 0) {
- dev_err(&chip->dev, "CRC mismatch for command.\n");
- return rc;
+ for (try = 0; try < TPM_RETRY; try++) {
+ rc = tpm_tis_send_data(chip, buf, len);
+ if (rc >= 0)
+ /* Data transfer done successfully */
+ break;
+ else if (rc != -EIO)
+ /* Data transfer failed, not recoverable */
+ return rc;
}
/* go and do it */
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index b1a169d7d1ca..13e99cf65efe 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
+ TPM_STS_RESPONSE_RETRY = 0x02,
TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
};
diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c
index 9bfaba092a06..a62f5c7f38d3 100644
--- a/drivers/char/tpm/tpm_tis_spi_main.c
+++ b/drivers/char/tpm/tpm_tis_spi_main.c
@@ -71,8 +71,74 @@ static int tpm_tis_spi_flow_control(struct tpm_tis_spi_phy *phy,
return 0;
}
-int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
- u8 *in, const u8 *out)
+/*
+ * Half duplex controller with support for TPM wait state detection like
+ * Tegra QSPI need CMD, ADDR & DATA sent in single message to manage HW flow
+ * control. Each phase sent in different transfer for controller to idenity
+ * phase.
+ */
+static int tpm_tis_spi_transfer_half(struct tpm_tis_data *data, u32 addr,
+ u16 len, u8 *in, const u8 *out)
+{
+ struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
+ struct spi_transfer spi_xfer[3];
+ struct spi_message m;
+ u8 transfer_len;
+ int ret;
+
+ while (len) {
+ transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
+
+ spi_message_init(&m);
+ phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
+ phy->iobuf[1] = 0xd4;
+ phy->iobuf[2] = addr >> 8;
+ phy->iobuf[3] = addr;
+
+ memset(&spi_xfer, 0, sizeof(spi_xfer));
+
+ spi_xfer[0].tx_buf = phy->iobuf;
+ spi_xfer[0].len = 1;
+ spi_message_add_tail(&spi_xfer[0], &m);
+
+ spi_xfer[1].tx_buf = phy->iobuf + 1;
+ spi_xfer[1].len = 3;
+ spi_message_add_tail(&spi_xfer[1], &m);
+
+ if (out) {
+ spi_xfer[2].tx_buf = &phy->iobuf[4];
+ spi_xfer[2].rx_buf = NULL;
+ memcpy(&phy->iobuf[4], out, transfer_len);
+ out += transfer_len;
+ }
+
+ if (in) {
+ spi_xfer[2].tx_buf = NULL;
+ spi_xfer[2].rx_buf = &phy->iobuf[4];
+ }
+
+ spi_xfer[2].len = transfer_len;
+ spi_message_add_tail(&spi_xfer[2], &m);
+
+ reinit_completion(&phy->ready);
+
+ ret = spi_sync(phy->spi_device, &m);
+ if (ret < 0)
+ return ret;
+
+ if (in) {
+ memcpy(in, &phy->iobuf[4], transfer_len);
+ in += transfer_len;
+ }
+
+ len -= transfer_len;
+ }
+
+ return ret;
+}
+
+static int tpm_tis_spi_transfer_full(struct tpm_tis_data *data, u32 addr,
+ u16 len, u8 *in, const u8 *out)
{
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
int ret = 0;
@@ -148,6 +214,24 @@ exit:
return ret;
}
+int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
+ u8 *in, const u8 *out)
+{
+ struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
+ struct spi_controller *ctlr = phy->spi_device->controller;
+
+ /*
+ * TPM flow control over SPI requires full duplex support.
+ * Send entire message to a half duplex controller to handle
+ * wait polling in controller.
+ * Set TPM HW flow control flag..
+ */
+ if (ctlr->flags & SPI_CONTROLLER_HALF_DUPLEX)
+ return tpm_tis_spi_transfer_half(data, addr, len, in, out);
+ else
+ return tpm_tis_spi_transfer_full(data, addr, len, in, out);
+}
+
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
u16 len, u8 *result, enum tpm_tis_io_mode io_mode)
{
@@ -189,6 +273,9 @@ static int tpm_tis_spi_probe(struct spi_device *dev)
phy->flow_control = tpm_tis_spi_flow_control;
+ if (dev->controller->flags & SPI_CONTROLLER_HALF_DUPLEX)
+ dev->mode |= SPI_TPM_HW_FLOW;
+
/* If the SPI device has an IRQ then use that */
if (dev->irq > 0)
irq = dev->irq;
diff --git a/drivers/char/tpm/tpm_tis_synquacer.c b/drivers/char/tpm/tpm_tis_synquacer.c
index 49278746b0e2..f7d5e76b505e 100644
--- a/drivers/char/tpm/tpm_tis_synquacer.c
+++ b/drivers/char/tpm/tpm_tis_synquacer.c
@@ -162,23 +162,7 @@ static struct platform_driver tis_synquacer_drv = {
},
};
-static int __init tpm_tis_synquacer_module_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&tis_synquacer_drv);
- if (rc)
- return rc;
-
- return 0;
-}
-
-static void __exit tpm_tis_synquacer_module_exit(void)
-{
- platform_driver_unregister(&tis_synquacer_drv);
-}
+module_platform_driver(tis_synquacer_drv);
-module_init(tpm_tis_synquacer_module_init);
-module_exit(tpm_tis_synquacer_module_exit);
MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index 4fb4fd4b06bd..737aa70e2cb3 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -205,18 +205,19 @@ EXPORT_SYMBOL(devm_clk_put);
struct clk *devm_get_clk_from_child(struct device *dev,
struct device_node *np, const char *con_id)
{
- struct clk **ptr, *clk;
+ struct devm_clk_state *state;
+ struct clk *clk;
- ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
+ state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+ if (!state)
return ERR_PTR(-ENOMEM);
clk = of_clk_get_by_name(np, con_id);
if (!IS_ERR(clk)) {
- *ptr = clk;
- devres_add(dev, ptr);
+ state->clk = clk;
+ devres_add(dev, state);
} else {
- devres_free(ptr);
+ devres_free(state);
}
return clk;
diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c
index d33f74119488..935d9a2d8c2b 100644
--- a/drivers/clk/keystone/syscon-clk.c
+++ b/drivers/clk/keystone/syscon-clk.c
@@ -151,8 +151,10 @@ static int ti_syscon_gate_clk_probe(struct platform_device *pdev)
data[i].name);
}
- return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
- hw_data);
+ if (num_clks == 1)
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ hw_data->hws[0]);
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
}
#define TI_SYSCON_CLK_GATE(_name, _offset, _bit_idx) \
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index ccac1c453080..05d562e9c8b1 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -48,8 +48,47 @@ static DEFINE_PER_CPU(struct local_event, local_event) = {
.lock = INIT_LOCAL_LOCK(lock),
};
+static int cn_filter(struct sock *dsk, struct sk_buff *skb, void *data)
+{
+ __u32 what, exit_code, *ptr;
+ enum proc_cn_mcast_op mc_op;
+ uintptr_t val;
+
+ if (!dsk || !data)
+ return 0;
+
+ ptr = (__u32 *)data;
+ what = *ptr++;
+ exit_code = *ptr;
+ val = ((struct proc_input *)(dsk->sk_user_data))->event_type;
+ mc_op = ((struct proc_input *)(dsk->sk_user_data))->mcast_op;
+
+ if (mc_op == PROC_CN_MCAST_IGNORE)
+ return 1;
+
+ if ((__u32)val == PROC_EVENT_ALL)
+ return 0;
+
+ /*
+ * Drop packet if we have to report only non-zero exit status
+ * (PROC_EVENT_NONZERO_EXIT) and exit status is 0
+ */
+ if (((__u32)val & PROC_EVENT_NONZERO_EXIT) &&
+ (what == PROC_EVENT_EXIT)) {
+ if (exit_code)
+ return 0;
+ }
+
+ if ((__u32)val & what)
+ return 0;
+
+ return 1;
+}
+
static inline void send_msg(struct cn_msg *msg)
{
+ __u32 filter_data[2];
+
local_lock(&local_event.lock);
msg->seq = __this_cpu_inc_return(local_event.count) - 1;
@@ -61,7 +100,16 @@ static inline void send_msg(struct cn_msg *msg)
*
* If cn_netlink_send() fails, the data is not sent.
*/
- cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT);
+ filter_data[0] = ((struct proc_event *)msg->data)->what;
+ if (filter_data[0] == PROC_EVENT_EXIT) {
+ filter_data[1] =
+ ((struct proc_event *)msg->data)->event_data.exit.exit_code;
+ } else {
+ filter_data[1] = 0;
+ }
+
+ cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT,
+ cn_filter, (void *)filter_data);
local_unlock(&local_event.lock);
}
@@ -341,16 +389,17 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
/**
* cn_proc_mcast_ctl
- * @data: message sent from userspace via the connector
+ * @msg: message sent from userspace via the connector
+ * @nsp: NETLINK_CB of the client's socket buffer
*/
static void cn_proc_mcast_ctl(struct cn_msg *msg,
struct netlink_skb_parms *nsp)
{
- enum proc_cn_mcast_op *mc_op = NULL;
- int err = 0;
-
- if (msg->len != sizeof(*mc_op))
- return;
+ enum proc_cn_mcast_op mc_op = 0, prev_mc_op = 0;
+ struct proc_input *pinput = NULL;
+ enum proc_cn_event ev_type = 0;
+ int err = 0, initial = 0;
+ struct sock *sk = NULL;
/*
* Events are reported with respect to the initial pid
@@ -361,19 +410,51 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
!task_is_in_init_pid_ns(current))
return;
- /* Can only change if privileged. */
- if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
- err = EPERM;
- goto out;
+ if (msg->len == sizeof(*pinput)) {
+ pinput = (struct proc_input *)msg->data;
+ mc_op = pinput->mcast_op;
+ ev_type = pinput->event_type;
+ } else if (msg->len == sizeof(mc_op)) {
+ mc_op = *((enum proc_cn_mcast_op *)msg->data);
+ ev_type = PROC_EVENT_ALL;
+ } else {
+ return;
+ }
+
+ ev_type = valid_event((enum proc_cn_event)ev_type);
+
+ if (ev_type == PROC_EVENT_NONE)
+ ev_type = PROC_EVENT_ALL;
+
+ if (nsp->sk) {
+ sk = nsp->sk;
+ if (sk->sk_user_data == NULL) {
+ sk->sk_user_data = kzalloc(sizeof(struct proc_input),
+ GFP_KERNEL);
+ if (sk->sk_user_data == NULL) {
+ err = ENOMEM;
+ goto out;
+ }
+ initial = 1;
+ } else {
+ prev_mc_op =
+ ((struct proc_input *)(sk->sk_user_data))->mcast_op;
+ }
+ ((struct proc_input *)(sk->sk_user_data))->event_type =
+ ev_type;
+ ((struct proc_input *)(sk->sk_user_data))->mcast_op = mc_op;
}
- mc_op = (enum proc_cn_mcast_op *)msg->data;
- switch (*mc_op) {
+ switch (mc_op) {
case PROC_CN_MCAST_LISTEN:
- atomic_inc(&proc_event_num_listeners);
+ if (initial || (prev_mc_op != PROC_CN_MCAST_LISTEN))
+ atomic_inc(&proc_event_num_listeners);
break;
case PROC_CN_MCAST_IGNORE:
- atomic_dec(&proc_event_num_listeners);
+ if (!initial && (prev_mc_op != PROC_CN_MCAST_IGNORE))
+ atomic_dec(&proc_event_num_listeners);
+ ((struct proc_input *)(sk->sk_user_data))->event_type =
+ PROC_EVENT_NONE;
break;
default:
err = EINVAL;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 48ec7ce6ecac..7f7b94f616a6 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -59,7 +59,9 @@ static int cn_already_initialized;
* both, or if both are zero then the group is looked up and sent there.
*/
int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group,
- gfp_t gfp_mask)
+ gfp_t gfp_mask,
+ int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
+ void *filter_data)
{
struct cn_callback_entry *__cbq;
unsigned int size;
@@ -110,8 +112,9 @@ int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group,
NETLINK_CB(skb).dst_group = group;
if (group)
- return netlink_broadcast(dev->nls, skb, portid, group,
- gfp_mask);
+ return netlink_broadcast_filtered(dev->nls, skb, portid, group,
+ gfp_mask, filter,
+ (void *)filter_data);
return netlink_unicast(dev->nls, skb, portid,
!gfpflags_allow_blocking(gfp_mask));
}
@@ -121,7 +124,8 @@ EXPORT_SYMBOL_GPL(cn_netlink_send_mult);
int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group,
gfp_t gfp_mask)
{
- return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask);
+ return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask,
+ NULL, NULL);
}
EXPORT_SYMBOL_GPL(cn_netlink_send);
@@ -163,6 +167,31 @@ static int cn_call_callback(struct sk_buff *skb)
}
/*
+ * Allow non-root access for NETLINK_CONNECTOR family having CN_IDX_PROC
+ * multicast group.
+ */
+static int cn_bind(struct net *net, int group)
+{
+ unsigned long groups = (unsigned long) group;
+
+ if (ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return 0;
+
+ if (test_bit(CN_IDX_PROC - 1, &groups))
+ return 0;
+
+ return -EPERM;
+}
+
+static void cn_release(struct sock *sk, unsigned long *groups)
+{
+ if (groups && test_bit(CN_IDX_PROC - 1, groups)) {
+ kfree(sk->sk_user_data);
+ sk->sk_user_data = NULL;
+ }
+}
+
+/*
* Main netlink receiving function.
*
* It checks skb, netlink header and msg sizes, and calls callback helper.
@@ -249,6 +278,9 @@ static int cn_init(void)
struct netlink_kernel_cfg cfg = {
.groups = CN_NETLINK_USERS + 0xf,
.input = cn_rx_skb,
+ .flags = NL_CFG_F_NONROOT_RECV,
+ .bind = cn_bind,
+ .release = cn_release,
};
dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg);
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index b2f05d27167e..37f1cdf46d29 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -1011,22 +1011,20 @@ static int __init acpi_cpufreq_probe(struct platform_device *pdev)
return ret;
}
-static int acpi_cpufreq_remove(struct platform_device *pdev)
+static void acpi_cpufreq_remove(struct platform_device *pdev)
{
pr_debug("%s\n", __func__);
cpufreq_unregister_driver(&acpi_cpufreq_driver);
free_acpi_perf_data();
-
- return 0;
}
static struct platform_driver acpi_cpufreq_platdrv = {
.driver = {
.name = "acpi-cpufreq",
},
- .remove = acpi_cpufreq_remove,
+ .remove_new = acpi_cpufreq_remove,
};
static int __init acpi_cpufreq_init(void)
diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
index 7f3fe2048981..f04ae67dda37 100644
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -64,27 +64,9 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
static bool get_shared_mem(void)
{
bool result = false;
- char path[] = "/sys/module/amd_pstate/parameters/shared_mem";
- char buf[5] = {0};
- struct file *filp = NULL;
- loff_t pos = 0;
- ssize_t ret;
-
- if (!boot_cpu_has(X86_FEATURE_CPPC)) {
- filp = filp_open(path, O_RDONLY, 0);
- if (IS_ERR(filp))
- pr_err("%s unable to open %s file!\n", __func__, path);
- else {
- ret = kernel_read(filp, &buf, sizeof(buf), &pos);
- if (ret < 0)
- pr_err("%s read %s file fail ret=%ld!\n",
- __func__, path, (long)ret);
- filp_close(filp, NULL);
- }
- if ('Y' == *buf)
- result = true;
- }
+ if (!boot_cpu_has(X86_FEATURE_CPPC))
+ result = true;
return result;
}
@@ -145,8 +127,6 @@ static void amd_pstate_ut_check_perf(u32 index)
struct cpufreq_policy *policy = NULL;
struct amd_cpudata *cpudata = NULL;
- highest_perf = amd_get_highest_perf();
-
for_each_possible_cpu(cpu) {
policy = cpufreq_cpu_get(cpu);
if (!policy)
@@ -158,9 +138,10 @@ static void amd_pstate_ut_check_perf(u32 index)
if (ret) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret);
- return;
+ goto skip_test;
}
+ highest_perf = cppc_perf.highest_perf;
nominal_perf = cppc_perf.nominal_perf;
lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf;
lowest_perf = cppc_perf.lowest_perf;
@@ -169,9 +150,10 @@ static void amd_pstate_ut_check_perf(u32 index)
if (ret) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret);
- return;
+ goto skip_test;
}
+ highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
nominal_perf = AMD_CPPC_NOMINAL_PERF(cap1);
lowest_nonlinear_perf = AMD_CPPC_LOWNONLIN_PERF(cap1);
lowest_perf = AMD_CPPC_LOWEST_PERF(cap1);
@@ -187,7 +169,7 @@ static void amd_pstate_ut_check_perf(u32 index)
nominal_perf, cpudata->nominal_perf,
lowest_nonlinear_perf, cpudata->lowest_nonlinear_perf,
lowest_perf, cpudata->lowest_perf);
- return;
+ goto skip_test;
}
if (!((highest_perf >= nominal_perf) &&
@@ -198,11 +180,15 @@ static void amd_pstate_ut_check_perf(u32 index)
pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n",
__func__, cpu, highest_perf, nominal_perf,
lowest_nonlinear_perf, lowest_perf);
- return;
+ goto skip_test;
}
+ cpufreq_cpu_put(policy);
}
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
+ return;
+skip_test:
+ cpufreq_cpu_put(policy);
}
/*
@@ -230,14 +216,14 @@ static void amd_pstate_ut_check_freq(u32 index)
pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n",
__func__, cpu, cpudata->max_freq, cpudata->nominal_freq,
cpudata->lowest_nonlinear_freq, cpudata->min_freq);
- return;
+ goto skip_test;
}
if (cpudata->min_freq != policy->min) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d cpudata_min_freq=%d policy_min=%d, they should be equal!\n",
__func__, cpu, cpudata->min_freq, policy->min);
- return;
+ goto skip_test;
}
if (cpudata->boost_supported) {
@@ -249,16 +235,20 @@ static void amd_pstate_ut_check_freq(u32 index)
pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
__func__, cpu, policy->max, cpudata->max_freq,
cpudata->nominal_freq);
- return;
+ goto skip_test;
}
} else {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d must support boost!\n", __func__, cpu);
- return;
+ goto skip_test;
}
+ cpufreq_cpu_put(policy);
}
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
+ return;
+skip_test:
+ cpufreq_cpu_put(policy);
}
static int __init amd_pstate_ut_init(void)
diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c
index b74289a95a17..bea41ccabf1f 100644
--- a/drivers/cpufreq/armada-37xx-cpufreq.c
+++ b/drivers/cpufreq/armada-37xx-cpufreq.c
@@ -14,10 +14,8 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regmap.h>
diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c
index ffea6402189d..35fb3a559ea9 100644
--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c
+++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c
@@ -434,7 +434,11 @@ brcm_avs_get_freq_table(struct device *dev, struct private_data *priv)
if (ret)
return ERR_PTR(ret);
- table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table),
+ /*
+ * We allocate space for the 5 different P-STATES AVS,
+ * plus extra space for a terminating element.
+ */
+ table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1 + 1, sizeof(*table),
GFP_KERNEL);
if (!table)
return ERR_PTR(-ENOMEM);
@@ -749,13 +753,11 @@ static int brcm_avs_cpufreq_probe(struct platform_device *pdev)
return ret;
}
-static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
+static void brcm_avs_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&brcm_avs_driver);
brcm_avs_prepare_uninit(pdev);
-
- return 0;
}
static const struct of_device_id brcm_avs_cpufreq_match[] = {
@@ -770,7 +772,7 @@ static struct platform_driver brcm_avs_cpufreq_platdrv = {
.of_match_table = brcm_avs_cpufreq_match,
},
.probe = brcm_avs_cpufreq_probe,
- .remove = brcm_avs_cpufreq_remove,
+ .remove_new = brcm_avs_cpufreq_remove,
};
module_platform_driver(brcm_avs_cpufreq_platdrv);
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 022e3555407c..fe08ca419b3d 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -249,15 +249,19 @@ static void __init cppc_freq_invariance_init(void)
return;
kworker_fie = kthread_create_worker(0, "cppc_fie");
- if (IS_ERR(kworker_fie))
+ if (IS_ERR(kworker_fie)) {
+ pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
+ PTR_ERR(kworker_fie));
+ fie_disabled = FIE_DISABLED;
return;
+ }
ret = sched_setattr_nocheck(kworker_fie->task, &attr);
if (ret) {
pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__,
ret);
kthread_destroy_worker(kworker_fie);
- return;
+ fie_disabled = FIE_DISABLED;
}
}
@@ -267,7 +271,6 @@ static void cppc_freq_invariance_exit(void)
return;
kthread_destroy_worker(kworker_fie);
- kworker_fie = NULL;
}
#else
@@ -849,13 +852,13 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t0);
if (ret)
- return ret;
+ return 0;
udelay(2); /* 2usec delay between sampling */
ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t1);
if (ret)
- return ret;
+ return 0;
delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0,
&fb_ctrs_t1);
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index e2b20080de3a..fb2875ce1fdd 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -143,14 +143,19 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "qcom,apq8096", },
{ .compatible = "qcom,msm8996", },
+ { .compatible = "qcom,msm8998", },
+ { .compatible = "qcom,qcm2290", },
{ .compatible = "qcom,qcs404", },
+ { .compatible = "qcom,qdu1000", },
{ .compatible = "qcom,sa8155p" },
{ .compatible = "qcom,sa8540p" },
+ { .compatible = "qcom,sa8775p" },
{ .compatible = "qcom,sc7180", },
{ .compatible = "qcom,sc7280", },
{ .compatible = "qcom,sc8180x", },
{ .compatible = "qcom,sc8280xp", },
{ .compatible = "qcom,sdm845", },
+ { .compatible = "qcom,sdx75", },
{ .compatible = "qcom,sm6115", },
{ .compatible = "qcom,sm6350", },
{ .compatible = "qcom,sm6375", },
@@ -158,6 +163,8 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "qcom,sm8150", },
{ .compatible = "qcom,sm8250", },
{ .compatible = "qcom,sm8350", },
+ { .compatible = "qcom,sm8450", },
+ { .compatible = "qcom,sm8550", },
{ .compatible = "st,stih407", },
{ .compatible = "st,stih410", },
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 4aec4b2a5225..8bd6e5e8f121 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -349,11 +349,10 @@ err:
return ret;
}
-static int dt_cpufreq_remove(struct platform_device *pdev)
+static void dt_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&dt_cpufreq_driver);
dt_cpufreq_release();
- return 0;
}
static struct platform_driver dt_cpufreq_platdrv = {
@@ -361,7 +360,7 @@ static struct platform_driver dt_cpufreq_platdrv = {
.name = "cpufreq-dt",
},
.probe = dt_cpufreq_probe,
- .remove = dt_cpufreq_remove,
+ .remove_new = dt_cpufreq_remove,
};
module_platform_driver(dt_cpufreq_platdrv);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 50bbc969ffe5..a757f90aa9d6 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1234,16 +1234,16 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
ret = freq_qos_add_notifier(&policy->constraints, FREQ_QOS_MIN,
&policy->nb_min);
if (ret) {
- dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
- ret, cpumask_pr_args(policy->cpus));
+ dev_err(dev, "Failed to register MIN QoS notifier: %d (CPU%u)\n",
+ ret, cpu);
goto err_kobj_remove;
}
ret = freq_qos_add_notifier(&policy->constraints, FREQ_QOS_MAX,
&policy->nb_max);
if (ret) {
- dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
- ret, cpumask_pr_args(policy->cpus));
+ dev_err(dev, "Failed to register MAX QoS notifier: %d (CPU%u)\n",
+ ret, cpu);
goto err_min_qos_notifier;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 55c7ffd37d1c..a33df3c66c88 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -243,7 +243,8 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
/* Find valid-unique entries */
cpufreq_for_each_valid_entry(pos, policy->freq_table)
- if (freq_table_get_index(stats, pos->frequency) == -1)
+ if (policy->freq_table_sorted != CPUFREQ_TABLE_UNSORTED ||
+ freq_table_get_index(stats, pos->frequency) == -1)
stats->freq_table[i++] = pos->frequency;
stats->state_num = i;
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index ebb3a8102681..7d2754411d8c 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -131,7 +131,7 @@ static int __init davinci_cpufreq_probe(struct platform_device *pdev)
return cpufreq_register_driver(&davinci_driver);
}
-static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
+static void __exit davinci_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&davinci_driver);
@@ -139,15 +139,13 @@ static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
if (cpufreq.asyncclk)
clk_put(cpufreq.asyncclk);
-
- return 0;
}
static struct platform_driver davinci_cpufreq_driver = {
.driver = {
.name = "cpufreq-davinci",
},
- .remove = __exit_p(davinci_cpufreq_remove),
+ .remove_new = __exit_p(davinci_cpufreq_remove),
};
int __init davinci_cpufreq_init(void)
diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c
index 535867a7dfdd..577bb9e2f112 100644
--- a/drivers/cpufreq/imx-cpufreq-dt.c
+++ b/drivers/cpufreq/imx-cpufreq-dt.c
@@ -172,20 +172,18 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
return 0;
}
-static int imx_cpufreq_dt_remove(struct platform_device *pdev)
+static void imx_cpufreq_dt_remove(struct platform_device *pdev)
{
platform_device_unregister(cpufreq_dt_pdev);
if (!of_machine_is_compatible("fsl,imx7ulp"))
dev_pm_opp_put_supported_hw(cpufreq_opp_token);
else
clk_bulk_put(ARRAY_SIZE(imx7ulp_clks), imx7ulp_clks);
-
- return 0;
}
static struct platform_driver imx_cpufreq_dt_driver = {
.probe = imx_cpufreq_dt_probe,
- .remove = imx_cpufreq_dt_remove,
+ .remove_new = imx_cpufreq_dt_remove,
.driver = {
.name = "imx-cpufreq-dt",
},
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index 9fb1501033bb..494d044b9e72 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -519,7 +519,7 @@ put_node:
return ret;
}
-static int imx6q_cpufreq_remove(struct platform_device *pdev)
+static void imx6q_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
@@ -530,8 +530,6 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
regulator_put(soc_reg);
clk_bulk_put(num_clks, clks);
-
- return 0;
}
static struct platform_driver imx6q_cpufreq_platdrv = {
@@ -539,7 +537,7 @@ static struct platform_driver imx6q_cpufreq_platdrv = {
.name = "imx6q-cpufreq",
},
.probe = imx6q_cpufreq_probe,
- .remove = imx6q_cpufreq_remove,
+ .remove_new = imx6q_cpufreq_remove,
};
module_platform_driver(imx6q_cpufreq_platdrv);
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 8ca2bce4341a..dc50c9fb488d 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2609,6 +2609,11 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
intel_pstate_clear_update_util_hook(policy->cpu);
intel_pstate_hwp_set(policy->cpu);
}
+ /*
+ * policy->cur is never updated with the intel_pstate driver, but it
+ * is used as a stale frequency value. So, keep it within limits.
+ */
+ policy->cur = policy->min;
mutex_unlock(&intel_pstate_limits_lock);
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index 95588101efbd..fd20b986d1f2 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -178,20 +178,18 @@ out_node:
return err;
}
-static int kirkwood_cpufreq_remove(struct platform_device *pdev)
+static void kirkwood_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&kirkwood_cpufreq_driver);
clk_disable_unprepare(priv.powersave_clk);
clk_disable_unprepare(priv.ddr_clk);
clk_disable_unprepare(priv.cpu_clk);
-
- return 0;
}
static struct platform_driver kirkwood_cpufreq_platform_driver = {
.probe = kirkwood_cpufreq_probe,
- .remove = kirkwood_cpufreq_remove,
+ .remove_new = kirkwood_cpufreq_remove,
.driver = {
.name = "kirkwood-cpufreq",
},
diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c
index b22f5cc8a463..d46afb3c0092 100644
--- a/drivers/cpufreq/mediatek-cpufreq-hw.c
+++ b/drivers/cpufreq/mediatek-cpufreq-hw.c
@@ -10,8 +10,9 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#define LUT_MAX_ENTRIES 32U
@@ -315,11 +316,9 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
return ret;
}
-static int mtk_cpufreq_hw_driver_remove(struct platform_device *pdev)
+static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&cpufreq_mtk_hw_driver);
-
- return 0;
}
static const struct of_device_id mtk_cpufreq_hw_match[] = {
@@ -330,7 +329,7 @@ MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match);
static struct platform_driver mtk_cpufreq_hw_driver = {
.probe = mtk_cpufreq_hw_driver_probe,
- .remove = mtk_cpufreq_hw_driver_remove,
+ .remove_new = mtk_cpufreq_hw_driver_remove,
.driver = {
.name = "mtk-cpufreq-hw",
.of_match_table = mtk_cpufreq_hw_match,
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index fef68cb2b38f..a0a61919bc4c 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -313,8 +313,6 @@ out:
return ret;
}
-#define DYNAMIC_POWER "dynamic-power-coefficient"
-
static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 81649a1969b6..895690856665 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -182,11 +182,9 @@ static int omap_cpufreq_probe(struct platform_device *pdev)
return cpufreq_register_driver(&omap_driver);
}
-static int omap_cpufreq_remove(struct platform_device *pdev)
+static void omap_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&omap_driver);
-
- return 0;
}
static struct platform_driver omap_cpufreq_platdrv = {
@@ -194,7 +192,7 @@ static struct platform_driver omap_cpufreq_platdrv = {
.name = "omap-cpufreq",
},
.probe = omap_cpufreq_probe,
- .remove = omap_cpufreq_remove,
+ .remove_new = omap_cpufreq_remove,
};
module_platform_driver(omap_cpufreq_platdrv);
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 73efbcf5513b..84fe37def0f1 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -608,22 +608,20 @@ static int __init pcc_cpufreq_probe(struct platform_device *pdev)
return ret;
}
-static int pcc_cpufreq_remove(struct platform_device *pdev)
+static void pcc_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&pcc_cpufreq_driver);
pcc_clear_mapping();
free_percpu(pcc_cpu_info);
-
- return 0;
}
static struct platform_driver pcc_cpufreq_platdrv = {
.driver = {
.name = "pcc-cpufreq",
},
- .remove = pcc_cpufreq_remove,
+ .remove_new = pcc_cpufreq_remove,
};
static int __init pcc_cpufreq_init(void)
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index d289036beff2..b10f7a1b77f1 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1101,7 +1101,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
kfree(data->powernow_table);
kfree(data);
- for_each_cpu(cpu, pol->cpus)
+ /* pol->cpus will be empty here, use related_cpus instead. */
+ for_each_cpu(cpu, pol->related_cpus)
per_cpu(powernow_data, cpu) = NULL;
return 0;
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index e3313ce63b38..88afc49941b7 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -9,7 +9,7 @@
#include <linux/cpufreq.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <asm/machdep.h>
#include <asm/cell-regs.h>
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
index 4fba3637b115..6f0c32592416 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
@@ -11,7 +11,6 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/init.h>
-#include <linux/of_platform.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index f2830371d25f..70b0f21968a0 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -28,7 +28,7 @@
#define GT_IRQ_STATUS BIT(2)
-#define MAX_FREQ_DOMAINS 3
+#define MAX_FREQ_DOMAINS 4
struct qcom_cpufreq_soc_data {
u32 reg_enable;
@@ -730,16 +730,14 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
return ret;
}
-static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
+static void qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
-
- return 0;
}
static struct platform_driver qcom_cpufreq_hw_driver = {
.probe = qcom_cpufreq_hw_driver_probe,
- .remove = qcom_cpufreq_hw_driver_remove,
+ .remove_new = qcom_cpufreq_hw_driver_remove,
.driver = {
.name = "qcom-cpufreq-hw",
.of_match_table = qcom_cpufreq_hw_match,
diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c
index a88b6fe5db50..84d7033e5efe 100644
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
@@ -334,7 +333,7 @@ free_drv:
return ret;
}
-static int qcom_cpufreq_remove(struct platform_device *pdev)
+static void qcom_cpufreq_remove(struct platform_device *pdev)
{
struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev);
unsigned int cpu;
@@ -346,13 +345,11 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
kfree(drv->opp_tokens);
kfree(drv);
-
- return 0;
}
static struct platform_driver qcom_cpufreq_driver = {
.probe = qcom_cpufreq_probe,
- .remove = qcom_cpufreq_remove,
+ .remove_new = qcom_cpufreq_remove,
.driver = {
.name = "qcom-cpufreq-nvmem",
},
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 573b417e1483..0aecaecbb0e6 100644
--- a/drivers/cpufreq/qoriq-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -288,11 +288,9 @@ static int qoriq_cpufreq_probe(struct platform_device *pdev)
return 0;
}
-static int qoriq_cpufreq_remove(struct platform_device *pdev)
+static void qoriq_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&qoriq_cpufreq_driver);
-
- return 0;
}
static struct platform_driver qoriq_cpufreq_platform_driver = {
@@ -300,7 +298,7 @@ static struct platform_driver qoriq_cpufreq_platform_driver = {
.name = "qoriq-cpufreq",
},
.probe = qoriq_cpufreq_probe,
- .remove = qoriq_cpufreq_remove,
+ .remove_new = qoriq_cpufreq_remove,
};
module_platform_driver(qoriq_cpufreq_platform_driver);
diff --git a/drivers/cpufreq/raspberrypi-cpufreq.c b/drivers/cpufreq/raspberrypi-cpufreq.c
index 2bc7d9734272..e0705cc9a57d 100644
--- a/drivers/cpufreq/raspberrypi-cpufreq.c
+++ b/drivers/cpufreq/raspberrypi-cpufreq.c
@@ -65,7 +65,7 @@ remove_opp:
return ret;
}
-static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
+static void raspberrypi_cpufreq_remove(struct platform_device *pdev)
{
struct device *cpu_dev;
@@ -74,8 +74,6 @@ static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
dev_pm_opp_remove_all_dynamic(cpu_dev);
platform_device_unregister(cpufreq_dt);
-
- return 0;
}
/*
@@ -87,7 +85,7 @@ static struct platform_driver raspberrypi_cpufreq_driver = {
.name = "raspberrypi-cpufreq",
},
.probe = raspberrypi_cpufreq_probe,
- .remove = raspberrypi_cpufreq_remove,
+ .remove_new = raspberrypi_cpufreq_remove,
};
module_platform_driver(raspberrypi_cpufreq_driver);
diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c
index fd2c16821d54..d33be56983ed 100644
--- a/drivers/cpufreq/scpi-cpufreq.c
+++ b/drivers/cpufreq/scpi-cpufreq.c
@@ -14,7 +14,7 @@
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>
@@ -208,11 +208,10 @@ static int scpi_cpufreq_probe(struct platform_device *pdev)
return ret;
}
-static int scpi_cpufreq_remove(struct platform_device *pdev)
+static void scpi_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&scpi_cpufreq_driver);
scpi_ops = NULL;
- return 0;
}
static struct platform_driver scpi_cpufreq_platdrv = {
@@ -220,7 +219,7 @@ static struct platform_driver scpi_cpufreq_platdrv = {
.name = "scpi-cpufreq",
},
.probe = scpi_cpufreq_probe,
- .remove = scpi_cpufreq_remove,
+ .remove_new = scpi_cpufreq_remove,
};
module_platform_driver(scpi_cpufreq_platdrv);
diff --git a/drivers/cpufreq/sti-cpufreq.c b/drivers/cpufreq/sti-cpufreq.c
index 1a63aeea8711..9c542e723a15 100644
--- a/drivers/cpufreq/sti-cpufreq.c
+++ b/drivers/cpufreq/sti-cpufreq.c
@@ -13,7 +13,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regmap.h>
diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
index 4321d7bbe769..32a9c88f8ff6 100644
--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
@@ -137,7 +137,7 @@ free_opp:
return ret;
}
-static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
+static void sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
{
int *opp_tokens = platform_get_drvdata(pdev);
unsigned int cpu;
@@ -148,13 +148,11 @@ static int sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
kfree(opp_tokens);
-
- return 0;
}
static struct platform_driver sun50i_cpufreq_driver = {
.probe = sun50i_cpufreq_nvmem_probe,
- .remove = sun50i_cpufreq_nvmem_remove,
+ .remove_new = sun50i_cpufreq_nvmem_remove,
.driver = {
.name = "sun50i-cpufreq-nvmem",
},
diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c
index f98f53bf1011..7b8fcfa55038 100644
--- a/drivers/cpufreq/tegra186-cpufreq.c
+++ b/drivers/cpufreq/tegra186-cpufreq.c
@@ -259,11 +259,9 @@ put_bpmp:
return err;
}
-static int tegra186_cpufreq_remove(struct platform_device *pdev)
+static void tegra186_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&tegra186_cpufreq_driver);
-
- return 0;
}
static const struct of_device_id tegra186_cpufreq_of_match[] = {
@@ -278,7 +276,7 @@ static struct platform_driver tegra186_cpufreq_platform_driver = {
.of_match_table = tegra186_cpufreq_of_match,
},
.probe = tegra186_cpufreq_probe,
- .remove = tegra186_cpufreq_remove,
+ .remove_new = tegra186_cpufreq_remove,
};
module_platform_driver(tegra186_cpufreq_platform_driver);
diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c
index 36dad5ea5947..88ef5e57ccd0 100644
--- a/drivers/cpufreq/tegra194-cpufreq.c
+++ b/drivers/cpufreq/tegra194-cpufreq.c
@@ -508,6 +508,32 @@ static int tegra194_cpufreq_init(struct cpufreq_policy *policy)
return 0;
}
+static int tegra194_cpufreq_online(struct cpufreq_policy *policy)
+{
+ /* We did light-weight tear down earlier, nothing to do here */
+ return 0;
+}
+
+static int tegra194_cpufreq_offline(struct cpufreq_policy *policy)
+{
+ /*
+ * Preserve policy->driver_data and don't free resources on light-weight
+ * tear down.
+ */
+
+ return 0;
+}
+
+static int tegra194_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ struct device *cpu_dev = get_cpu_device(policy->cpu);
+
+ dev_pm_opp_remove_all_dynamic(cpu_dev);
+ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+
+ return 0;
+}
+
static int tegra194_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index)
{
@@ -535,6 +561,9 @@ static struct cpufreq_driver tegra194_cpufreq_driver = {
.target_index = tegra194_cpufreq_set_target,
.get = tegra194_get_speed,
.init = tegra194_cpufreq_init,
+ .exit = tegra194_cpufreq_exit,
+ .online = tegra194_cpufreq_online,
+ .offline = tegra194_cpufreq_offline,
.attr = cpufreq_generic_attr,
};
@@ -708,12 +737,10 @@ put_bpmp:
return err;
}
-static int tegra194_cpufreq_remove(struct platform_device *pdev)
+static void tegra194_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&tegra194_cpufreq_driver);
tegra194_cpufreq_free_resources();
-
- return 0;
}
static const struct of_device_id tegra194_cpufreq_of_match[] = {
@@ -730,7 +757,7 @@ static struct platform_driver tegra194_ccplex_driver = {
.of_match_table = tegra194_cpufreq_of_match,
},
.probe = tegra194_cpufreq_probe,
- .remove = tegra194_cpufreq_remove,
+ .remove_new = tegra194_cpufreq_remove,
};
module_platform_driver(tegra194_ccplex_driver);
diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
index d5cd2fd25cad..3c37d7899660 100644
--- a/drivers/cpufreq/ti-cpufreq.c
+++ b/drivers/cpufreq/ti-cpufreq.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c
index d295f405c4bb..9ac4ea50b874 100644
--- a/drivers/cpufreq/vexpress-spc-cpufreq.c
+++ b/drivers/cpufreq/vexpress-spc-cpufreq.c
@@ -18,7 +18,6 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
@@ -552,7 +551,7 @@ static int ve_spc_cpufreq_probe(struct platform_device *pdev)
return ret;
}
-static int ve_spc_cpufreq_remove(struct platform_device *pdev)
+static void ve_spc_cpufreq_remove(struct platform_device *pdev)
{
bL_switcher_get_enabled();
__bLs_unregister_notifier();
@@ -560,7 +559,6 @@ static int ve_spc_cpufreq_remove(struct platform_device *pdev)
bL_switcher_put_enabled();
pr_info("%s: Un-registered platform driver: %s\n", __func__,
ve_spc_cpufreq_driver.name);
- return 0;
}
static struct platform_driver ve_spc_cpufreq_platdrv = {
@@ -568,7 +566,7 @@ static struct platform_driver ve_spc_cpufreq_platdrv = {
.name = "vexpress-spc-cpufreq",
},
.probe = ve_spc_cpufreq_probe,
- .remove = ve_spc_cpufreq_remove,
+ .remove_new = ve_spc_cpufreq_remove,
};
module_platform_driver(ve_spc_cpufreq_platdrv);
diff --git a/drivers/cpuidle/governors/gov.h b/drivers/cpuidle/governors/gov.h
new file mode 100644
index 000000000000..99e067d9668c
--- /dev/null
+++ b/drivers/cpuidle/governors/gov.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Common definitions for cpuidle governors. */
+
+#ifndef __CPUIDLE_GOVERNOR_H
+#define __CPUIDLE_GOVERNOR_H
+
+/*
+ * Idle state target residency threshold used for deciding whether or not to
+ * check the time till the closest expected timer event.
+ */
+#define RESIDENCY_THRESHOLD_NS (15 * NSEC_PER_USEC)
+
+#endif /* __CPUIDLE_GOVERNOR_H */
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c4922684f305..b96e3da0fedd 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -19,6 +19,8 @@
#include <linux/sched/stat.h>
#include <linux/math64.h>
+#include "gov.h"
+
#define BUCKETS 12
#define INTERVAL_SHIFT 3
#define INTERVALS (1UL << INTERVAL_SHIFT)
@@ -166,8 +168,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
* of points is below a threshold. If it is... then use the
* average of these 8 points as the estimated value.
*/
-static unsigned int get_typical_interval(struct menu_device *data,
- unsigned int predicted_us)
+static unsigned int get_typical_interval(struct menu_device *data)
{
int i, divisor;
unsigned int min, max, thresh, avg;
@@ -195,11 +196,7 @@ again:
}
}
- /*
- * If the result of the computation is going to be discarded anyway,
- * avoid the computation altogether.
- */
- if (min >= predicted_us)
+ if (!max)
return UINT_MAX;
if (divisor == INTERVALS)
@@ -267,7 +264,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
{
struct menu_device *data = this_cpu_ptr(&menu_devices);
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
- unsigned int predicted_us;
u64 predicted_ns;
u64 interactivity_req;
unsigned int nr_iowaiters;
@@ -279,16 +275,41 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
data->needs_update = 0;
}
- /* determine the expected residency time, round up */
- delta = tick_nohz_get_sleep_length(&delta_tick);
- if (unlikely(delta < 0)) {
- delta = 0;
- delta_tick = 0;
- }
- data->next_timer_ns = delta;
-
nr_iowaiters = nr_iowait_cpu(dev->cpu);
- data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters);
+
+ /* Find the shortest expected idle interval. */
+ predicted_ns = get_typical_interval(data) * NSEC_PER_USEC;
+ if (predicted_ns > RESIDENCY_THRESHOLD_NS) {
+ unsigned int timer_us;
+
+ /* Determine the time till the closest timer. */
+ delta = tick_nohz_get_sleep_length(&delta_tick);
+ if (unlikely(delta < 0)) {
+ delta = 0;
+ delta_tick = 0;
+ }
+
+ data->next_timer_ns = delta;
+ data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters);
+
+ /* Round up the result for half microseconds. */
+ timer_us = div_u64((RESOLUTION * DECAY * NSEC_PER_USEC) / 2 +
+ data->next_timer_ns *
+ data->correction_factor[data->bucket],
+ RESOLUTION * DECAY * NSEC_PER_USEC);
+ /* Use the lowest expected idle interval to pick the idle state. */
+ predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns);
+ } else {
+ /*
+ * Because the next timer event is not going to be determined
+ * in this case, assume that without the tick the closest timer
+ * will be in distant future and that the closest tick will occur
+ * after 1/2 of the tick period.
+ */
+ data->next_timer_ns = KTIME_MAX;
+ delta_tick = TICK_NSEC / 2;
+ data->bucket = which_bucket(KTIME_MAX, nr_iowaiters);
+ }
if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
((data->next_timer_ns < drv->states[1].target_residency_ns ||
@@ -303,16 +324,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
return 0;
}
- /* Round up the result for half microseconds. */
- predicted_us = div_u64(data->next_timer_ns *
- data->correction_factor[data->bucket] +
- (RESOLUTION * DECAY * NSEC_PER_USEC) / 2,
- RESOLUTION * DECAY * NSEC_PER_USEC);
- /* Use the lowest expected idle interval to pick the idle state. */
- predicted_ns = (u64)min(predicted_us,
- get_typical_interval(data, predicted_us)) *
- NSEC_PER_USEC;
-
if (tick_nohz_tick_stopped()) {
/*
* If the tick is already stopped, the cost of possible short
diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c
index 987fc5f3997d..7244f71c59c5 100644
--- a/drivers/cpuidle/governors/teo.c
+++ b/drivers/cpuidle/governors/teo.c
@@ -140,6 +140,8 @@
#include <linux/sched/topology.h>
#include <linux/tick.h>
+#include "gov.h"
+
/*
* The number of bits to shift the CPU's capacity by in order to determine
* the utilized threshold.
@@ -152,7 +154,6 @@
*/
#define UTIL_THRESHOLD_SHIFT 6
-
/*
* The PULSE value is added to metrics when they grow and the DECAY_SHIFT value
* is used for decreasing metrics on a regular basis.
@@ -186,8 +187,8 @@ struct teo_bin {
* @total: Grand total of the "intercepts" and "hits" metrics for all bins.
* @next_recent_idx: Index of the next @recent_idx entry to update.
* @recent_idx: Indices of bins corresponding to recent "intercepts".
+ * @tick_hits: Number of "hits" after TICK_NSEC.
* @util_threshold: Threshold above which the CPU is considered utilized
- * @utilized: Whether the last sleep on the CPU happened while utilized
*/
struct teo_cpu {
s64 time_span_ns;
@@ -196,8 +197,8 @@ struct teo_cpu {
unsigned int total;
int next_recent_idx;
int recent_idx[NR_RECENT];
+ unsigned int tick_hits;
unsigned long util_threshold;
- bool utilized;
};
static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
@@ -228,6 +229,7 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
int i, idx_timer = 0, idx_duration = 0;
+ s64 target_residency_ns;
u64 measured_ns;
if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) {
@@ -268,7 +270,6 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* fall into.
*/
for (i = 0; i < drv->state_count; i++) {
- s64 target_residency_ns = drv->states[i].target_residency_ns;
struct teo_bin *bin = &cpu_data->state_bins[i];
bin->hits -= bin->hits >> DECAY_SHIFT;
@@ -276,6 +277,8 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
cpu_data->total += bin->hits + bin->intercepts;
+ target_residency_ns = drv->states[i].target_residency_ns;
+
if (target_residency_ns <= cpu_data->sleep_length_ns) {
idx_timer = i;
if (target_residency_ns <= measured_ns)
@@ -291,6 +294,26 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
cpu_data->state_bins[cpu_data->recent_idx[i]].recent--;
/*
+ * If the deepest state's target residency is below the tick length,
+ * make a record of it to help teo_select() decide whether or not
+ * to stop the tick. This effectively adds an extra hits-only bin
+ * beyond the last state-related one.
+ */
+ if (target_residency_ns < TICK_NSEC) {
+ cpu_data->tick_hits -= cpu_data->tick_hits >> DECAY_SHIFT;
+
+ cpu_data->total += cpu_data->tick_hits;
+
+ if (TICK_NSEC <= cpu_data->sleep_length_ns) {
+ idx_timer = drv->state_count;
+ if (TICK_NSEC <= measured_ns) {
+ cpu_data->tick_hits += PULSE;
+ goto end;
+ }
+ }
+ }
+
+ /*
* If the measured idle duration falls into the same bin as the sleep
* length, this is a "hit", so update the "hits" metric for that bin.
* Otherwise, update the "intercepts" metric for the bin fallen into by
@@ -305,18 +328,14 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
cpu_data->recent_idx[i] = idx_duration;
}
+end:
cpu_data->total += PULSE;
}
-static bool teo_time_ok(u64 interval_ns)
+static bool teo_state_ok(int i, struct cpuidle_driver *drv)
{
- return !tick_nohz_tick_stopped() || interval_ns >= TICK_NSEC;
-}
-
-static s64 teo_middle_of_bin(int idx, struct cpuidle_driver *drv)
-{
- return (drv->states[idx].target_residency_ns +
- drv->states[idx+1].target_residency_ns) / 2;
+ return !tick_nohz_tick_stopped() ||
+ drv->states[i].target_residency_ns >= TICK_NSEC;
}
/**
@@ -356,6 +375,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
{
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
+ ktime_t delta_tick = TICK_NSEC / 2;
+ unsigned int tick_intercept_sum = 0;
unsigned int idx_intercept_sum = 0;
unsigned int intercept_sum = 0;
unsigned int idx_recent_sum = 0;
@@ -365,7 +386,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
int constraint_idx = 0;
int idx0 = 0, idx = -1;
bool alt_intercepts, alt_recent;
- ktime_t delta_tick;
+ bool cpu_utilized;
s64 duration_ns;
int i;
@@ -375,44 +396,48 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
}
cpu_data->time_span_ns = local_clock();
-
- duration_ns = tick_nohz_get_sleep_length(&delta_tick);
- cpu_data->sleep_length_ns = duration_ns;
+ /*
+ * Set the expected sleep length to infinity in case of an early
+ * return.
+ */
+ cpu_data->sleep_length_ns = KTIME_MAX;
/* Check if there is any choice in the first place. */
if (drv->state_count < 2) {
idx = 0;
- goto end;
+ goto out_tick;
}
- if (!dev->states_usage[0].disable) {
+
+ if (!dev->states_usage[0].disable)
idx = 0;
- if (drv->states[1].target_residency_ns > duration_ns)
- goto end;
- }
- cpu_data->utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
+ cpu_utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
/*
* If the CPU is being utilized over the threshold and there are only 2
* states to choose from, the metrics need not be considered, so choose
* the shallowest non-polling state and exit.
*/
- if (drv->state_count < 3 && cpu_data->utilized) {
- for (i = 0; i < drv->state_count; ++i) {
- if (!dev->states_usage[i].disable &&
- !(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) {
- idx = i;
- goto end;
- }
+ if (drv->state_count < 3 && cpu_utilized) {
+ /*
+ * If state 0 is enabled and it is not a polling one, select it
+ * right away unless the scheduler tick has been stopped, in
+ * which case care needs to be taken to leave the CPU in a deep
+ * enough state in case it is not woken up any time soon after
+ * all. If state 1 is disabled, though, state 0 must be used
+ * anyway.
+ */
+ if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
+ teo_state_ok(0, drv)) || dev->states_usage[1].disable) {
+ idx = 0;
+ goto out_tick;
}
+ /* Assume that state 1 is not a polling one and use it. */
+ idx = 1;
+ duration_ns = drv->states[1].target_residency_ns;
+ goto end;
}
- /*
- * Find the deepest idle state whose target residency does not exceed
- * the current sleep length and the deepest idle state not deeper than
- * the former whose exit latency does not exceed the current latency
- * constraint. Compute the sums of metrics for early wakeup pattern
- * detection.
- */
+ /* Compute the sums of metrics for early wakeup pattern detection. */
for (i = 1; i < drv->state_count; i++) {
struct teo_bin *prev_bin = &cpu_data->state_bins[i-1];
struct cpuidle_state *s = &drv->states[i];
@@ -428,19 +453,15 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (dev->states_usage[i].disable)
continue;
- if (idx < 0) {
- idx = i; /* first enabled state */
- idx0 = i;
- }
-
- if (s->target_residency_ns > duration_ns)
- break;
+ if (idx < 0)
+ idx0 = i; /* first enabled state */
idx = i;
if (s->exit_latency_ns <= latency_req)
constraint_idx = i;
+ /* Save the sums for the current state. */
idx_intercept_sum = intercept_sum;
idx_hit_sum = hit_sum;
idx_recent_sum = recent_sum;
@@ -449,11 +470,21 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
/* Avoid unnecessary overhead. */
if (idx < 0) {
idx = 0; /* No states enabled, must use 0. */
- goto end;
- } else if (idx == idx0) {
+ goto out_tick;
+ }
+
+ if (idx == idx0) {
+ /*
+ * Only one idle state is enabled, so use it, but do not
+ * allow the tick to be stopped it is shallow enough.
+ */
+ duration_ns = drv->states[idx].target_residency_ns;
goto end;
}
+ tick_intercept_sum = intercept_sum +
+ cpu_data->state_bins[drv->state_count-1].intercepts;
+
/*
* If the sum of the intercepts metric for all of the idle states
* shallower than the current candidate one (idx) is greater than the
@@ -461,13 +492,11 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* all of the deeper states, or the sum of the numbers of recent
* intercepts over all of the states shallower than the candidate one
* is greater than a half of the number of recent events taken into
- * account, the CPU is likely to wake up early, so find an alternative
- * idle state to select.
+ * account, a shallower idle state is likely to be a better choice.
*/
alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum;
alt_recent = idx_recent_sum > NR_RECENT / 2;
if (alt_recent || alt_intercepts) {
- s64 first_suitable_span_ns = duration_ns;
int first_suitable_idx = idx;
/*
@@ -476,44 +505,39 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* cases (both with respect to intercepts overall and with
* respect to the recent intercepts only) in the past.
*
- * Take the possible latency constraint and duration limitation
- * present if the tick has been stopped already into account.
+ * Take the possible duration limitation present if the tick
+ * has been stopped already into account.
*/
intercept_sum = 0;
recent_sum = 0;
for (i = idx - 1; i >= 0; i--) {
struct teo_bin *bin = &cpu_data->state_bins[i];
- s64 span_ns;
intercept_sum += bin->intercepts;
recent_sum += bin->recent;
- span_ns = teo_middle_of_bin(i, drv);
-
if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
(!alt_intercepts ||
2 * intercept_sum > idx_intercept_sum)) {
- if (teo_time_ok(span_ns) &&
- !dev->states_usage[i].disable) {
+ /*
+ * Use the current state unless it is too
+ * shallow or disabled, in which case take the
+ * first enabled state that is deep enough.
+ */
+ if (teo_state_ok(i, drv) &&
+ !dev->states_usage[i].disable)
idx = i;
- duration_ns = span_ns;
- } else {
- /*
- * The current state is too shallow or
- * disabled, so take the first enabled
- * deeper state with suitable time span.
- */
+ else
idx = first_suitable_idx;
- duration_ns = first_suitable_span_ns;
- }
+
break;
}
if (dev->states_usage[i].disable)
continue;
- if (!teo_time_ok(span_ns)) {
+ if (!teo_state_ok(i, drv)) {
/*
* The current state is too shallow, but if an
* alternative candidate state has been found,
@@ -525,7 +549,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
break;
}
- first_suitable_span_ns = span_ns;
first_suitable_idx = i;
}
}
@@ -539,31 +562,75 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
/*
* If the CPU is being utilized over the threshold, choose a shallower
- * non-polling state to improve latency
+ * non-polling state to improve latency, unless the scheduler tick has
+ * been stopped already and the shallower state's target residency is
+ * not sufficiently large.
*/
- if (cpu_data->utilized)
- idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
+ if (cpu_utilized) {
+ i = teo_find_shallower_state(drv, dev, idx, KTIME_MAX, true);
+ if (teo_state_ok(i, drv))
+ idx = i;
+ }
-end:
/*
- * Don't stop the tick if the selected state is a polling one or if the
- * expected idle duration is shorter than the tick period length.
+ * Skip the timers check if state 0 is the current candidate one,
+ * because an immediate non-timer wakeup is expected in that case.
*/
- if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
- duration_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) {
- *stop_tick = false;
+ if (!idx)
+ goto out_tick;
- /*
- * The tick is not going to be stopped, so if the target
- * residency of the state to be returned is not within the time
- * till the closest timer including the tick, try to correct
- * that.
- */
- if (idx > idx0 &&
- drv->states[idx].target_residency_ns > delta_tick)
- idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
+ /*
+ * If state 0 is a polling one, check if the target residency of
+ * the current candidate state is low enough and skip the timers
+ * check in that case too.
+ */
+ if ((drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
+ drv->states[idx].target_residency_ns < RESIDENCY_THRESHOLD_NS)
+ goto out_tick;
+
+ duration_ns = tick_nohz_get_sleep_length(&delta_tick);
+ cpu_data->sleep_length_ns = duration_ns;
+
+ /*
+ * If the closest expected timer is before the terget residency of the
+ * candidate state, a shallower one needs to be found.
+ */
+ if (drv->states[idx].target_residency_ns > duration_ns) {
+ i = teo_find_shallower_state(drv, dev, idx, duration_ns, false);
+ if (teo_state_ok(i, drv))
+ idx = i;
}
+ /*
+ * If the selected state's target residency is below the tick length
+ * and intercepts occurring before the tick length are the majority of
+ * total wakeup events, do not stop the tick.
+ */
+ if (drv->states[idx].target_residency_ns < TICK_NSEC &&
+ tick_intercept_sum > cpu_data->total / 2 + cpu_data->total / 8)
+ duration_ns = TICK_NSEC / 2;
+
+end:
+ /*
+ * Allow the tick to be stopped unless the selected state is a polling
+ * one or the expected idle duration is shorter than the tick period
+ * length.
+ */
+ if ((!(drv->states[idx].flags & CPUIDLE_FLAG_POLLING) &&
+ duration_ns >= TICK_NSEC) || tick_nohz_tick_stopped())
+ return idx;
+
+ /*
+ * The tick is not going to be stopped, so if the target residency of
+ * the state to be returned is not within the time till the closest
+ * timer including the tick, try to correct that.
+ */
+ if (idx > idx0 &&
+ drv->states[idx].target_residency_ns > delta_tick)
+ idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
+
+out_tick:
+ *stop_tick = false;
return idx;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 44e44b8d9ce6..c761952f0dc6 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -70,10 +70,9 @@ config ZCRYPT
select HW_RANDOM
help
Select this option if you want to enable support for
- s390 cryptographic adapters like:
- + Crypto Express 2 up to 7 Coprocessor (CEXxC)
- + Crypto Express 2 up to 7 Accelerator (CEXxA)
- + Crypto Express 4 up to 7 EP11 Coprocessor (CEXxP)
+ s390 cryptographic adapters like Crypto Express 4 up
+ to 8 in Coprocessor (CEXxC), EP11 Coprocessor (CEXxP)
+ or Accelerator (CEXxA) mode.
config ZCRYPT_DEBUG
bool "Enable debug features for s390 cryptographic adapters"
diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
index 51a3a7b5b985..3bcfcfc37084 100644
--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
@@ -14,7 +14,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <crypto/scatterwalk.h>
#include <linux/scatterlist.h>
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
index c13550090785..8d4c42863a62 100644
--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
+++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
@@ -29,7 +29,7 @@ static int sun8i_ce_cipher_need_fallback(struct skcipher_request *areq)
struct sun8i_ce_alg_template *algt;
unsigned int todo, len;
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
if (sg_nents_for_len(areq->src, areq->cryptlen) > MAX_SG ||
sg_nents_for_len(areq->dst, areq->cryptlen) > MAX_SG) {
@@ -92,13 +92,18 @@ static int sun8i_ce_cipher_fallback(struct skcipher_request *areq)
struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm);
struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
int err;
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct sun8i_ce_alg_template *algt;
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher);
- algt->stat_fb++;
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct sun8i_ce_alg_template *algt __maybe_unused;
+
+ algt = container_of(alg, struct sun8i_ce_alg_template,
+ alg.skcipher.base);
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+ algt->stat_fb++;
#endif
+ }
skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
@@ -133,7 +138,7 @@ static int sun8i_ce_cipher_prepare(struct crypto_engine *engine, void *async_req
int ns = sg_nents_for_len(areq->src, areq->cryptlen);
int nd = sg_nents_for_len(areq->dst, areq->cryptlen);
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
crypto_tfm_alg_name(areq->base.tfm),
@@ -294,7 +299,7 @@ theend:
return err;
}
-static int sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
+static void sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
{
struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(breq);
@@ -308,10 +313,10 @@ static int sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq)
local_bh_disable();
crypto_finalize_skcipher_request(engine, breq, err);
local_bh_enable();
- return 0;
}
-static int sun8i_ce_cipher_unprepare(struct crypto_engine *engine, void *async_req)
+static void sun8i_ce_cipher_unprepare(struct crypto_engine *engine,
+ void *async_req)
{
struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base);
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
@@ -353,7 +358,17 @@ static int sun8i_ce_cipher_unprepare(struct crypto_engine *engine, void *async_r
}
dma_unmap_single(ce->dev, rctx->addr_key, op->keylen, DMA_TO_DEVICE);
+}
+
+int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq)
+{
+ int err = sun8i_ce_cipher_prepare(engine, areq);
+ if (err)
+ return err;
+
+ sun8i_ce_cipher_run(engine, areq);
+ sun8i_ce_cipher_unprepare(engine, areq);
return 0;
}
@@ -406,7 +421,7 @@ int sun8i_ce_cipher_init(struct crypto_tfm *tfm)
memset(op, 0, sizeof(struct sun8i_cipher_tfm_ctx));
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.skcipher.base);
op->ce = algt->ce;
op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
@@ -423,10 +438,6 @@ int sun8i_ce_cipher_init(struct crypto_tfm *tfm)
crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)),
CRYPTO_MAX_ALG_NAME);
- op->enginectx.op.do_one_request = sun8i_ce_cipher_run;
- op->enginectx.op.prepare_request = sun8i_ce_cipher_prepare;
- op->enginectx.op.unprepare_request = sun8i_ce_cipher_unprepare;
-
err = pm_runtime_get_sync(op->ce->dev);
if (err < 0)
goto error_pm;
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
index 07ea0cc82b16..d4ccd5254280 100644
--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
+++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
@@ -9,21 +9,24 @@
*
* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst
*/
+
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/rng.h>
+#include <crypto/internal/skcipher.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <crypto/internal/rng.h>
-#include <crypto/internal/skcipher.h>
#include "sun8i-ce.h"
@@ -277,7 +280,7 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ce_algo_id = CE_ID_CIPHER_AES,
.ce_blockmode = CE_ID_OP_CBC,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-sun8i-ce",
@@ -298,13 +301,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.setkey = sun8i_ce_aes_setkey,
.encrypt = sun8i_ce_skencrypt,
.decrypt = sun8i_ce_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ce_cipher_do_one,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ce_algo_id = CE_ID_CIPHER_AES,
.ce_blockmode = CE_ID_OP_ECB,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-sun8i-ce",
@@ -324,13 +330,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.setkey = sun8i_ce_aes_setkey,
.encrypt = sun8i_ce_skencrypt,
.decrypt = sun8i_ce_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ce_cipher_do_one,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ce_algo_id = CE_ID_CIPHER_DES3,
.ce_blockmode = CE_ID_OP_CBC,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-des3-sun8i-ce",
@@ -351,13 +360,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.setkey = sun8i_ce_des3_setkey,
.encrypt = sun8i_ce_skencrypt,
.decrypt = sun8i_ce_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ce_cipher_do_one,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ce_algo_id = CE_ID_CIPHER_DES3,
.ce_blockmode = CE_ID_OP_ECB,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3-sun8i-ce",
@@ -377,12 +389,15 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.setkey = sun8i_ce_des3_setkey,
.encrypt = sun8i_ce_skencrypt,
.decrypt = sun8i_ce_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ce_cipher_do_one,
+ },
},
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_HASH
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_MD5,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -390,6 +405,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = MD5_DIGEST_SIZE,
.statesize = sizeof(struct md5_state),
@@ -404,15 +421,17 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
+
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_SHA1,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -420,6 +439,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.statesize = sizeof(struct sha1_state),
@@ -434,15 +455,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_SHA224,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -450,6 +472,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
@@ -464,15 +488,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_SHA256,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -480,6 +505,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
@@ -494,15 +521,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_SHA384,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -510,6 +538,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
@@ -524,15 +554,16 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ce_algo_id = CE_ID_HASH_SHA512,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ce_hash_init,
.update = sun8i_ce_hash_update,
.final = sun8i_ce_hash_final,
@@ -540,6 +571,8 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.digest = sun8i_ce_hash_digest,
.export = sun8i_ce_hash_export,
.import = sun8i_ce_hash_import,
+ .init_tfm = sun8i_ce_hash_init_tfm,
+ .exit_tfm = sun8i_ce_hash_exit_tfm,
.halg = {
.digestsize = SHA512_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
@@ -554,11 +587,12 @@ static struct sun8i_ce_alg_template ce_algs[] = {
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ce_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ce_hash_crainit,
- .cra_exit = sun8i_ce_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ce_hash_run,
+ },
},
#endif
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG
@@ -582,14 +616,18 @@ static struct sun8i_ce_alg_template ce_algs[] = {
#endif
};
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
{
- struct sun8i_ce_dev *ce = seq->private;
+ struct sun8i_ce_dev *ce __maybe_unused = seq->private;
unsigned int i;
for (i = 0; i < MAXFLOW; i++)
- seq_printf(seq, "Channel %d: nreq %lu\n", i, ce->chanlist[i].stat_req);
+ seq_printf(seq, "Channel %d: nreq %lu\n", i,
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+ ce->chanlist[i].stat_req);
+#else
+ 0ul);
+#endif
for (i = 0; i < ARRAY_SIZE(ce_algs); i++) {
if (!ce_algs[i].ce)
@@ -597,8 +635,8 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
switch (ce_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- ce_algs[i].alg.skcipher.base.cra_driver_name,
- ce_algs[i].alg.skcipher.base.cra_name,
+ ce_algs[i].alg.skcipher.base.base.cra_driver_name,
+ ce_algs[i].alg.skcipher.base.base.cra_name,
ce_algs[i].stat_req, ce_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
ce_algs[i].fbname);
@@ -621,8 +659,8 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
break;
case CRYPTO_ALG_TYPE_AHASH:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- ce_algs[i].alg.hash.halg.base.cra_driver_name,
- ce_algs[i].alg.hash.halg.base.cra_name,
+ ce_algs[i].alg.hash.base.halg.base.cra_driver_name,
+ ce_algs[i].alg.hash.base.halg.base.cra_name,
ce_algs[i].stat_req, ce_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
ce_algs[i].fbname);
@@ -643,7 +681,8 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
break;
}
}
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG
+#if defined(CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG) && \
+ defined(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)
seq_printf(seq, "HWRNG %lu %lu\n",
ce->hwrng_stat_req, ce->hwrng_stat_bytes);
#endif
@@ -651,7 +690,6 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
}
DEFINE_SHOW_ATTRIBUTE(sun8i_ce_debugfs);
-#endif
static void sun8i_ce_free_chanlist(struct sun8i_ce_dev *ce, int i)
{
@@ -839,7 +877,7 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
if (ce_method == CE_ID_NOTSUPP) {
dev_dbg(ce->dev,
"DEBUG: Algo of %s not supported\n",
- ce_algs[i].alg.skcipher.base.cra_name);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
ce_algs[i].ce = NULL;
break;
}
@@ -847,16 +885,16 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
ce_method = ce->variant->op_mode[id];
if (ce_method == CE_ID_NOTSUPP) {
dev_dbg(ce->dev, "DEBUG: Blockmode of %s not supported\n",
- ce_algs[i].alg.skcipher.base.cra_name);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
ce_algs[i].ce = NULL;
break;
}
dev_info(ce->dev, "Register %s\n",
- ce_algs[i].alg.skcipher.base.cra_name);
- err = crypto_register_skcipher(&ce_algs[i].alg.skcipher);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
+ err = crypto_engine_register_skcipher(&ce_algs[i].alg.skcipher);
if (err) {
dev_err(ce->dev, "ERROR: Fail to register %s\n",
- ce_algs[i].alg.skcipher.base.cra_name);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
ce_algs[i].ce = NULL;
return err;
}
@@ -867,16 +905,16 @@ static int sun8i_ce_register_algs(struct sun8i_ce_dev *ce)
if (ce_method == CE_ID_NOTSUPP) {
dev_info(ce->dev,
"DEBUG: Algo of %s not supported\n",
- ce_algs[i].alg.hash.halg.base.cra_name);
+ ce_algs[i].alg.hash.base.halg.base.cra_name);
ce_algs[i].ce = NULL;
break;
}
dev_info(ce->dev, "Register %s\n",
- ce_algs[i].alg.hash.halg.base.cra_name);
- err = crypto_register_ahash(&ce_algs[i].alg.hash);
+ ce_algs[i].alg.hash.base.halg.base.cra_name);
+ err = crypto_engine_register_ahash(&ce_algs[i].alg.hash);
if (err) {
dev_err(ce->dev, "ERROR: Fail to register %s\n",
- ce_algs[i].alg.hash.halg.base.cra_name);
+ ce_algs[i].alg.hash.base.halg.base.cra_name);
ce_algs[i].ce = NULL;
return err;
}
@@ -916,13 +954,13 @@ static void sun8i_ce_unregister_algs(struct sun8i_ce_dev *ce)
switch (ce_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(ce->dev, "Unregister %d %s\n", i,
- ce_algs[i].alg.skcipher.base.cra_name);
- crypto_unregister_skcipher(&ce_algs[i].alg.skcipher);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
+ crypto_engine_unregister_skcipher(&ce_algs[i].alg.skcipher);
break;
case CRYPTO_ALG_TYPE_AHASH:
dev_info(ce->dev, "Unregister %d %s\n", i,
- ce_algs[i].alg.hash.halg.base.cra_name);
- crypto_unregister_ahash(&ce_algs[i].alg.hash);
+ ce_algs[i].alg.hash.base.halg.base.cra_name);
+ crypto_engine_unregister_ahash(&ce_algs[i].alg.hash);
break;
case CRYPTO_ALG_TYPE_RNG:
dev_info(ce->dev, "Unregister %d %s\n", i,
@@ -1007,13 +1045,21 @@ static int sun8i_ce_probe(struct platform_device *pdev)
pm_runtime_put_sync(ce->dev);
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
+ struct dentry *dbgfs_dir __maybe_unused;
+ struct dentry *dbgfs_stats __maybe_unused;
+
+ /* Ignore error of debugfs */
+ dbgfs_dir = debugfs_create_dir("sun8i-ce", NULL);
+ dbgfs_stats = debugfs_create_file("stats", 0444,
+ dbgfs_dir, ce,
+ &sun8i_ce_debugfs_fops);
+
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- /* Ignore error of debugfs */
- ce->dbgfs_dir = debugfs_create_dir("sun8i-ce", NULL);
- ce->dbgfs_stats = debugfs_create_file("stats", 0444,
- ce->dbgfs_dir, ce,
- &sun8i_ce_debugfs_fops);
+ ce->dbgfs_dir = dbgfs_dir;
+ ce->dbgfs_stats = dbgfs_stats;
#endif
+ }
return 0;
error_alg:
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c
index 930ad157004c..d358334e5981 100644
--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c
+++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c
@@ -9,48 +9,46 @@
*
* You could find the datasheet in Documentation/arch/arm/sunxi.rst
*/
+
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
#include <linux/bottom_half.h>
#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
-#include <crypto/internal/hash.h>
-#include <crypto/sha1.h>
-#include <crypto/sha2.h>
-#include <crypto/md5.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include "sun8i-ce.h"
-int sun8i_ce_hash_crainit(struct crypto_tfm *tfm)
+int sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm)
{
- struct sun8i_ce_hash_tfm_ctx *op = crypto_tfm_ctx(tfm);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+ struct sun8i_ce_hash_tfm_ctx *op = crypto_ahash_ctx(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
struct sun8i_ce_alg_template *algt;
int err;
- memset(op, 0, sizeof(struct sun8i_ce_hash_tfm_ctx));
-
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
op->ce = algt->ce;
- op->enginectx.op.do_one_request = sun8i_ce_hash_run;
- op->enginectx.op.prepare_request = NULL;
- op->enginectx.op.unprepare_request = NULL;
-
/* FALLBACK */
- op->fallback_tfm = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
+ op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(op->fallback_tfm)) {
dev_err(algt->ce->dev, "Fallback driver could no be loaded\n");
return PTR_ERR(op->fallback_tfm);
}
- if (algt->alg.hash.halg.statesize < crypto_ahash_statesize(op->fallback_tfm))
- algt->alg.hash.halg.statesize = crypto_ahash_statesize(op->fallback_tfm);
+ crypto_ahash_set_statesize(tfm,
+ crypto_ahash_statesize(op->fallback_tfm));
- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ crypto_ahash_set_reqsize(tfm,
sizeof(struct sun8i_ce_hash_reqctx) +
crypto_ahash_reqsize(op->fallback_tfm));
- memcpy(algt->fbname, crypto_tfm_alg_driver_name(&op->fallback_tfm->base),
+ memcpy(algt->fbname, crypto_ahash_driver_name(op->fallback_tfm),
CRYPTO_MAX_ALG_NAME);
err = pm_runtime_get_sync(op->ce->dev);
@@ -63,9 +61,9 @@ error_pm:
return err;
}
-void sun8i_ce_hash_craexit(struct crypto_tfm *tfm)
+void sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm)
{
- struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_tfm_ctx(tfm);
+ struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
crypto_free_ahash(tfmctx->fallback_tfm);
pm_runtime_put_sync_suspend(tfmctx->ce->dev);
@@ -114,20 +112,22 @@ int sun8i_ce_hash_final(struct ahash_request *areq)
struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ce_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
CRYPTO_TFM_REQ_MAY_SLEEP;
rctx->fallback_req.result = areq->result;
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
+ struct sun8i_ce_alg_template *algt __maybe_unused;
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+
+ algt = container_of(alg, struct sun8i_ce_alg_template,
+ alg.hash.base);
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_final(&rctx->fallback_req);
}
@@ -152,10 +152,6 @@ int sun8i_ce_hash_finup(struct ahash_request *areq)
struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ce_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
@@ -164,10 +160,17 @@ int sun8i_ce_hash_finup(struct ahash_request *areq)
rctx->fallback_req.nbytes = areq->nbytes;
rctx->fallback_req.src = areq->src;
rctx->fallback_req.result = areq->result;
+
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
+ struct sun8i_ce_alg_template *algt __maybe_unused;
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+
+ algt = container_of(alg, struct sun8i_ce_alg_template,
+ alg.hash.base);
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_finup(&rctx->fallback_req);
}
@@ -177,10 +180,6 @@ static int sun8i_ce_hash_digest_fb(struct ahash_request *areq)
struct sun8i_ce_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ce_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ce_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
@@ -189,10 +188,17 @@ static int sun8i_ce_hash_digest_fb(struct ahash_request *areq)
rctx->fallback_req.nbytes = areq->nbytes;
rctx->fallback_req.src = areq->src;
rctx->fallback_req.result = areq->result;
+
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG)) {
+ struct sun8i_ce_alg_template *algt __maybe_unused;
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+
+ algt = container_of(alg, struct sun8i_ce_alg_template,
+ alg.hash.base);
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_digest(&rctx->fallback_req);
}
@@ -204,7 +210,7 @@ static bool sun8i_ce_hash_need_fallback(struct ahash_request *areq)
struct sun8i_ce_alg_template *algt;
struct scatterlist *sg;
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
if (areq->nbytes == 0) {
algt->stat_fb_len0++;
@@ -253,7 +259,7 @@ int sun8i_ce_hash_digest(struct ahash_request *areq)
return sun8i_ce_hash_digest_fb(areq);
}
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
ce = algt->ce;
e = sun8i_ce_get_engine_number(ce);
@@ -345,11 +351,11 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
dma_addr_t addr_res, addr_pad;
int ns = sg_nents_for_len(areq->src, areq->nbytes);
- algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ce_alg_template, alg.hash.base);
ce = algt->ce;
- bs = algt->alg.hash.halg.base.cra_blocksize;
- digestsize = algt->alg.hash.halg.digestsize;
+ bs = algt->alg.hash.base.halg.base.cra_blocksize;
+ digestsize = algt->alg.hash.base.halg.digestsize;
if (digestsize == SHA224_DIGEST_SIZE)
digestsize = SHA256_DIGEST_SIZE;
if (digestsize == SHA384_DIGEST_SIZE)
@@ -454,14 +460,14 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq)
chan->timeout = areq->nbytes;
- err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(areq->base.tfm));
+ err = sun8i_ce_run_task(ce, flow, crypto_ahash_alg_name(tfm));
dma_unmap_single(ce->dev, addr_pad, j * 4, DMA_TO_DEVICE);
dma_unmap_sg(ce->dev, areq->src, ns, DMA_TO_DEVICE);
dma_unmap_single(ce->dev, addr_res, digestsize, DMA_FROM_DEVICE);
- memcpy(areq->result, result, algt->alg.hash.halg.digestsize);
+ memcpy(areq->result, result, algt->alg.hash.base.halg.digestsize);
theend:
kfree(buf);
kfree(result);
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
index 27029fb77e29..93d4985def87 100644
--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
+++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h
@@ -265,14 +265,12 @@ struct sun8i_cipher_req_ctx {
/*
* struct sun8i_cipher_tfm_ctx - context for a skcipher TFM
- * @enginectx: crypto_engine used by this TFM
* @key: pointer to key data
* @keylen: len of the key
* @ce: pointer to the private data of driver handling this TFM
* @fallback_tfm: pointer to the fallback TFM
*/
struct sun8i_cipher_tfm_ctx {
- struct crypto_engine_ctx enginectx;
u32 *key;
u32 keylen;
struct sun8i_ce_dev *ce;
@@ -281,12 +279,10 @@ struct sun8i_cipher_tfm_ctx {
/*
* struct sun8i_ce_hash_tfm_ctx - context for an ahash TFM
- * @enginectx: crypto_engine used by this TFM
* @ce: pointer to the private data of driver handling this TFM
* @fallback_tfm: pointer to the fallback TFM
*/
struct sun8i_ce_hash_tfm_ctx {
- struct crypto_engine_ctx enginectx;
struct sun8i_ce_dev *ce;
struct crypto_ahash *fallback_tfm;
};
@@ -329,8 +325,8 @@ struct sun8i_ce_alg_template {
u32 ce_blockmode;
struct sun8i_ce_dev *ce;
union {
- struct skcipher_alg skcipher;
- struct ahash_alg hash;
+ struct skcipher_engine_alg skcipher;
+ struct ahash_engine_alg hash;
struct rng_alg rng;
} alg;
unsigned long stat_req;
@@ -347,14 +343,13 @@ struct sun8i_ce_alg_template {
char fbname[CRYPTO_MAX_ALG_NAME];
};
-int sun8i_ce_enqueue(struct crypto_async_request *areq, u32 type);
-
int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun8i_ce_cipher_init(struct crypto_tfm *tfm);
void sun8i_ce_cipher_exit(struct crypto_tfm *tfm);
+int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq);
int sun8i_ce_skdecrypt(struct skcipher_request *areq);
int sun8i_ce_skencrypt(struct skcipher_request *areq);
@@ -362,12 +357,11 @@ int sun8i_ce_get_engine_number(struct sun8i_ce_dev *ce);
int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name);
-int sun8i_ce_hash_crainit(struct crypto_tfm *tfm);
-void sun8i_ce_hash_craexit(struct crypto_tfm *tfm);
+int sun8i_ce_hash_init_tfm(struct crypto_ahash *tfm);
+void sun8i_ce_hash_exit_tfm(struct crypto_ahash *tfm);
int sun8i_ce_hash_init(struct ahash_request *areq);
int sun8i_ce_hash_export(struct ahash_request *areq, void *out);
int sun8i_ce_hash_import(struct ahash_request *areq, const void *in);
-int sun8i_ce_hash(struct ahash_request *areq);
int sun8i_ce_hash_final(struct ahash_request *areq);
int sun8i_ce_hash_update(struct ahash_request *areq);
int sun8i_ce_hash_finup(struct ahash_request *areq);
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
index 381a90fbeaff..7fa359725ec7 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
@@ -24,7 +24,7 @@ static bool sun8i_ss_need_fallback(struct skcipher_request *areq)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct sun8i_ss_alg_template *algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher);
+ struct sun8i_ss_alg_template *algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher.base);
struct scatterlist *in_sg = areq->src;
struct scatterlist *out_sg = areq->dst;
struct scatterlist *sg;
@@ -93,13 +93,18 @@ static int sun8i_ss_cipher_fallback(struct skcipher_request *areq)
struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq);
int err;
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct sun8i_ss_alg_template *algt;
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct sun8i_ss_alg_template *algt __maybe_unused;
+
+ algt = container_of(alg, struct sun8i_ss_alg_template,
+ alg.skcipher.base);
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher);
- algt->stat_fb++;
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+ algt->stat_fb++;
#endif
+ }
+
skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
areq->base.complete, areq->base.data);
@@ -193,7 +198,7 @@ static int sun8i_ss_cipher(struct skcipher_request *areq)
int nsgd = sg_nents_for_len(areq->dst, areq->cryptlen);
int i;
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher.base);
dev_dbg(ss->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
crypto_tfm_alg_name(areq->base.tfm),
@@ -324,7 +329,7 @@ theend:
return err;
}
-static int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *areq)
+int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *areq)
{
int err;
struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
@@ -390,7 +395,7 @@ int sun8i_ss_cipher_init(struct crypto_tfm *tfm)
memset(op, 0, sizeof(struct sun8i_cipher_tfm_ctx));
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher.base);
op->ss = algt->ss;
op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
@@ -408,10 +413,6 @@ int sun8i_ss_cipher_init(struct crypto_tfm *tfm)
crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)),
CRYPTO_MAX_ALG_NAME);
- op->enginectx.op.do_one_request = sun8i_ss_handle_cipher_request;
- op->enginectx.op.prepare_request = NULL;
- op->enginectx.op.unprepare_request = NULL;
-
err = pm_runtime_resume_and_get(op->ss->dev);
if (err < 0) {
dev_err(op->ss->dev, "pm error %d\n", err);
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
index 3dd844b40ff7..4a9587285c04 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c
@@ -9,22 +9,23 @@
*
* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst
*/
+
+#include <crypto/engine.h>
+#include <crypto/internal/rng.h>
+#include <crypto/internal/skcipher.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <crypto/internal/rng.h>
-#include <crypto/internal/skcipher.h>
#include "sun8i-ss.h"
@@ -168,7 +169,7 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ss_algo_id = SS_ID_CIPHER_AES,
.ss_blockmode = SS_ID_OP_CBC,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-sun8i-ss",
@@ -189,13 +190,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.setkey = sun8i_ss_aes_setkey,
.encrypt = sun8i_ss_skencrypt,
.decrypt = sun8i_ss_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ss_handle_cipher_request,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ss_algo_id = SS_ID_CIPHER_AES,
.ss_blockmode = SS_ID_OP_ECB,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-sun8i-ss",
@@ -215,13 +219,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.setkey = sun8i_ss_aes_setkey,
.encrypt = sun8i_ss_skencrypt,
.decrypt = sun8i_ss_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ss_handle_cipher_request,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ss_algo_id = SS_ID_CIPHER_DES3,
.ss_blockmode = SS_ID_OP_CBC,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-des3-sun8i-ss",
@@ -242,13 +249,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.setkey = sun8i_ss_des3_setkey,
.encrypt = sun8i_ss_skencrypt,
.decrypt = sun8i_ss_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ss_handle_cipher_request,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.ss_algo_id = SS_ID_CIPHER_DES3,
.ss_blockmode = SS_ID_OP_ECB,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3-sun8i-ss",
@@ -268,7 +278,10 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.setkey = sun8i_ss_des3_setkey,
.encrypt = sun8i_ss_skencrypt,
.decrypt = sun8i_ss_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sun8i_ss_handle_cipher_request,
+ },
},
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_PRNG
{
@@ -292,7 +305,7 @@ static struct sun8i_ss_alg_template ss_algs[] = {
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_HASH
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ss_algo_id = SS_ID_HASH_MD5,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ss_hash_init,
.update = sun8i_ss_hash_update,
.final = sun8i_ss_hash_final,
@@ -300,6 +313,8 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.digest = sun8i_ss_hash_digest,
.export = sun8i_ss_hash_export,
.import = sun8i_ss_hash_import,
+ .init_tfm = sun8i_ss_hash_init_tfm,
+ .exit_tfm = sun8i_ss_hash_exit_tfm,
.halg = {
.digestsize = MD5_DIGEST_SIZE,
.statesize = sizeof(struct md5_state),
@@ -314,15 +329,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ss_hash_crainit,
- .cra_exit = sun8i_ss_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ss_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ss_algo_id = SS_ID_HASH_SHA1,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ss_hash_init,
.update = sun8i_ss_hash_update,
.final = sun8i_ss_hash_final,
@@ -330,6 +346,8 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.digest = sun8i_ss_hash_digest,
.export = sun8i_ss_hash_export,
.import = sun8i_ss_hash_import,
+ .init_tfm = sun8i_ss_hash_init_tfm,
+ .exit_tfm = sun8i_ss_hash_exit_tfm,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.statesize = sizeof(struct sha1_state),
@@ -344,15 +362,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ss_hash_crainit,
- .cra_exit = sun8i_ss_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ss_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ss_algo_id = SS_ID_HASH_SHA224,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ss_hash_init,
.update = sun8i_ss_hash_update,
.final = sun8i_ss_hash_final,
@@ -360,6 +379,8 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.digest = sun8i_ss_hash_digest,
.export = sun8i_ss_hash_export,
.import = sun8i_ss_hash_import,
+ .init_tfm = sun8i_ss_hash_init_tfm,
+ .exit_tfm = sun8i_ss_hash_exit_tfm,
.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
@@ -374,15 +395,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ss_hash_crainit,
- .cra_exit = sun8i_ss_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ss_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ss_algo_id = SS_ID_HASH_SHA256,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ss_hash_init,
.update = sun8i_ss_hash_update,
.final = sun8i_ss_hash_final,
@@ -390,6 +412,8 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.digest = sun8i_ss_hash_digest,
.export = sun8i_ss_hash_export,
.import = sun8i_ss_hash_import,
+ .init_tfm = sun8i_ss_hash_init_tfm,
+ .exit_tfm = sun8i_ss_hash_exit_tfm,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
@@ -404,15 +428,16 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ss_hash_crainit,
- .cra_exit = sun8i_ss_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ss_hash_run,
+ },
},
{ .type = CRYPTO_ALG_TYPE_AHASH,
.ss_algo_id = SS_ID_HASH_SHA1,
- .alg.hash = {
+ .alg.hash.base = {
.init = sun8i_ss_hash_init,
.update = sun8i_ss_hash_update,
.final = sun8i_ss_hash_final,
@@ -420,6 +445,8 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.digest = sun8i_ss_hash_digest,
.export = sun8i_ss_hash_export,
.import = sun8i_ss_hash_import,
+ .init_tfm = sun8i_ss_hash_init_tfm,
+ .exit_tfm = sun8i_ss_hash_exit_tfm,
.setkey = sun8i_ss_hmac_setkey,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
@@ -435,23 +462,28 @@ static struct sun8i_ss_alg_template ss_algs[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct sun8i_ss_hash_tfm_ctx),
.cra_module = THIS_MODULE,
- .cra_init = sun8i_ss_hash_crainit,
- .cra_exit = sun8i_ss_hash_craexit,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = sun8i_ss_hash_run,
+ },
},
#endif
};
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)
{
- struct sun8i_ss_dev *ss = seq->private;
+ struct sun8i_ss_dev *ss __maybe_unused = seq->private;
unsigned int i;
for (i = 0; i < MAXFLOW; i++)
- seq_printf(seq, "Channel %d: nreq %lu\n", i, ss->flows[i].stat_req);
+ seq_printf(seq, "Channel %d: nreq %lu\n", i,
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
+ ss->flows[i].stat_req);
+#else
+ 0ul);
+#endif
for (i = 0; i < ARRAY_SIZE(ss_algs); i++) {
if (!ss_algs[i].ss)
@@ -459,8 +491,8 @@ static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)
switch (ss_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- ss_algs[i].alg.skcipher.base.cra_driver_name,
- ss_algs[i].alg.skcipher.base.cra_name,
+ ss_algs[i].alg.skcipher.base.base.cra_driver_name,
+ ss_algs[i].alg.skcipher.base.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
@@ -482,8 +514,8 @@ static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)
break;
case CRYPTO_ALG_TYPE_AHASH:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- ss_algs[i].alg.hash.halg.base.cra_driver_name,
- ss_algs[i].alg.hash.halg.base.cra_name,
+ ss_algs[i].alg.hash.base.halg.base.cra_driver_name,
+ ss_algs[i].alg.hash.base.halg.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
ss_algs[i].fbname);
@@ -502,7 +534,6 @@ static int sun8i_ss_debugfs_show(struct seq_file *seq, void *v)
}
DEFINE_SHOW_ATTRIBUTE(sun8i_ss_debugfs);
-#endif
static void sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)
{
@@ -659,7 +690,7 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
if (ss_method == SS_ID_NOTSUPP) {
dev_info(ss->dev,
"DEBUG: Algo of %s not supported\n",
- ss_algs[i].alg.skcipher.base.cra_name);
+ ss_algs[i].alg.skcipher.base.base.cra_name);
ss_algs[i].ss = NULL;
break;
}
@@ -667,16 +698,16 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
ss_method = ss->variant->op_mode[id];
if (ss_method == SS_ID_NOTSUPP) {
dev_info(ss->dev, "DEBUG: Blockmode of %s not supported\n",
- ss_algs[i].alg.skcipher.base.cra_name);
+ ss_algs[i].alg.skcipher.base.base.cra_name);
ss_algs[i].ss = NULL;
break;
}
dev_info(ss->dev, "DEBUG: Register %s\n",
- ss_algs[i].alg.skcipher.base.cra_name);
- err = crypto_register_skcipher(&ss_algs[i].alg.skcipher);
+ ss_algs[i].alg.skcipher.base.base.cra_name);
+ err = crypto_engine_register_skcipher(&ss_algs[i].alg.skcipher);
if (err) {
dev_err(ss->dev, "Fail to register %s\n",
- ss_algs[i].alg.skcipher.base.cra_name);
+ ss_algs[i].alg.skcipher.base.base.cra_name);
ss_algs[i].ss = NULL;
return err;
}
@@ -695,16 +726,16 @@ static int sun8i_ss_register_algs(struct sun8i_ss_dev *ss)
if (ss_method == SS_ID_NOTSUPP) {
dev_info(ss->dev,
"DEBUG: Algo of %s not supported\n",
- ss_algs[i].alg.hash.halg.base.cra_name);
+ ss_algs[i].alg.hash.base.halg.base.cra_name);
ss_algs[i].ss = NULL;
break;
}
dev_info(ss->dev, "Register %s\n",
- ss_algs[i].alg.hash.halg.base.cra_name);
- err = crypto_register_ahash(&ss_algs[i].alg.hash);
+ ss_algs[i].alg.hash.base.halg.base.cra_name);
+ err = crypto_engine_register_ahash(&ss_algs[i].alg.hash);
if (err) {
dev_err(ss->dev, "ERROR: Fail to register %s\n",
- ss_algs[i].alg.hash.halg.base.cra_name);
+ ss_algs[i].alg.hash.base.halg.base.cra_name);
ss_algs[i].ss = NULL;
return err;
}
@@ -727,8 +758,8 @@ static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)
switch (ss_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(ss->dev, "Unregister %d %s\n", i,
- ss_algs[i].alg.skcipher.base.cra_name);
- crypto_unregister_skcipher(&ss_algs[i].alg.skcipher);
+ ss_algs[i].alg.skcipher.base.base.cra_name);
+ crypto_engine_unregister_skcipher(&ss_algs[i].alg.skcipher);
break;
case CRYPTO_ALG_TYPE_RNG:
dev_info(ss->dev, "Unregister %d %s\n", i,
@@ -737,8 +768,8 @@ static void sun8i_ss_unregister_algs(struct sun8i_ss_dev *ss)
break;
case CRYPTO_ALG_TYPE_AHASH:
dev_info(ss->dev, "Unregister %d %s\n", i,
- ss_algs[i].alg.hash.halg.base.cra_name);
- crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ ss_algs[i].alg.hash.base.halg.base.cra_name);
+ crypto_engine_unregister_ahash(&ss_algs[i].alg.hash);
break;
}
}
@@ -851,13 +882,21 @@ static int sun8i_ss_probe(struct platform_device *pdev)
pm_runtime_put_sync(ss->dev);
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {
+ struct dentry *dbgfs_dir __maybe_unused;
+ struct dentry *dbgfs_stats __maybe_unused;
+
+ /* Ignore error of debugfs */
+ dbgfs_dir = debugfs_create_dir("sun8i-ss", NULL);
+ dbgfs_stats = debugfs_create_file("stats", 0444,
+ dbgfs_dir, ss,
+ &sun8i_ss_debugfs_fops);
+
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- /* Ignore error of debugfs */
- ss->dbgfs_dir = debugfs_create_dir("sun8i-ss", NULL);
- ss->dbgfs_stats = debugfs_create_file("stats", 0444,
- ss->dbgfs_dir, ss,
- &sun8i_ss_debugfs_fops);
+ ss->dbgfs_dir = dbgfs_dir;
+ ss->dbgfs_stats = dbgfs_stats;
#endif
+ }
return 0;
error_alg:
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
index a4b67d130d11..d70b105dcfa1 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
@@ -9,16 +9,21 @@
*
* You could find the datasheet in Documentation/arch/arm/sunxi.rst
*/
-#include <linux/bottom_half.h>
-#include <linux/dma-mapping.h>
-#include <linux/pm_runtime.h>
-#include <linux/scatterlist.h>
-#include <crypto/internal/hash.h>
+
#include <crypto/hmac.h>
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
#include <crypto/scatterwalk.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
-#include <crypto/md5.h>
+#include <linux/bottom_half.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include "sun8i-ss.h"
static int sun8i_ss_hashkey(struct sun8i_ss_hash_tfm_ctx *tfmctx, const u8 *key,
@@ -60,14 +65,11 @@ int sun8i_ss_hmac_setkey(struct crypto_ahash *ahash, const u8 *key,
unsigned int keylen)
{
struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(ahash);
- struct ahash_alg *alg = __crypto_ahash_alg(ahash->base.__crt_alg);
- struct sun8i_ss_alg_template *algt;
int digestsize, i;
int bs = crypto_ahash_blocksize(ahash);
int ret;
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
- digestsize = algt->alg.hash.halg.digestsize;
+ digestsize = crypto_ahash_digestsize(ahash);
if (keylen > bs) {
ret = sun8i_ss_hashkey(tfmctx, key, keylen);
@@ -107,38 +109,33 @@ err_opad:
return ret;
}
-int sun8i_ss_hash_crainit(struct crypto_tfm *tfm)
+int sun8i_ss_hash_init_tfm(struct crypto_ahash *tfm)
{
- struct sun8i_ss_hash_tfm_ctx *op = crypto_tfm_ctx(tfm);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+ struct sun8i_ss_hash_tfm_ctx *op = crypto_ahash_ctx(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
struct sun8i_ss_alg_template *algt;
int err;
- memset(op, 0, sizeof(struct sun8i_ss_hash_tfm_ctx));
-
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);
op->ss = algt->ss;
- op->enginectx.op.do_one_request = sun8i_ss_hash_run;
- op->enginectx.op.prepare_request = NULL;
- op->enginectx.op.unprepare_request = NULL;
-
/* FALLBACK */
- op->fallback_tfm = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
+ op->fallback_tfm = crypto_alloc_ahash(crypto_ahash_alg_name(tfm), 0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(op->fallback_tfm)) {
dev_err(algt->ss->dev, "Fallback driver could no be loaded\n");
return PTR_ERR(op->fallback_tfm);
}
- if (algt->alg.hash.halg.statesize < crypto_ahash_statesize(op->fallback_tfm))
- algt->alg.hash.halg.statesize = crypto_ahash_statesize(op->fallback_tfm);
+ crypto_ahash_set_statesize(tfm,
+ crypto_ahash_statesize(op->fallback_tfm));
- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ crypto_ahash_set_reqsize(tfm,
sizeof(struct sun8i_ss_hash_reqctx) +
crypto_ahash_reqsize(op->fallback_tfm));
- memcpy(algt->fbname, crypto_tfm_alg_driver_name(&op->fallback_tfm->base), CRYPTO_MAX_ALG_NAME);
+ memcpy(algt->fbname, crypto_ahash_driver_name(op->fallback_tfm),
+ CRYPTO_MAX_ALG_NAME);
err = pm_runtime_get_sync(op->ss->dev);
if (err < 0)
@@ -150,9 +147,9 @@ error_pm:
return err;
}
-void sun8i_ss_hash_craexit(struct crypto_tfm *tfm)
+void sun8i_ss_hash_exit_tfm(struct crypto_ahash *tfm)
{
- struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_tfm_ctx(tfm);
+ struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
kfree_sensitive(tfmctx->ipad);
kfree_sensitive(tfmctx->opad);
@@ -204,20 +201,23 @@ int sun8i_ss_hash_final(struct ahash_request *areq)
struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ss_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
CRYPTO_TFM_REQ_MAY_SLEEP;
rctx->fallback_req.result = areq->result;
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct sun8i_ss_alg_template *algt __maybe_unused;
+
+ algt = container_of(alg, struct sun8i_ss_alg_template,
+ alg.hash.base);
+
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_final(&rctx->fallback_req);
}
@@ -242,10 +242,6 @@ int sun8i_ss_hash_finup(struct ahash_request *areq)
struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ss_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
@@ -254,10 +250,18 @@ int sun8i_ss_hash_finup(struct ahash_request *areq)
rctx->fallback_req.nbytes = areq->nbytes;
rctx->fallback_req.src = areq->src;
rctx->fallback_req.result = areq->result;
+
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct sun8i_ss_alg_template *algt __maybe_unused;
+
+ algt = container_of(alg, struct sun8i_ss_alg_template,
+ alg.hash.base);
+
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_finup(&rctx->fallback_req);
}
@@ -267,10 +271,6 @@ static int sun8i_ss_hash_digest_fb(struct ahash_request *areq)
struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct sun8i_ss_alg_template *algt;
-#endif
ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
rctx->fallback_req.base.flags = areq->base.flags &
@@ -279,10 +279,18 @@ static int sun8i_ss_hash_digest_fb(struct ahash_request *areq)
rctx->fallback_req.nbytes = areq->nbytes;
rctx->fallback_req.src = areq->src;
rctx->fallback_req.result = areq->result;
+
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG)) {
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct sun8i_ss_alg_template *algt __maybe_unused;
+
+ algt = container_of(alg, struct sun8i_ss_alg_template,
+ alg.hash.base);
+
#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
- algt->stat_fb++;
+ algt->stat_fb++;
#endif
+ }
return crypto_ahash_digest(&rctx->fallback_req);
}
@@ -349,11 +357,11 @@ static int sun8i_ss_run_hash_task(struct sun8i_ss_dev *ss,
static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
struct sun8i_ss_alg_template *algt;
struct scatterlist *sg;
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);
if (areq->nbytes == 0) {
algt->stat_fb_len++;
@@ -398,8 +406,8 @@ static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)
int sun8i_ss_hash_digest(struct ahash_request *areq)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
struct sun8i_ss_alg_template *algt;
struct sun8i_ss_dev *ss;
struct crypto_engine *engine;
@@ -408,7 +416,7 @@ int sun8i_ss_hash_digest(struct ahash_request *areq)
if (sun8i_ss_hash_need_fallback(areq))
return sun8i_ss_hash_digest_fb(areq);
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);
ss = algt->ss;
e = sun8i_ss_get_engine_number(ss);
@@ -484,8 +492,8 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
struct ahash_request *areq = container_of(breq, struct ahash_request, base);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct sun8i_ss_hash_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
struct sun8i_ss_hash_reqctx *rctx = ahash_request_ctx(areq);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
struct sun8i_ss_alg_template *algt;
struct sun8i_ss_dev *ss;
struct scatterlist *sg;
@@ -504,10 +512,10 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
*/
int hmac = 0;
- algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash);
+ algt = container_of(alg, struct sun8i_ss_alg_template, alg.hash.base);
ss = algt->ss;
- digestsize = algt->alg.hash.halg.digestsize;
+ digestsize = crypto_ahash_digestsize(tfm);
if (digestsize == SHA224_DIGEST_SIZE)
digestsize = SHA256_DIGEST_SIZE;
@@ -700,7 +708,7 @@ err_dma_result:
}
if (!err)
- memcpy(areq->result, result, algt->alg.hash.halg.digestsize);
+ memcpy(areq->result, result, crypto_ahash_digestsize(tfm));
theend:
local_bh_disable();
crypto_finalize_hash_request(engine, breq, err);
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h
index df6f08f6092f..ae66eb45fb24 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss.h
@@ -201,16 +201,12 @@ struct sun8i_cipher_req_ctx {
/*
* struct sun8i_cipher_tfm_ctx - context for a skcipher TFM
- * @enginectx: crypto_engine used by this TFM
* @key: pointer to key data
* @keylen: len of the key
* @ss: pointer to the private data of driver handling this TFM
* @fallback_tfm: pointer to the fallback TFM
- *
- * enginectx must be the first element
*/
struct sun8i_cipher_tfm_ctx {
- struct crypto_engine_ctx enginectx;
u32 *key;
u32 keylen;
struct sun8i_ss_dev *ss;
@@ -229,14 +225,10 @@ struct sun8i_ss_rng_tfm_ctx {
/*
* struct sun8i_ss_hash_tfm_ctx - context for an ahash TFM
- * @enginectx: crypto_engine used by this TFM
* @fallback_tfm: pointer to the fallback TFM
* @ss: pointer to the private data of driver handling this TFM
- *
- * enginectx must be the first element
*/
struct sun8i_ss_hash_tfm_ctx {
- struct crypto_engine_ctx enginectx;
struct crypto_ahash *fallback_tfm;
struct sun8i_ss_dev *ss;
u8 *ipad;
@@ -279,9 +271,9 @@ struct sun8i_ss_alg_template {
u32 ss_blockmode;
struct sun8i_ss_dev *ss;
union {
- struct skcipher_alg skcipher;
+ struct skcipher_engine_alg skcipher;
struct rng_alg rng;
- struct ahash_alg hash;
+ struct ahash_engine_alg hash;
} alg;
unsigned long stat_req;
unsigned long stat_fb;
@@ -293,14 +285,13 @@ struct sun8i_ss_alg_template {
char fbname[CRYPTO_MAX_ALG_NAME];
};
-int sun8i_ss_enqueue(struct crypto_async_request *areq, u32 type);
-
int sun8i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun8i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun8i_ss_cipher_init(struct crypto_tfm *tfm);
void sun8i_ss_cipher_exit(struct crypto_tfm *tfm);
+int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *areq);
int sun8i_ss_skdecrypt(struct skcipher_request *areq);
int sun8i_ss_skencrypt(struct skcipher_request *areq);
@@ -313,8 +304,8 @@ int sun8i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen
int sun8i_ss_prng_init(struct crypto_tfm *tfm);
void sun8i_ss_prng_exit(struct crypto_tfm *tfm);
-int sun8i_ss_hash_crainit(struct crypto_tfm *tfm);
-void sun8i_ss_hash_craexit(struct crypto_tfm *tfm);
+int sun8i_ss_hash_init_tfm(struct crypto_ahash *tfm);
+void sun8i_ss_hash_exit_tfm(struct crypto_ahash *tfm);
int sun8i_ss_hash_init(struct ahash_request *areq);
int sun8i_ss_hash_export(struct ahash_request *areq, void *out);
int sun8i_ss_hash_import(struct ahash_request *areq, const void *in);
diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c
index af017a087ebf..3308406612fc 100644
--- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c
+++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c
@@ -65,7 +65,7 @@ static int meson_cipher_do_fallback(struct skcipher_request *areq)
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
struct meson_alg_template *algt;
- algt = container_of(alg, struct meson_alg_template, alg.skcipher);
+ algt = container_of(alg, struct meson_alg_template, alg.skcipher.base);
algt->stat_fb++;
#endif
skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
@@ -101,7 +101,7 @@ static int meson_cipher(struct skcipher_request *areq)
void *backup_iv = NULL, *bkeyiv;
u32 v;
- algt = container_of(alg, struct meson_alg_template, alg.skcipher);
+ algt = container_of(alg, struct meson_alg_template, alg.skcipher.base);
dev_dbg(mc->dev, "%s %s %u %x IV(%u) key=%u flow=%d\n", __func__,
crypto_tfm_alg_name(areq->base.tfm),
@@ -258,8 +258,7 @@ theend:
return err;
}
-static int meson_handle_cipher_request(struct crypto_engine *engine,
- void *areq)
+int meson_handle_cipher_request(struct crypto_engine *engine, void *areq)
{
int err;
struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
@@ -318,7 +317,7 @@ int meson_cipher_init(struct crypto_tfm *tfm)
memset(op, 0, sizeof(struct meson_cipher_tfm_ctx));
- algt = container_of(alg, struct meson_alg_template, alg.skcipher);
+ algt = container_of(alg, struct meson_alg_template, alg.skcipher.base);
op->mc = algt->mc;
op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
@@ -331,10 +330,6 @@ int meson_cipher_init(struct crypto_tfm *tfm)
sktfm->reqsize = sizeof(struct meson_cipher_req_ctx) +
crypto_skcipher_reqsize(op->fallback_tfm);
- op->enginectx.op.do_one_request = meson_handle_cipher_request;
- op->enginectx.op.prepare_request = NULL;
- op->enginectx.op.unprepare_request = NULL;
-
return 0;
}
diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c
index 937187027ad5..da6dfe0f9ac3 100644
--- a/drivers/crypto/amlogic/amlogic-gxl-core.c
+++ b/drivers/crypto/amlogic/amlogic-gxl-core.c
@@ -6,17 +6,19 @@
*
* Core file which registers crypto algorithms supported by the hardware.
*/
+
+#include <crypto/engine.h>
+#include <crypto/internal/skcipher.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
-#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <crypto/internal/skcipher.h>
-#include <linux/dma-mapping.h>
#include "amlogic-gxl.h"
@@ -47,7 +49,7 @@ static struct meson_alg_template mc_algs[] = {
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.blockmode = MESON_OPMODE_CBC,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-gxl",
@@ -68,12 +70,15 @@ static struct meson_alg_template mc_algs[] = {
.setkey = meson_aes_setkey,
.encrypt = meson_skencrypt,
.decrypt = meson_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = meson_handle_cipher_request,
+ },
},
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.blockmode = MESON_OPMODE_ECB,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-gxl",
@@ -93,33 +98,43 @@ static struct meson_alg_template mc_algs[] = {
.setkey = meson_aes_setkey,
.encrypt = meson_skencrypt,
.decrypt = meson_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = meson_handle_cipher_request,
+ },
},
};
-#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
static int meson_debugfs_show(struct seq_file *seq, void *v)
{
- struct meson_dev *mc = seq->private;
+ struct meson_dev *mc __maybe_unused = seq->private;
int i;
for (i = 0; i < MAXFLOW; i++)
- seq_printf(seq, "Channel %d: nreq %lu\n", i, mc->chanlist[i].stat_req);
+ seq_printf(seq, "Channel %d: nreq %lu\n", i,
+#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
+ mc->chanlist[i].stat_req);
+#else
+ 0ul);
+#endif
for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
switch (mc_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s %lu %lu\n",
- mc_algs[i].alg.skcipher.base.cra_driver_name,
- mc_algs[i].alg.skcipher.base.cra_name,
+ mc_algs[i].alg.skcipher.base.base.cra_driver_name,
+ mc_algs[i].alg.skcipher.base.base.cra_name,
+#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
mc_algs[i].stat_req, mc_algs[i].stat_fb);
+#else
+ 0ul, 0ul);
+#endif
break;
}
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(meson_debugfs);
-#endif
static void meson_free_chanlist(struct meson_dev *mc, int i)
{
@@ -183,10 +198,10 @@ static int meson_register_algs(struct meson_dev *mc)
mc_algs[i].mc = mc;
switch (mc_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
- err = crypto_register_skcipher(&mc_algs[i].alg.skcipher);
+ err = crypto_engine_register_skcipher(&mc_algs[i].alg.skcipher);
if (err) {
dev_err(mc->dev, "Fail to register %s\n",
- mc_algs[i].alg.skcipher.base.cra_name);
+ mc_algs[i].alg.skcipher.base.base.cra_name);
mc_algs[i].mc = NULL;
return err;
}
@@ -206,7 +221,7 @@ static void meson_unregister_algs(struct meson_dev *mc)
continue;
switch (mc_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
- crypto_unregister_skcipher(&mc_algs[i].alg.skcipher);
+ crypto_engine_unregister_skcipher(&mc_algs[i].alg.skcipher);
break;
}
}
@@ -264,10 +279,16 @@ static int meson_crypto_probe(struct platform_device *pdev)
if (err)
goto error_alg;
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG)) {
+ struct dentry *dbgfs_dir;
+
+ dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
+ debugfs_create_file("stats", 0444, dbgfs_dir, mc, &meson_debugfs_fops);
+
#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
- mc->dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
- debugfs_create_file("stats", 0444, mc->dbgfs_dir, mc, &meson_debugfs_fops);
+ mc->dbgfs_dir = dbgfs_dir;
#endif
+ }
return 0;
error_alg:
diff --git a/drivers/crypto/amlogic/amlogic-gxl.h b/drivers/crypto/amlogic/amlogic-gxl.h
index 8c0746a1d6d4..1013a666c932 100644
--- a/drivers/crypto/amlogic/amlogic-gxl.h
+++ b/drivers/crypto/amlogic/amlogic-gxl.h
@@ -114,7 +114,6 @@ struct meson_cipher_req_ctx {
/*
* struct meson_cipher_tfm_ctx - context for a skcipher TFM
- * @enginectx: crypto_engine used by this TFM
* @key: pointer to key data
* @keylen: len of the key
* @keymode: The keymode(type and size of key) associated with this TFM
@@ -122,7 +121,6 @@ struct meson_cipher_req_ctx {
* @fallback_tfm: pointer to the fallback TFM
*/
struct meson_cipher_tfm_ctx {
- struct crypto_engine_ctx enginectx;
u32 *key;
u32 keylen;
u32 keymode;
@@ -143,7 +141,7 @@ struct meson_alg_template {
u32 type;
u32 blockmode;
union {
- struct skcipher_alg skcipher;
+ struct skcipher_engine_alg skcipher;
} alg;
struct meson_dev *mc;
#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
@@ -160,3 +158,4 @@ int meson_cipher_init(struct crypto_tfm *tfm);
void meson_cipher_exit(struct crypto_tfm *tfm);
int meson_skdecrypt(struct skcipher_request *areq);
int meson_skencrypt(struct skcipher_request *areq);
+int meson_handle_cipher_request(struct crypto_engine *engine, void *areq);
diff --git a/drivers/crypto/aspeed/aspeed-acry.c b/drivers/crypto/aspeed/aspeed-acry.c
index 470122c87fea..247c568aa8df 100644
--- a/drivers/crypto/aspeed/aspeed-acry.c
+++ b/drivers/crypto/aspeed/aspeed-acry.c
@@ -2,25 +2,23 @@
/*
* Copyright 2021 Aspeed Technology Inc.
*/
-#include <crypto/akcipher.h>
-#include <crypto/algapi.h>
#include <crypto/engine.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/rsa.h>
#include <crypto/scatterwalk.h>
#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/mfd/syscon.h>
-#include <linux/interrupt.h>
#include <linux/count_zeros.h>
-#include <linux/err.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
#define ACRY_DBG(d, fmt, ...) \
@@ -112,7 +110,6 @@ struct aspeed_acry_dev {
};
struct aspeed_acry_ctx {
- struct crypto_engine_ctx enginectx;
struct aspeed_acry_dev *acry_dev;
struct rsa_key key;
@@ -131,7 +128,7 @@ struct aspeed_acry_ctx {
struct aspeed_acry_alg {
struct aspeed_acry_dev *acry_dev;
- struct akcipher_alg akcipher;
+ struct akcipher_engine_alg akcipher;
};
enum aspeed_rsa_key_mode {
@@ -577,7 +574,7 @@ static int aspeed_acry_rsa_init_tfm(struct crypto_akcipher *tfm)
const char *name = crypto_tfm_alg_name(&tfm->base);
struct aspeed_acry_alg *acry_alg;
- acry_alg = container_of(alg, struct aspeed_acry_alg, akcipher);
+ acry_alg = container_of(alg, struct aspeed_acry_alg, akcipher.base);
ctx->acry_dev = acry_alg->acry_dev;
@@ -589,10 +586,6 @@ static int aspeed_acry_rsa_init_tfm(struct crypto_akcipher *tfm)
return PTR_ERR(ctx->fallback_tfm);
}
- ctx->enginectx.op.do_one_request = aspeed_acry_do_request;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -605,7 +598,7 @@ static void aspeed_acry_rsa_exit_tfm(struct crypto_akcipher *tfm)
static struct aspeed_acry_alg aspeed_acry_akcipher_algs[] = {
{
- .akcipher = {
+ .akcipher.base = {
.encrypt = aspeed_acry_rsa_enc,
.decrypt = aspeed_acry_rsa_dec,
.sign = aspeed_acry_rsa_dec,
@@ -627,6 +620,9 @@ static struct aspeed_acry_alg aspeed_acry_akcipher_algs[] = {
.cra_ctxsize = sizeof(struct aspeed_acry_ctx),
},
},
+ .akcipher.op = {
+ .do_one_request = aspeed_acry_do_request,
+ },
},
};
@@ -636,10 +632,10 @@ static void aspeed_acry_register(struct aspeed_acry_dev *acry_dev)
for (i = 0; i < ARRAY_SIZE(aspeed_acry_akcipher_algs); i++) {
aspeed_acry_akcipher_algs[i].acry_dev = acry_dev;
- rc = crypto_register_akcipher(&aspeed_acry_akcipher_algs[i].akcipher);
+ rc = crypto_engine_register_akcipher(&aspeed_acry_akcipher_algs[i].akcipher);
if (rc) {
ACRY_DBG(acry_dev, "Failed to register %s\n",
- aspeed_acry_akcipher_algs[i].akcipher.base.cra_name);
+ aspeed_acry_akcipher_algs[i].akcipher.base.base.cra_name);
}
}
}
@@ -649,7 +645,7 @@ static void aspeed_acry_unregister(struct aspeed_acry_dev *acry_dev)
int i;
for (i = 0; i < ARRAY_SIZE(aspeed_acry_akcipher_algs); i++)
- crypto_unregister_akcipher(&aspeed_acry_akcipher_algs[i].akcipher);
+ crypto_engine_unregister_akcipher(&aspeed_acry_akcipher_algs[i].akcipher);
}
/* ACRY interrupt service routine. */
diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/aspeed-hace-crypto.c
index ef73b0028b4d..f0eddb7854e5 100644
--- a/drivers/crypto/aspeed/aspeed-hace-crypto.c
+++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c
@@ -4,6 +4,17 @@
*/
#include "aspeed-hace.h"
+#include <crypto/des.h>
+#include <crypto/engine.h>
+#include <crypto/internal/des.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
#ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO_DEBUG
#define CIPHER_DBG(h, fmt, ...) \
@@ -696,7 +707,7 @@ static int aspeed_crypto_cra_init(struct crypto_skcipher *tfm)
struct aspeed_hace_alg *crypto_alg;
- crypto_alg = container_of(alg, struct aspeed_hace_alg, alg.skcipher);
+ crypto_alg = container_of(alg, struct aspeed_hace_alg, alg.skcipher.base);
ctx->hace_dev = crypto_alg->hace_dev;
ctx->start = aspeed_hace_skcipher_trigger;
@@ -713,10 +724,6 @@ static int aspeed_crypto_cra_init(struct crypto_skcipher *tfm)
crypto_skcipher_set_reqsize(tfm, sizeof(struct aspeed_cipher_reqctx) +
crypto_skcipher_reqsize(ctx->fallback_tfm));
- ctx->enginectx.op.do_one_request = aspeed_crypto_do_request;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -731,7 +738,7 @@ static void aspeed_crypto_cra_exit(struct crypto_skcipher *tfm)
static struct aspeed_hace_alg aspeed_crypto_algs[] = {
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.setkey = aspeed_aes_setkey,
@@ -751,10 +758,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = AES_BLOCK_SIZE,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
@@ -775,10 +785,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = AES_BLOCK_SIZE,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
@@ -799,10 +812,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = AES_BLOCK_SIZE,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
@@ -823,10 +839,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
.setkey = aspeed_des_setkey,
@@ -846,10 +865,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
@@ -870,10 +892,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
@@ -894,10 +919,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
@@ -918,10 +946,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
.setkey = aspeed_des_setkey,
@@ -941,10 +972,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
@@ -965,10 +999,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
@@ -989,10 +1026,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
@@ -1013,13 +1053,16 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
};
static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = {
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = AES_BLOCK_SIZE,
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
@@ -1039,10 +1082,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
@@ -1062,10 +1108,13 @@ static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
{
- .alg.skcipher = {
+ .alg.skcipher.base = {
.ivsize = DES_BLOCK_SIZE,
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
@@ -1085,7 +1134,10 @@ static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = {
.cra_alignmask = 0x0f,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = aspeed_crypto_do_request,
+ },
},
};
@@ -1095,13 +1147,13 @@ void aspeed_unregister_hace_crypto_algs(struct aspeed_hace_dev *hace_dev)
int i;
for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs); i++)
- crypto_unregister_skcipher(&aspeed_crypto_algs[i].alg.skcipher);
+ crypto_engine_unregister_skcipher(&aspeed_crypto_algs[i].alg.skcipher);
if (hace_dev->version != AST2600_VERSION)
return;
for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++)
- crypto_unregister_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher);
+ crypto_engine_unregister_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher);
}
void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev)
@@ -1112,10 +1164,10 @@ void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev)
for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs); i++) {
aspeed_crypto_algs[i].hace_dev = hace_dev;
- rc = crypto_register_skcipher(&aspeed_crypto_algs[i].alg.skcipher);
+ rc = crypto_engine_register_skcipher(&aspeed_crypto_algs[i].alg.skcipher);
if (rc) {
CIPHER_DBG(hace_dev, "Failed to register %s\n",
- aspeed_crypto_algs[i].alg.skcipher.base.cra_name);
+ aspeed_crypto_algs[i].alg.skcipher.base.base.cra_name);
}
}
@@ -1124,10 +1176,10 @@ void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev)
for (i = 0; i < ARRAY_SIZE(aspeed_crypto_algs_g6); i++) {
aspeed_crypto_algs_g6[i].hace_dev = hace_dev;
- rc = crypto_register_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher);
+ rc = crypto_engine_register_skcipher(&aspeed_crypto_algs_g6[i].alg.skcipher);
if (rc) {
CIPHER_DBG(hace_dev, "Failed to register %s\n",
- aspeed_crypto_algs_g6[i].alg.skcipher.base.cra_name);
+ aspeed_crypto_algs_g6[i].alg.skcipher.base.base.cra_name);
}
}
}
diff --git a/drivers/crypto/aspeed/aspeed-hace-hash.c b/drivers/crypto/aspeed/aspeed-hace-hash.c
index 935135229ebd..0b6e49c06eff 100644
--- a/drivers/crypto/aspeed/aspeed-hace-hash.c
+++ b/drivers/crypto/aspeed/aspeed-hace-hash.c
@@ -4,6 +4,17 @@
*/
#include "aspeed-hace.h"
+#include <crypto/engine.h>
+#include <crypto/hmac.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
#define AHASH_DBG(h, fmt, ...) \
@@ -48,28 +59,6 @@ static const __be64 sha512_iv[8] = {
cpu_to_be64(SHA512_H6), cpu_to_be64(SHA512_H7)
};
-static const __be32 sha512_224_iv[16] = {
- cpu_to_be32(0xC8373D8CUL), cpu_to_be32(0xA24D5419UL),
- cpu_to_be32(0x6699E173UL), cpu_to_be32(0xD6D4DC89UL),
- cpu_to_be32(0xAEB7FA1DUL), cpu_to_be32(0x829CFF32UL),
- cpu_to_be32(0x14D59D67UL), cpu_to_be32(0xCF9F2F58UL),
- cpu_to_be32(0x692B6D0FUL), cpu_to_be32(0xA84DD47BUL),
- cpu_to_be32(0x736FE377UL), cpu_to_be32(0x4289C404UL),
- cpu_to_be32(0xA8859D3FUL), cpu_to_be32(0xC8361D6AUL),
- cpu_to_be32(0xADE61211UL), cpu_to_be32(0xA192D691UL)
-};
-
-static const __be32 sha512_256_iv[16] = {
- cpu_to_be32(0x94213122UL), cpu_to_be32(0x2CF72BFCUL),
- cpu_to_be32(0xA35F559FUL), cpu_to_be32(0xC2644CC8UL),
- cpu_to_be32(0x6BB89323UL), cpu_to_be32(0x51B1536FUL),
- cpu_to_be32(0x19773896UL), cpu_to_be32(0xBDEA4059UL),
- cpu_to_be32(0xE23E2896UL), cpu_to_be32(0xE3FF8EA8UL),
- cpu_to_be32(0x251E5EBEUL), cpu_to_be32(0x92398653UL),
- cpu_to_be32(0xFC99012BUL), cpu_to_be32(0xAAB8852CUL),
- cpu_to_be32(0xDC2DB70EUL), cpu_to_be32(0xA22CC581UL)
-};
-
/* The purpose of this padding is to ensure that the padded message is a
* multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512).
* The bit "1" is appended at the end of the message followed by
@@ -565,8 +554,8 @@ static int aspeed_ahash_do_request(struct crypto_engine *engine, void *areq)
return 0;
}
-static int aspeed_ahash_prepare_request(struct crypto_engine *engine,
- void *areq)
+static void aspeed_ahash_prepare_request(struct crypto_engine *engine,
+ void *areq)
{
struct ahash_request *req = ahash_request_cast(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -581,8 +570,12 @@ static int aspeed_ahash_prepare_request(struct crypto_engine *engine,
hash_engine->dma_prepare = aspeed_ahash_dma_prepare_sg;
else
hash_engine->dma_prepare = aspeed_ahash_dma_prepare;
+}
- return 0;
+static int aspeed_ahash_do_one(struct crypto_engine *engine, void *areq)
+{
+ aspeed_ahash_prepare_request(engine, areq);
+ return aspeed_ahash_do_request(engine, areq);
}
static int aspeed_sham_update(struct ahash_request *req)
@@ -750,62 +743,6 @@ static int aspeed_sham_init(struct ahash_request *req)
return 0;
}
-static int aspeed_sha512s_init(struct ahash_request *req)
-{
- struct aspeed_sham_reqctx *rctx = ahash_request_ctx(req);
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct aspeed_sham_ctx *tctx = crypto_ahash_ctx(tfm);
- struct aspeed_hace_dev *hace_dev = tctx->hace_dev;
- struct aspeed_sha_hmac_ctx *bctx = tctx->base;
-
- AHASH_DBG(hace_dev, "digest size: %d\n", crypto_ahash_digestsize(tfm));
-
- rctx->cmd = HASH_CMD_ACC_MODE;
- rctx->flags = 0;
-
- switch (crypto_ahash_digestsize(tfm)) {
- case SHA224_DIGEST_SIZE:
- rctx->cmd |= HASH_CMD_SHA512_SER | HASH_CMD_SHA512_224 |
- HASH_CMD_SHA_SWAP;
- rctx->flags |= SHA_FLAGS_SHA512_224;
- rctx->digsize = SHA224_DIGEST_SIZE;
- rctx->block_size = SHA512_BLOCK_SIZE;
- rctx->sha_iv = sha512_224_iv;
- rctx->ivsize = 64;
- memcpy(rctx->digest, sha512_224_iv, rctx->ivsize);
- break;
- case SHA256_DIGEST_SIZE:
- rctx->cmd |= HASH_CMD_SHA512_SER | HASH_CMD_SHA512_256 |
- HASH_CMD_SHA_SWAP;
- rctx->flags |= SHA_FLAGS_SHA512_256;
- rctx->digsize = SHA256_DIGEST_SIZE;
- rctx->block_size = SHA512_BLOCK_SIZE;
- rctx->sha_iv = sha512_256_iv;
- rctx->ivsize = 64;
- memcpy(rctx->digest, sha512_256_iv, rctx->ivsize);
- break;
- default:
- dev_warn(tctx->hace_dev->dev, "digest size %d not support\n",
- crypto_ahash_digestsize(tfm));
- return -EINVAL;
- }
-
- rctx->bufcnt = 0;
- rctx->total = 0;
- rctx->digcnt[0] = 0;
- rctx->digcnt[1] = 0;
-
- /* HMAC init */
- if (tctx->flags & SHA_FLAGS_HMAC) {
- rctx->digcnt[0] = rctx->block_size;
- rctx->bufcnt = rctx->block_size;
- memcpy(rctx->buffer, bctx->ipad, rctx->block_size);
- rctx->flags |= SHA_FLAGS_HMAC;
- }
-
- return 0;
-}
-
static int aspeed_sham_digest(struct ahash_request *req)
{
return aspeed_sham_init(req) ? : aspeed_sham_finup(req);
@@ -854,7 +791,7 @@ static int aspeed_sham_cra_init(struct crypto_tfm *tfm)
struct aspeed_sham_ctx *tctx = crypto_tfm_ctx(tfm);
struct aspeed_hace_alg *ast_alg;
- ast_alg = container_of(alg, struct aspeed_hace_alg, alg.ahash);
+ ast_alg = container_of(alg, struct aspeed_hace_alg, alg.ahash.base);
tctx->hace_dev = ast_alg->hace_dev;
tctx->flags = 0;
@@ -876,10 +813,6 @@ static int aspeed_sham_cra_init(struct crypto_tfm *tfm)
}
}
- tctx->enginectx.op.do_one_request = aspeed_ahash_do_request;
- tctx->enginectx.op.prepare_request = aspeed_ahash_prepare_request;
- tctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -917,7 +850,7 @@ static int aspeed_sham_import(struct ahash_request *req, const void *in)
static struct aspeed_hace_alg aspeed_ahash_algs[] = {
{
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -944,9 +877,12 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -973,9 +909,12 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1002,10 +941,13 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
.alg_base = "sha1",
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1034,10 +976,13 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
.alg_base = "sha224",
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1066,10 +1011,13 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
.alg_base = "sha256",
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1098,12 +1046,15 @@ static struct aspeed_hace_alg aspeed_ahash_algs[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
};
static struct aspeed_hace_alg aspeed_ahash_algs_g6[] = {
{
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1130,9 +1081,12 @@ static struct aspeed_hace_alg aspeed_ahash_algs_g6[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1159,68 +1113,13 @@ static struct aspeed_hace_alg aspeed_ahash_algs_g6[] = {
}
}
},
- },
- {
- .alg.ahash = {
- .init = aspeed_sha512s_init,
- .update = aspeed_sham_update,
- .final = aspeed_sham_final,
- .finup = aspeed_sham_finup,
- .digest = aspeed_sham_digest,
- .export = aspeed_sham_export,
- .import = aspeed_sham_import,
- .halg = {
- .digestsize = SHA224_DIGEST_SIZE,
- .statesize = sizeof(struct aspeed_sham_reqctx),
- .base = {
- .cra_name = "sha512_224",
- .cra_driver_name = "aspeed-sha512_224",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct aspeed_sham_ctx),
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_init = aspeed_sham_cra_init,
- .cra_exit = aspeed_sham_cra_exit,
- }
- }
- },
- },
- {
- .alg.ahash = {
- .init = aspeed_sha512s_init,
- .update = aspeed_sham_update,
- .final = aspeed_sham_final,
- .finup = aspeed_sham_finup,
- .digest = aspeed_sham_digest,
- .export = aspeed_sham_export,
- .import = aspeed_sham_import,
- .halg = {
- .digestsize = SHA256_DIGEST_SIZE,
- .statesize = sizeof(struct aspeed_sham_reqctx),
- .base = {
- .cra_name = "sha512_256",
- .cra_driver_name = "aspeed-sha512_256",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct aspeed_sham_ctx),
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_init = aspeed_sham_cra_init,
- .cra_exit = aspeed_sham_cra_exit,
- }
- }
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
},
},
{
.alg_base = "sha384",
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1249,10 +1148,13 @@ static struct aspeed_hace_alg aspeed_ahash_algs_g6[] = {
}
}
},
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
+ },
},
{
.alg_base = "sha512",
- .alg.ahash = {
+ .alg.ahash.base = {
.init = aspeed_sham_init,
.update = aspeed_sham_update,
.final = aspeed_sham_final,
@@ -1281,69 +1183,8 @@ static struct aspeed_hace_alg aspeed_ahash_algs_g6[] = {
}
}
},
- },
- {
- .alg_base = "sha512_224",
- .alg.ahash = {
- .init = aspeed_sha512s_init,
- .update = aspeed_sham_update,
- .final = aspeed_sham_final,
- .finup = aspeed_sham_finup,
- .digest = aspeed_sham_digest,
- .setkey = aspeed_sham_setkey,
- .export = aspeed_sham_export,
- .import = aspeed_sham_import,
- .halg = {
- .digestsize = SHA224_DIGEST_SIZE,
- .statesize = sizeof(struct aspeed_sham_reqctx),
- .base = {
- .cra_name = "hmac(sha512_224)",
- .cra_driver_name = "aspeed-hmac-sha512_224",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct aspeed_sham_ctx) +
- sizeof(struct aspeed_sha_hmac_ctx),
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_init = aspeed_sham_cra_init,
- .cra_exit = aspeed_sham_cra_exit,
- }
- }
- },
- },
- {
- .alg_base = "sha512_256",
- .alg.ahash = {
- .init = aspeed_sha512s_init,
- .update = aspeed_sham_update,
- .final = aspeed_sham_final,
- .finup = aspeed_sham_finup,
- .digest = aspeed_sham_digest,
- .setkey = aspeed_sham_setkey,
- .export = aspeed_sham_export,
- .import = aspeed_sham_import,
- .halg = {
- .digestsize = SHA256_DIGEST_SIZE,
- .statesize = sizeof(struct aspeed_sham_reqctx),
- .base = {
- .cra_name = "hmac(sha512_256)",
- .cra_driver_name = "aspeed-hmac-sha512_256",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct aspeed_sham_ctx) +
- sizeof(struct aspeed_sha_hmac_ctx),
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_init = aspeed_sham_cra_init,
- .cra_exit = aspeed_sham_cra_exit,
- }
- }
+ .alg.ahash.op = {
+ .do_one_request = aspeed_ahash_do_one,
},
},
};
@@ -1353,13 +1194,13 @@ void aspeed_unregister_hace_hash_algs(struct aspeed_hace_dev *hace_dev)
int i;
for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs); i++)
- crypto_unregister_ahash(&aspeed_ahash_algs[i].alg.ahash);
+ crypto_engine_unregister_ahash(&aspeed_ahash_algs[i].alg.ahash);
if (hace_dev->version != AST2600_VERSION)
return;
for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++)
- crypto_unregister_ahash(&aspeed_ahash_algs_g6[i].alg.ahash);
+ crypto_engine_unregister_ahash(&aspeed_ahash_algs_g6[i].alg.ahash);
}
void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev)
@@ -1370,10 +1211,10 @@ void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev)
for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs); i++) {
aspeed_ahash_algs[i].hace_dev = hace_dev;
- rc = crypto_register_ahash(&aspeed_ahash_algs[i].alg.ahash);
+ rc = crypto_engine_register_ahash(&aspeed_ahash_algs[i].alg.ahash);
if (rc) {
AHASH_DBG(hace_dev, "Failed to register %s\n",
- aspeed_ahash_algs[i].alg.ahash.halg.base.cra_name);
+ aspeed_ahash_algs[i].alg.ahash.base.halg.base.cra_name);
}
}
@@ -1382,10 +1223,10 @@ void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev)
for (i = 0; i < ARRAY_SIZE(aspeed_ahash_algs_g6); i++) {
aspeed_ahash_algs_g6[i].hace_dev = hace_dev;
- rc = crypto_register_ahash(&aspeed_ahash_algs_g6[i].alg.ahash);
+ rc = crypto_engine_register_ahash(&aspeed_ahash_algs_g6[i].alg.ahash);
if (rc) {
AHASH_DBG(hace_dev, "Failed to register %s\n",
- aspeed_ahash_algs_g6[i].alg.ahash.halg.base.cra_name);
+ aspeed_ahash_algs_g6[i].alg.ahash.base.halg.base.cra_name);
}
}
}
diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed-hace.c
index d2871e1de9c2..8f7aab82e1d8 100644
--- a/drivers/crypto/aspeed/aspeed-hace.c
+++ b/drivers/crypto/aspeed/aspeed-hace.c
@@ -3,7 +3,14 @@
* Copyright (c) 2021 Aspeed Technology Inc.
*/
+#include "aspeed-hace.h"
+#include <crypto/engine.h>
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -11,8 +18,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
-#include "aspeed-hace.h"
-
#ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
#define HACE_DBG(d, fmt, ...) \
dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__)
diff --git a/drivers/crypto/aspeed/aspeed-hace.h b/drivers/crypto/aspeed/aspeed-hace.h
index 05d0a15d546d..68f70e01fccb 100644
--- a/drivers/crypto/aspeed/aspeed-hace.h
+++ b/drivers/crypto/aspeed/aspeed-hace.h
@@ -2,25 +2,14 @@
#ifndef __ASPEED_HACE_H__
#define __ASPEED_HACE_H__
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/fips.h>
-#include <linux/dma-mapping.h>
#include <crypto/aes.h>
-#include <crypto/des.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/internal/aead.h>
-#include <crypto/internal/akcipher.h>
-#include <crypto/internal/des.h>
-#include <crypto/internal/hash.h>
-#include <crypto/internal/kpp.h>
-#include <crypto/internal/skcipher.h>
-#include <crypto/algapi.h>
#include <crypto/engine.h>
-#include <crypto/hmac.h>
-#include <crypto/sha1.h>
+#include <crypto/hash.h>
#include <crypto/sha2.h>
+#include <linux/bits.h>
+#include <linux/compiler_attributes.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
/*****************************
* *
@@ -144,6 +133,7 @@
HACE_CMD_OFB | HACE_CMD_CTR)
struct aspeed_hace_dev;
+struct scatterlist;
typedef int (*aspeed_hace_fn_t)(struct aspeed_hace_dev *);
@@ -178,8 +168,6 @@ struct aspeed_sha_hmac_ctx {
};
struct aspeed_sham_ctx {
- struct crypto_engine_ctx enginectx;
-
struct aspeed_hace_dev *hace_dev;
unsigned long flags; /* hmac flag */
@@ -235,8 +223,6 @@ struct aspeed_engine_crypto {
};
struct aspeed_cipher_ctx {
- struct crypto_engine_ctx enginectx;
-
struct aspeed_hace_dev *hace_dev;
int key_len;
u8 key[AES_MAX_KEYLENGTH];
@@ -275,8 +261,8 @@ struct aspeed_hace_alg {
const char *alg_base;
union {
- struct skcipher_alg skcipher;
- struct ahash_alg ahash;
+ struct skcipher_engine_alg skcipher;
+ struct ahash_engine_alg ahash;
} alg;
};
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 143d33fbb316..55b5f577b01c 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -28,7 +28,7 @@
#include <linux/irq.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/crypto.h>
#include <crypto/scatterwalk.h>
@@ -2533,13 +2533,11 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
}
}
-#if defined(CONFIG_OF)
static const struct of_device_id atmel_aes_dt_ids[] = {
{ .compatible = "atmel,at91sam9g46-aes" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids);
-#endif
static int atmel_aes_probe(struct platform_device *pdev)
{
@@ -2566,11 +2564,9 @@ static int atmel_aes_probe(struct platform_device *pdev)
crypto_init_queue(&aes_dd->queue, ATMEL_AES_QUEUE_LENGTH);
- /* Get the base address */
- aes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!aes_res) {
- dev_err(dev, "no MEM resource info\n");
- err = -ENODEV;
+ aes_dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &aes_res);
+ if (IS_ERR(aes_dd->io_base)) {
+ err = PTR_ERR(aes_dd->io_base);
goto err_tasklet_kill;
}
aes_dd->phys_base = aes_res->start;
@@ -2597,13 +2593,6 @@ static int atmel_aes_probe(struct platform_device *pdev)
goto err_tasklet_kill;
}
- aes_dd->io_base = devm_ioremap_resource(&pdev->dev, aes_res);
- if (IS_ERR(aes_dd->io_base)) {
- dev_err(dev, "can't ioremap\n");
- err = PTR_ERR(aes_dd->io_base);
- goto err_tasklet_kill;
- }
-
err = clk_prepare(aes_dd->iclk);
if (err)
goto err_tasklet_kill;
@@ -2687,7 +2676,7 @@ static struct platform_driver atmel_aes_driver = {
.remove = atmel_aes_remove,
.driver = {
.name = "atmel_aes",
- .of_match_table = of_match_ptr(atmel_aes_dt_ids),
+ .of_match_table = atmel_aes_dt_ids,
},
};
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 432beabd79e6..590ea984c622 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 6bef634d3c86..3622120add62 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -28,7 +28,7 @@
#include <linux/irq.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/crypto.h>
#include <crypto/scatterwalk.h>
@@ -1770,7 +1770,8 @@ static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd)
size_t bs = ctx->block_size;
size_t i, num_words = bs / sizeof(u32);
- memcpy(hmac->opad, hmac->ipad, bs);
+ unsafe_memcpy(hmac->opad, hmac->ipad, bs,
+ "fortified memcpy causes -Wrestrict warning");
for (i = 0; i < num_words; ++i) {
hmac->ipad[i] ^= 0x36363636;
hmac->opad[i] ^= 0x5c5c5c5c;
@@ -2499,8 +2500,8 @@ static int atmel_sha_dma_init(struct atmel_sha_dev *dd)
{
dd->dma_lch_in.chan = dma_request_chan(dd->dev, "tx");
if (IS_ERR(dd->dma_lch_in.chan)) {
- dev_err(dd->dev, "DMA channel is not available\n");
- return PTR_ERR(dd->dma_lch_in.chan);
+ return dev_err_probe(dd->dev, PTR_ERR(dd->dma_lch_in.chan),
+ "DMA channel is not available\n");
}
dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
@@ -2570,14 +2571,12 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
}
}
-#if defined(CONFIG_OF)
static const struct of_device_id atmel_sha_dt_ids[] = {
{ .compatible = "atmel,at91sam9g46-sha" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids);
-#endif
static int atmel_sha_probe(struct platform_device *pdev)
{
@@ -2604,11 +2603,9 @@ static int atmel_sha_probe(struct platform_device *pdev)
crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
- /* Get the base address */
- sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!sha_res) {
- dev_err(dev, "no MEM resource info\n");
- err = -ENODEV;
+ sha_dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &sha_res);
+ if (IS_ERR(sha_dd->io_base)) {
+ err = PTR_ERR(sha_dd->io_base);
goto err_tasklet_kill;
}
sha_dd->phys_base = sha_res->start;
@@ -2635,13 +2632,6 @@ static int atmel_sha_probe(struct platform_device *pdev)
goto err_tasklet_kill;
}
- sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res);
- if (IS_ERR(sha_dd->io_base)) {
- dev_err(dev, "can't ioremap\n");
- err = PTR_ERR(sha_dd->io_base);
- goto err_tasklet_kill;
- }
-
err = clk_prepare(sha_dd->iclk);
if (err)
goto err_tasklet_kill;
@@ -2716,7 +2706,7 @@ static struct platform_driver atmel_sha_driver = {
.remove = atmel_sha_remove,
.driver = {
.name = "atmel_sha",
- .of_match_table = of_match_ptr(atmel_sha_dt_ids),
+ .of_match_table = atmel_sha_dt_ids,
},
};
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index c9ded8be9c39..099b32a10dd7 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -28,7 +28,7 @@
#include <linux/irq.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/crypto.h>
#include <crypto/scatterwalk.h>
@@ -1139,13 +1139,11 @@ static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd)
}
}
-#if defined(CONFIG_OF)
static const struct of_device_id atmel_tdes_dt_ids[] = {
{ .compatible = "atmel,at91sam9g46-tdes" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids);
-#endif
static int atmel_tdes_probe(struct platform_device *pdev)
{
@@ -1172,11 +1170,9 @@ static int atmel_tdes_probe(struct platform_device *pdev)
crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH);
- /* Get the base address */
- tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!tdes_res) {
- dev_err(dev, "no MEM resource info\n");
- err = -ENODEV;
+ tdes_dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &tdes_res);
+ if (IS_ERR(tdes_dd->io_base)) {
+ err = PTR_ERR(tdes_dd->io_base);
goto err_tasklet_kill;
}
tdes_dd->phys_base = tdes_res->start;
@@ -1203,12 +1199,6 @@ static int atmel_tdes_probe(struct platform_device *pdev)
goto err_tasklet_kill;
}
- tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res);
- if (IS_ERR(tdes_dd->io_base)) {
- err = PTR_ERR(tdes_dd->io_base);
- goto err_tasklet_kill;
- }
-
err = atmel_tdes_hw_version_init(tdes_dd);
if (err)
goto err_tasklet_kill;
@@ -1282,7 +1272,7 @@ static struct platform_driver atmel_tdes_driver = {
.remove = atmel_tdes_remove,
.driver = {
.name = "atmel_tdes",
- .of_match_table = of_match_ptr(atmel_tdes_dt_ids),
+ .of_match_table = atmel_tdes_dt_ids,
},
};
diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c
index 70b911baab26..689be70d69c1 100644
--- a/drivers/crypto/bcm/cipher.c
+++ b/drivers/crypto/bcm/cipher.c
@@ -15,8 +15,7 @@
#include <linux/kthread.h>
#include <linux/rtnetlink.h>
#include <linux/sched.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/io.h>
#include <linux/bitops.h>
@@ -2397,7 +2396,8 @@ static int ahash_hmac_setkey(struct crypto_ahash *ahash, const u8 *key,
memset(ctx->ipad + ctx->authkeylen, 0,
blocksize - ctx->authkeylen);
ctx->authkeylen = 0;
- memcpy(ctx->opad, ctx->ipad, blocksize);
+ unsafe_memcpy(ctx->opad, ctx->ipad, blocksize,
+ "fortified memcpy causes -Wrestrict warning");
for (index = 0; index < blocksize; index++) {
ctx->ipad[index] ^= HMAC_IPAD_VALUE;
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index feb86013dbf6..eba2d750c3b0 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -56,12 +56,15 @@
#include "sg_sw_sec4.h"
#include "key_gen.h"
#include "caamalg_desc.h"
-#include <crypto/engine.h>
-#include <crypto/xts.h>
#include <asm/unaligned.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/engine.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/xts.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -95,13 +98,13 @@ struct caam_alg_entry {
};
struct caam_aead_alg {
- struct aead_alg aead;
+ struct aead_engine_alg aead;
struct caam_alg_entry caam;
bool registered;
};
struct caam_skcipher_alg {
- struct skcipher_alg skcipher;
+ struct skcipher_engine_alg skcipher;
struct caam_alg_entry caam;
bool registered;
};
@@ -110,7 +113,6 @@ struct caam_skcipher_alg {
* per-session context
*/
struct caam_ctx {
- struct crypto_engine_ctx enginectx;
u32 sh_desc_enc[DESC_MAX_USED_LEN];
u32 sh_desc_dec[DESC_MAX_USED_LEN];
u8 key[CAAM_MAX_KEY_SIZE];
@@ -188,7 +190,8 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead)
static int aead_set_sh_desc(struct crypto_aead *aead)
{
struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
- struct caam_aead_alg, aead);
+ struct caam_aead_alg,
+ aead.base);
unsigned int ivsize = crypto_aead_ivsize(aead);
struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
struct device *jrdev = ctx->jrdev;
@@ -738,7 +741,7 @@ static int skcipher_setkey(struct crypto_skcipher *skcipher, const u8 *key,
struct caam_ctx *ctx = crypto_skcipher_ctx_dma(skcipher);
struct caam_skcipher_alg *alg =
container_of(crypto_skcipher_alg(skcipher), typeof(*alg),
- skcipher);
+ skcipher.base);
struct device *jrdev = ctx->jrdev;
unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
u32 *desc;
@@ -1195,7 +1198,8 @@ static void init_authenc_job(struct aead_request *req,
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead),
- struct caam_aead_alg, aead);
+ struct caam_aead_alg,
+ aead.base);
unsigned int ivsize = crypto_aead_ivsize(aead);
struct caam_ctx *ctx = crypto_aead_ctx_dma(aead);
struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctx->jrdev->parent);
@@ -1881,7 +1885,7 @@ static int skcipher_decrypt(struct skcipher_request *req)
static struct caam_skcipher_alg driver_algs[] = {
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-caam",
@@ -1894,10 +1898,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-3des-caam",
@@ -1910,10 +1917,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.max_keysize = DES3_EDE_KEY_SIZE,
.ivsize = DES3_EDE_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "cbc(des)",
.cra_driver_name = "cbc-des-caam",
@@ -1926,10 +1936,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.max_keysize = DES_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "ctr(aes)",
.cra_driver_name = "ctr-aes-caam",
@@ -1943,11 +1956,14 @@ static struct caam_skcipher_alg driver_algs[] = {
.ivsize = AES_BLOCK_SIZE,
.chunksize = AES_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "rfc3686(ctr(aes))",
.cra_driver_name = "rfc3686-ctr-aes-caam",
@@ -1963,6 +1979,9 @@ static struct caam_skcipher_alg driver_algs[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.chunksize = AES_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -1970,7 +1989,7 @@ static struct caam_skcipher_alg driver_algs[] = {
},
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "xts(aes)",
.cra_driver_name = "xts-aes-caam",
@@ -1984,10 +2003,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "ecb(des)",
.cra_driver_name = "ecb-des-caam",
@@ -1999,10 +2021,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.min_keysize = DES_KEY_SIZE,
.max_keysize = DES_KEY_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-caam",
@@ -2014,10 +2039,13 @@ static struct caam_skcipher_alg driver_algs[] = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
},
{
- .skcipher = {
+ .skcipher.base = {
.base = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3-caam",
@@ -2029,13 +2057,16 @@ static struct caam_skcipher_alg driver_algs[] = {
.min_keysize = DES3_EDE_KEY_SIZE,
.max_keysize = DES3_EDE_KEY_SIZE,
},
+ .skcipher.op = {
+ .do_one_request = skcipher_do_one_req,
+ },
.caam.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB,
},
};
static struct caam_aead_alg driver_aeads[] = {
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "rfc4106(gcm(aes))",
.cra_driver_name = "rfc4106-gcm-aes-caam",
@@ -2048,13 +2079,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = GCM_RFC4106_IV_SIZE,
.maxauthsize = AES_BLOCK_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
.nodkp = true,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "rfc4543(gcm(aes))",
.cra_driver_name = "rfc4543-gcm-aes-caam",
@@ -2067,6 +2101,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = GCM_RFC4543_IV_SIZE,
.maxauthsize = AES_BLOCK_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
.nodkp = true,
@@ -2074,7 +2111,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
/* Galois Counter Mode */
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "gcm(aes)",
.cra_driver_name = "gcm-aes-caam",
@@ -2087,6 +2124,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = GCM_AES_IV_SIZE,
.maxauthsize = AES_BLOCK_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
.nodkp = true,
@@ -2094,7 +2134,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
/* single-pass ipsec_esp descriptor */
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(md5),"
"ecb(cipher_null))",
@@ -2109,13 +2149,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha1),"
"ecb(cipher_null))",
@@ -2130,13 +2173,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha224),"
"ecb(cipher_null))",
@@ -2151,13 +2197,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha256),"
"ecb(cipher_null))",
@@ -2172,13 +2221,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha384),"
"ecb(cipher_null))",
@@ -2193,13 +2245,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha512),"
"ecb(cipher_null))",
@@ -2214,13 +2269,16 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = NULL_IV_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
OP_ALG_AAI_HMAC_PRECOMP,
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(aes))",
.cra_driver_name = "authenc-hmac-md5-"
@@ -2234,6 +2292,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2241,7 +2302,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(md5),"
"cbc(aes)))",
@@ -2256,6 +2317,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2264,7 +2328,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha1-"
@@ -2278,6 +2342,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2285,7 +2352,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha1),"
"cbc(aes)))",
@@ -2300,6 +2367,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2308,7 +2378,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha224),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha224-"
@@ -2322,6 +2392,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2329,7 +2402,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha224),"
"cbc(aes)))",
@@ -2344,6 +2417,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2352,7 +2428,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha256),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha256-"
@@ -2366,6 +2442,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2373,7 +2452,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha256),"
"cbc(aes)))",
@@ -2388,6 +2467,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2396,7 +2478,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha384),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha384-"
@@ -2410,6 +2492,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2417,7 +2502,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha384),"
"cbc(aes)))",
@@ -2432,6 +2517,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2440,7 +2528,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha512),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha512-"
@@ -2454,6 +2542,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -2461,7 +2552,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha512),"
"cbc(aes)))",
@@ -2476,6 +2567,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -2484,7 +2578,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-md5-"
@@ -2498,6 +2592,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2505,7 +2602,7 @@ static struct caam_aead_alg driver_aeads[] = {
}
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(md5),"
"cbc(des3_ede)))",
@@ -2520,6 +2617,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2528,7 +2628,7 @@ static struct caam_aead_alg driver_aeads[] = {
}
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha1),"
"cbc(des3_ede))",
@@ -2543,6 +2643,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2550,7 +2653,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha1),"
"cbc(des3_ede)))",
@@ -2566,6 +2669,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2574,7 +2680,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha224),"
"cbc(des3_ede))",
@@ -2589,6 +2695,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2596,7 +2705,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha224),"
"cbc(des3_ede)))",
@@ -2612,6 +2721,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2620,7 +2732,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha256),"
"cbc(des3_ede))",
@@ -2635,6 +2747,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2642,7 +2757,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha256),"
"cbc(des3_ede)))",
@@ -2658,6 +2773,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2666,7 +2784,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha384),"
"cbc(des3_ede))",
@@ -2681,6 +2799,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2688,7 +2809,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha384),"
"cbc(des3_ede)))",
@@ -2704,6 +2825,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2712,7 +2836,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha512),"
"cbc(des3_ede))",
@@ -2727,6 +2851,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -2734,7 +2861,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha512),"
"cbc(des3_ede)))",
@@ -2750,6 +2877,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -2758,7 +2888,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(des))",
.cra_driver_name = "authenc-hmac-md5-"
@@ -2772,6 +2902,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2779,7 +2912,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(md5),"
"cbc(des)))",
@@ -2794,6 +2927,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_MD5 |
@@ -2802,7 +2938,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha1),cbc(des))",
.cra_driver_name = "authenc-hmac-sha1-"
@@ -2816,6 +2952,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2823,7 +2962,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha1),"
"cbc(des)))",
@@ -2838,6 +2977,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA1 |
@@ -2846,7 +2988,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha224),cbc(des))",
.cra_driver_name = "authenc-hmac-sha224-"
@@ -2860,6 +3002,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2867,7 +3012,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha224),"
"cbc(des)))",
@@ -2882,6 +3027,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA224 |
@@ -2890,7 +3038,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha256),cbc(des))",
.cra_driver_name = "authenc-hmac-sha256-"
@@ -2904,6 +3052,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2911,7 +3062,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha256),"
"cbc(des)))",
@@ -2926,6 +3077,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA256 |
@@ -2934,7 +3088,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha384),cbc(des))",
.cra_driver_name = "authenc-hmac-sha384-"
@@ -2948,6 +3102,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2955,7 +3112,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha384),"
"cbc(des)))",
@@ -2970,6 +3127,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA384 |
@@ -2978,7 +3138,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha512),cbc(des))",
.cra_driver_name = "authenc-hmac-sha512-"
@@ -2992,6 +3152,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -2999,7 +3162,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "echainiv(authenc(hmac(sha512),"
"cbc(des)))",
@@ -3014,6 +3177,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
.class2_alg_type = OP_ALG_ALGSEL_SHA512 |
@@ -3022,7 +3188,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(md5),"
"rfc3686(ctr(aes)))",
@@ -3037,6 +3203,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3046,7 +3215,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc("
"hmac(md5),rfc3686(ctr(aes))))",
@@ -3061,6 +3230,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3071,7 +3243,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha1),"
"rfc3686(ctr(aes)))",
@@ -3086,6 +3258,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3095,7 +3270,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc("
"hmac(sha1),rfc3686(ctr(aes))))",
@@ -3110,6 +3285,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3120,7 +3298,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha224),"
"rfc3686(ctr(aes)))",
@@ -3135,6 +3313,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3144,7 +3325,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc("
"hmac(sha224),rfc3686(ctr(aes))))",
@@ -3159,6 +3340,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3169,7 +3353,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha256),"
"rfc3686(ctr(aes)))",
@@ -3184,6 +3368,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3193,7 +3380,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc(hmac(sha256),"
"rfc3686(ctr(aes))))",
@@ -3208,6 +3395,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3218,7 +3408,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha384),"
"rfc3686(ctr(aes)))",
@@ -3233,6 +3423,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3242,7 +3435,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc(hmac(sha384),"
"rfc3686(ctr(aes))))",
@@ -3257,6 +3450,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3267,7 +3463,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "authenc(hmac(sha512),"
"rfc3686(ctr(aes)))",
@@ -3282,6 +3478,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3291,7 +3490,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "seqiv(authenc(hmac(sha512),"
"rfc3686(ctr(aes))))",
@@ -3306,6 +3505,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_AES |
OP_ALG_AAI_CTR_MOD128,
@@ -3316,7 +3518,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "rfc7539(chacha20,poly1305)",
.cra_driver_name = "rfc7539-chacha20-poly1305-"
@@ -3330,6 +3532,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = CHACHAPOLY_IV_SIZE,
.maxauthsize = POLY1305_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_CHACHA20 |
OP_ALG_AAI_AEAD,
@@ -3339,7 +3544,7 @@ static struct caam_aead_alg driver_aeads[] = {
},
},
{
- .aead = {
+ .aead.base = {
.base = {
.cra_name = "rfc7539esp(chacha20,poly1305)",
.cra_driver_name = "rfc7539esp-chacha20-"
@@ -3353,6 +3558,9 @@ static struct caam_aead_alg driver_aeads[] = {
.ivsize = 8,
.maxauthsize = POLY1305_DIGEST_SIZE,
},
+ .aead.op = {
+ .do_one_request = aead_do_one_req,
+ },
.caam = {
.class1_alg_type = OP_ALG_ALGSEL_CHACHA20 |
OP_ALG_AAI_AEAD,
@@ -3412,13 +3620,11 @@ static int caam_cra_init(struct crypto_skcipher *tfm)
{
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
struct caam_skcipher_alg *caam_alg =
- container_of(alg, typeof(*caam_alg), skcipher);
+ container_of(alg, typeof(*caam_alg), skcipher.base);
struct caam_ctx *ctx = crypto_skcipher_ctx_dma(tfm);
u32 alg_aai = caam_alg->caam.class1_alg_type & OP_ALG_AAI_MASK;
int ret = 0;
- ctx->enginectx.op.do_one_request = skcipher_do_one_req;
-
if (alg_aai == OP_ALG_AAI_XTS) {
const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
struct crypto_skcipher *fallback;
@@ -3449,13 +3655,11 @@ static int caam_aead_init(struct crypto_aead *tfm)
{
struct aead_alg *alg = crypto_aead_alg(tfm);
struct caam_aead_alg *caam_alg =
- container_of(alg, struct caam_aead_alg, aead);
+ container_of(alg, struct caam_aead_alg, aead.base);
struct caam_ctx *ctx = crypto_aead_ctx_dma(tfm);
crypto_aead_set_reqsize(tfm, sizeof(struct caam_aead_req_ctx));
- ctx->enginectx.op.do_one_request = aead_do_one_req;
-
return caam_init_common(ctx, &caam_alg->caam, !caam_alg->caam.nodkp);
}
@@ -3490,20 +3694,20 @@ void caam_algapi_exit(void)
struct caam_aead_alg *t_alg = driver_aeads + i;
if (t_alg->registered)
- crypto_unregister_aead(&t_alg->aead);
+ crypto_engine_unregister_aead(&t_alg->aead);
}
for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
struct caam_skcipher_alg *t_alg = driver_algs + i;
if (t_alg->registered)
- crypto_unregister_skcipher(&t_alg->skcipher);
+ crypto_engine_unregister_skcipher(&t_alg->skcipher);
}
}
static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
{
- struct skcipher_alg *alg = &t_alg->skcipher;
+ struct skcipher_alg *alg = &t_alg->skcipher.base;
alg->base.cra_module = THIS_MODULE;
alg->base.cra_priority = CAAM_CRA_PRIORITY;
@@ -3517,7 +3721,7 @@ static void caam_skcipher_alg_init(struct caam_skcipher_alg *t_alg)
static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
{
- struct aead_alg *alg = &t_alg->aead;
+ struct aead_alg *alg = &t_alg->aead.base;
alg->base.cra_module = THIS_MODULE;
alg->base.cra_priority = CAAM_CRA_PRIORITY;
@@ -3607,10 +3811,10 @@ int caam_algapi_init(struct device *ctrldev)
caam_skcipher_alg_init(t_alg);
- err = crypto_register_skcipher(&t_alg->skcipher);
+ err = crypto_engine_register_skcipher(&t_alg->skcipher);
if (err) {
pr_warn("%s alg registration failed\n",
- t_alg->skcipher.base.cra_driver_name);
+ t_alg->skcipher.base.base.cra_driver_name);
continue;
}
@@ -3654,15 +3858,15 @@ int caam_algapi_init(struct device *ctrldev)
* if MD or MD size is not supported by device.
*/
if (is_mdha(c2_alg_sel) &&
- (!md_inst || t_alg->aead.maxauthsize > md_limit))
+ (!md_inst || t_alg->aead.base.maxauthsize > md_limit))
continue;
caam_aead_alg_init(t_alg);
- err = crypto_register_aead(&t_alg->aead);
+ err = crypto_engine_register_aead(&t_alg->aead);
if (err) {
pr_warn("%s alg registration failed\n",
- t_alg->aead.base.cra_driver_name);
+ t_alg->aead.base.base.cra_driver_name);
continue;
}
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 80deb003f0a5..290c8500c247 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -65,9 +65,13 @@
#include "sg_sw_sec4.h"
#include "key_gen.h"
#include "caamhash_desc.h"
-#include <crypto/engine.h>
+#include <crypto/internal/engine.h>
+#include <crypto/internal/hash.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#define CAAM_CRA_PRIORITY 3000
@@ -89,7 +93,6 @@ static struct list_head hash_list;
/* ahash per-session context */
struct caam_hash_ctx {
- struct crypto_engine_ctx enginectx;
u32 sh_desc_update[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned;
@@ -368,10 +371,8 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, u32 *keylen, u8 *key,
int ret;
desc = kmalloc(CAAM_CMD_SZ * 8 + CAAM_PTR_SZ * 2, GFP_KERNEL);
- if (!desc) {
- dev_err(jrdev, "unable to allocate key input memory\n");
+ if (!desc)
return -ENOMEM;
- }
init_job_desc(desc, 0);
@@ -702,19 +703,14 @@ static struct ahash_edesc *ahash_edesc_alloc(struct ahash_request *req,
int sg_num, u32 *sh_desc,
dma_addr_t sh_desc_dma)
{
- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
- struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash);
struct caam_hash_state *state = ahash_request_ctx_dma(req);
gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
GFP_KERNEL : GFP_ATOMIC;
struct ahash_edesc *edesc;
- unsigned int sg_size = sg_num * sizeof(struct sec4_sg_entry);
- edesc = kzalloc(sizeof(*edesc) + sg_size, flags);
- if (!edesc) {
- dev_err(ctx->jrdev, "could not allocate extended descriptor\n");
+ edesc = kzalloc(struct_size(edesc, sec4_sg, sg_num), flags);
+ if (!edesc)
return NULL;
- }
state->edesc = edesc;
@@ -1757,7 +1753,7 @@ static struct caam_hash_template driver_hash[] = {
struct caam_hash_alg {
struct list_head entry;
int alg_type;
- struct ahash_alg ahash_alg;
+ struct ahash_engine_alg ahash_alg;
};
static int caam_hash_cra_init(struct crypto_tfm *tfm)
@@ -1769,7 +1765,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
struct ahash_alg *alg =
container_of(halg, struct ahash_alg, halg);
struct caam_hash_alg *caam_hash =
- container_of(alg, struct caam_hash_alg, ahash_alg);
+ container_of(alg, struct caam_hash_alg, ahash_alg.base);
struct caam_hash_ctx *ctx = crypto_ahash_ctx_dma(ahash);
/* Sizes for MDHA running digests: MD5, SHA1, 224, 256, 384, 512 */
static const u8 runninglen[] = { HASH_MSG_LEN + MD5_DIGEST_SIZE,
@@ -1860,8 +1856,6 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
sh_desc_digest) -
sh_desc_update_offset;
- ctx->enginectx.op.do_one_request = ahash_do_one_req;
-
crypto_ahash_set_reqsize_dma(ahash, sizeof(struct caam_hash_state));
/*
@@ -1894,7 +1888,7 @@ void caam_algapi_hash_exit(void)
return;
list_for_each_entry_safe(t_alg, n, &hash_list, entry) {
- crypto_unregister_ahash(&t_alg->ahash_alg);
+ crypto_engine_unregister_ahash(&t_alg->ahash_alg);
list_del(&t_alg->entry);
kfree(t_alg);
}
@@ -1909,13 +1903,11 @@ caam_hash_alloc(struct caam_hash_template *template,
struct crypto_alg *alg;
t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
- if (!t_alg) {
- pr_err("failed to allocate t_alg\n");
+ if (!t_alg)
return ERR_PTR(-ENOMEM);
- }
- t_alg->ahash_alg = template->template_ahash;
- halg = &t_alg->ahash_alg;
+ t_alg->ahash_alg.base = template->template_ahash;
+ halg = &t_alg->ahash_alg.base;
alg = &halg->halg.base;
if (keyed) {
@@ -1928,7 +1920,7 @@ caam_hash_alloc(struct caam_hash_template *template,
template->name);
snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
template->driver_name);
- t_alg->ahash_alg.setkey = NULL;
+ halg->setkey = NULL;
}
alg->cra_module = THIS_MODULE;
alg->cra_init = caam_hash_cra_init;
@@ -1940,6 +1932,7 @@ caam_hash_alloc(struct caam_hash_template *template,
alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY;
t_alg->alg_type = template->alg_type;
+ t_alg->ahash_alg.op.do_one_request = ahash_do_one_req;
return t_alg;
}
@@ -2001,10 +1994,10 @@ int caam_algapi_hash_init(struct device *ctrldev)
continue;
}
- err = crypto_register_ahash(&t_alg->ahash_alg);
+ err = crypto_engine_register_ahash(&t_alg->ahash_alg);
if (err) {
pr_warn("%s alg registration failed: %d\n",
- t_alg->ahash_alg.halg.base.cra_driver_name,
+ t_alg->ahash_alg.base.halg.base.cra_driver_name,
err);
kfree(t_alg);
} else
@@ -2021,10 +2014,10 @@ int caam_algapi_hash_init(struct device *ctrldev)
continue;
}
- err = crypto_register_ahash(&t_alg->ahash_alg);
+ err = crypto_engine_register_ahash(&t_alg->ahash_alg);
if (err) {
pr_warn("%s alg registration failed: %d\n",
- t_alg->ahash_alg.halg.base.cra_driver_name,
+ t_alg->ahash_alg.base.halg.base.cra_driver_name,
err);
kfree(t_alg);
} else
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
index 72afc249d42f..887a5f2fb927 100644
--- a/drivers/crypto/caam/caampkc.c
+++ b/drivers/crypto/caam/caampkc.c
@@ -16,8 +16,12 @@
#include "desc_constr.h"
#include "sg_sw_sec4.h"
#include "caampkc.h"
+#include <crypto/internal/engine.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#define DESC_RSA_PUB_LEN (2 * CAAM_CMD_SZ + SIZEOF_RSA_PUB_PDB)
#define DESC_RSA_PRIV_F1_LEN (2 * CAAM_CMD_SZ + \
@@ -38,7 +42,7 @@ static u8 *zero_buffer;
static bool init_done;
struct caam_akcipher_alg {
- struct akcipher_alg akcipher;
+ struct akcipher_engine_alg akcipher;
bool registered;
};
@@ -225,7 +229,9 @@ static int caam_rsa_count_leading_zeros(struct scatterlist *sgl,
if (len && *buff)
break;
- sg_miter_next(&miter);
+ if (!sg_miter_next(&miter))
+ break;
+
buff = miter.addr;
len = miter.length;
@@ -1121,8 +1127,6 @@ static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
return -ENOMEM;
}
- ctx->enginectx.op.do_one_request = akcipher_do_one_req;
-
return 0;
}
@@ -1139,7 +1143,7 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
}
static struct caam_akcipher_alg caam_rsa = {
- .akcipher = {
+ .akcipher.base = {
.encrypt = caam_rsa_enc,
.decrypt = caam_rsa_dec,
.set_pub_key = caam_rsa_set_pub_key,
@@ -1155,7 +1159,10 @@ static struct caam_akcipher_alg caam_rsa = {
.cra_ctxsize = sizeof(struct caam_rsa_ctx) +
CRYPTO_DMA_PADDING,
},
- }
+ },
+ .akcipher.op = {
+ .do_one_request = akcipher_do_one_req,
+ },
};
/* Public Key Cryptography module initialization handler */
@@ -1193,12 +1200,12 @@ int caam_pkc_init(struct device *ctrldev)
if (!zero_buffer)
return -ENOMEM;
- err = crypto_register_akcipher(&caam_rsa.akcipher);
+ err = crypto_engine_register_akcipher(&caam_rsa.akcipher);
if (err) {
kfree(zero_buffer);
dev_warn(ctrldev, "%s alg registration failed\n",
- caam_rsa.akcipher.base.cra_driver_name);
+ caam_rsa.akcipher.base.base.cra_driver_name);
} else {
init_done = true;
caam_rsa.registered = true;
@@ -1214,7 +1221,7 @@ void caam_pkc_exit(void)
return;
if (caam_rsa.registered)
- crypto_unregister_akcipher(&caam_rsa.akcipher);
+ crypto_engine_unregister_akcipher(&caam_rsa.akcipher);
kfree(zero_buffer);
}
diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h
index cc889a525e2f..96d03704c9be 100644
--- a/drivers/crypto/caam/caampkc.h
+++ b/drivers/crypto/caam/caampkc.h
@@ -12,7 +12,6 @@
#define _PKC_DESC_H_
#include "compat.h"
#include "pdb.h"
-#include <crypto/engine.h>
/**
* caam_priv_key_form - CAAM RSA private key representation
@@ -88,13 +87,11 @@ struct caam_rsa_key {
/**
* caam_rsa_ctx - per session context.
- * @enginectx : crypto engine context
* @key : RSA key in DMA zone
* @dev : device structure
* @padding_dma : dma address of padding, for adding it to the input
*/
struct caam_rsa_ctx {
- struct crypto_engine_ctx enginectx;
struct caam_rsa_key key;
struct device *dev;
dma_addr_t padding_dma;
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index ff9ddbbca377..bdf367f3f679 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <linux/fsl/mc.h>
@@ -382,8 +383,8 @@ static void kick_trng(struct device *dev, int ent_delay)
val = ent_delay;
/* min. freq. count, equal to 1/4 of the entropy sample length */
wr_reg32(&r4tst->rtfrqmin, val >> 2);
- /* max. freq. count, equal to 16 times the entropy sample length */
- wr_reg32(&r4tst->rtfrqmax, val << 4);
+ /* disable maximum frequency count */
+ wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE);
}
wr_reg32(&r4tst->rtsdctl, (val << RTSDCTL_ENT_DLY_SHIFT) |
@@ -740,6 +741,109 @@ static int caam_ctrl_rng_init(struct device *dev)
return 0;
}
+/* Indicate if the internal state of the CAAM is lost during PM */
+static int caam_off_during_pm(void)
+{
+ bool not_off_during_pm = of_machine_is_compatible("fsl,imx6q") ||
+ of_machine_is_compatible("fsl,imx6qp") ||
+ of_machine_is_compatible("fsl,imx6dl");
+
+ return not_off_during_pm ? 0 : 1;
+}
+
+static void caam_state_save(struct device *dev)
+{
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+ struct caam_ctl_state *state = &ctrlpriv->state;
+ struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
+ u32 deco_inst, jr_inst;
+ int i;
+
+ state->mcr = rd_reg32(&ctrl->mcr);
+ state->scfgr = rd_reg32(&ctrl->scfgr);
+
+ deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
+ CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
+ for (i = 0; i < deco_inst; i++) {
+ state->deco_mid[i].liodn_ms =
+ rd_reg32(&ctrl->deco_mid[i].liodn_ms);
+ state->deco_mid[i].liodn_ls =
+ rd_reg32(&ctrl->deco_mid[i].liodn_ls);
+ }
+
+ jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
+ CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
+ for (i = 0; i < jr_inst; i++) {
+ state->jr_mid[i].liodn_ms =
+ rd_reg32(&ctrl->jr_mid[i].liodn_ms);
+ state->jr_mid[i].liodn_ls =
+ rd_reg32(&ctrl->jr_mid[i].liodn_ls);
+ }
+}
+
+static void caam_state_restore(const struct device *dev)
+{
+ const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+ const struct caam_ctl_state *state = &ctrlpriv->state;
+ struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
+ u32 deco_inst, jr_inst;
+ int i;
+
+ wr_reg32(&ctrl->mcr, state->mcr);
+ wr_reg32(&ctrl->scfgr, state->scfgr);
+
+ deco_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
+ CHA_ID_MS_DECO_MASK) >> CHA_ID_MS_DECO_SHIFT;
+ for (i = 0; i < deco_inst; i++) {
+ wr_reg32(&ctrl->deco_mid[i].liodn_ms,
+ state->deco_mid[i].liodn_ms);
+ wr_reg32(&ctrl->deco_mid[i].liodn_ls,
+ state->deco_mid[i].liodn_ls);
+ }
+
+ jr_inst = (rd_reg32(&ctrl->perfmon.cha_num_ms) &
+ CHA_ID_MS_JR_MASK) >> CHA_ID_MS_JR_SHIFT;
+ for (i = 0; i < jr_inst; i++) {
+ wr_reg32(&ctrl->jr_mid[i].liodn_ms,
+ state->jr_mid[i].liodn_ms);
+ wr_reg32(&ctrl->jr_mid[i].liodn_ls,
+ state->jr_mid[i].liodn_ls);
+ }
+
+ if (ctrlpriv->virt_en == 1)
+ clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START |
+ JRSTART_JR1_START | JRSTART_JR2_START |
+ JRSTART_JR3_START);
+}
+
+static int caam_ctrl_suspend(struct device *dev)
+{
+ const struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+
+ if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en)
+ caam_state_save(dev);
+
+ return 0;
+}
+
+static int caam_ctrl_resume(struct device *dev)
+{
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (ctrlpriv->caam_off_during_pm && !ctrlpriv->optee_en) {
+ caam_state_restore(dev);
+
+ /* HW and rng will be reset so deinstantiation can be removed */
+ devm_remove_action(dev, devm_deinstantiate_rng, dev);
+ ret = caam_ctrl_rng_init(dev);
+ }
+
+ return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(caam_ctrl_pm_ops, caam_ctrl_suspend, caam_ctrl_resume);
+
/* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev)
{
@@ -771,6 +875,8 @@ static int caam_probe(struct platform_device *pdev)
caam_imx = (bool)imx_soc_match;
+ ctrlpriv->caam_off_during_pm = caam_imx && caam_off_during_pm();
+
if (imx_soc_match) {
/*
* Until Layerscape and i.MX OP-TEE get in sync,
@@ -1033,6 +1139,7 @@ static struct platform_driver caam_driver = {
.driver = {
.name = "caam",
.of_match_table = caam_match,
+ .pm = pm_ptr(&caam_ctrl_pm_ops),
},
.probe = caam_probe,
};
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index b4f7bf77f487..e51320150872 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -4,7 +4,7 @@
* Private/internal definitions between modules
*
* Copyright 2008-2011 Freescale Semiconductor, Inc.
- * Copyright 2019 NXP
+ * Copyright 2019, 2023 NXP
*/
#ifndef INTERN_H
@@ -47,6 +47,16 @@ struct caam_jrentry_info {
u32 desc_size; /* Stored size for postprocessing, header derived */
};
+struct caam_jr_state {
+ dma_addr_t inpbusaddr;
+ dma_addr_t outbusaddr;
+};
+
+struct caam_jr_dequeue_params {
+ struct device *dev;
+ int enable_itr;
+};
+
/* Private sub-storage for a single JobR */
struct caam_drv_private_jr {
struct list_head list_node; /* Job Ring device list */
@@ -54,6 +64,7 @@ struct caam_drv_private_jr {
int ridx;
struct caam_job_ring __iomem *rregs; /* JobR's register space */
struct tasklet_struct irqtask;
+ struct caam_jr_dequeue_params tasklet_params;
int irq; /* One per queue */
bool hwrng;
@@ -71,6 +82,15 @@ struct caam_drv_private_jr {
int tail; /* entinfo (s/w ring) tail index */
void *outring; /* Base of output ring, DMA-safe */
struct crypto_engine *engine;
+
+ struct caam_jr_state state; /* State of the JR during PM */
+};
+
+struct caam_ctl_state {
+ struct masterid deco_mid[16];
+ struct masterid jr_mid[4];
+ u32 mcr;
+ u32 scfgr;
};
/*
@@ -116,6 +136,9 @@ struct caam_drv_private {
struct dentry *ctl; /* controller dir */
struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
#endif
+
+ int caam_off_during_pm; /* If the CAAM is reset after suspend */
+ struct caam_ctl_state state; /* State of the CTL during PM */
};
#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 96dea5304d22..b1f1b393b98e 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -9,6 +9,7 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include "compat.h"
#include "ctrl.h"
@@ -117,6 +118,23 @@ static int caam_jr_flush(struct device *dev)
return caam_jr_stop_processing(dev, JRCR_RESET);
}
+/* The resume can be used after a park or a flush if CAAM has not been reset */
+static int caam_jr_restart_processing(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ u32 halt_status = rd_reg32(&jrp->rregs->jrintstatus) &
+ JRINT_ERR_HALT_MASK;
+
+ /* Check that the flush/park is completed */
+ if (halt_status != JRINT_ERR_HALT_COMPLETE)
+ return -1;
+
+ /* Resume processing of jobs */
+ clrsetbits_32(&jrp->rregs->jrintstatus, 0, JRINT_ERR_HALT_COMPLETE);
+
+ return 0;
+}
+
static int caam_reset_hw_jr(struct device *dev)
{
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
@@ -215,7 +233,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
* tasklet if jobs done.
*/
irqstate = rd_reg32(&jrp->rregs->jrintstatus);
- if (!irqstate)
+ if (!(irqstate & JRINT_JR_INT))
return IRQ_NONE;
/*
@@ -245,7 +263,8 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
static void caam_jr_dequeue(unsigned long devarg)
{
int hw_idx, sw_idx, i, head, tail;
- struct device *dev = (struct device *)devarg;
+ struct caam_jr_dequeue_params *params = (void *)devarg;
+ struct device *dev = params->dev;
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
u32 *userdesc, userstatus;
@@ -319,8 +338,9 @@ static void caam_jr_dequeue(unsigned long devarg)
outring_used--;
}
- /* reenable / unmask IRQs */
- clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
+ if (params->enable_itr)
+ /* reenable / unmask IRQs */
+ clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
}
/**
@@ -445,8 +465,16 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
* Guarantee that the descriptor's DMA address has been written to
* the next slot in the ring before the write index is updated, since
* other cores may update this index independently.
+ *
+ * Under heavy DDR load, smp_wmb() or dma_wmb() fail to make the input
+ * ring be updated before the CAAM starts reading it. So, CAAM will
+ * process, again, an old descriptor address and will put it in the
+ * output ring. This will make caam_jr_dequeue() to fail, since this
+ * old descriptor is not in the software ring.
+ * To fix this, use wmb() which works on the full system instead of
+ * inner/outer shareable domains.
*/
- smp_wmb();
+ wmb();
jrp->head = (head + 1) & (JOBR_DEPTH - 1);
@@ -470,6 +498,29 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
}
EXPORT_SYMBOL(caam_jr_enqueue);
+static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
+ dma_addr_t outbusaddr)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
+ wr_reg64(&jrp->rregs->outring_base, outbusaddr);
+ wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
+ wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+
+ /* Select interrupt coalescing parameters */
+ clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
+ (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+ (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+}
+
+static void caam_jr_reset_index(struct caam_drv_private_jr *jrp)
+{
+ jrp->out_ring_read_index = 0;
+ jrp->head = 0;
+ jrp->tail = 0;
+}
+
/*
* Init JobR independent of platform property detection
*/
@@ -506,25 +557,16 @@ static int caam_jr_init(struct device *dev)
jrp->entinfo[i].desc_addr_dma = !0;
/* Setup rings */
- jrp->out_ring_read_index = 0;
- jrp->head = 0;
- jrp->tail = 0;
-
- wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
- wr_reg64(&jrp->rregs->outring_base, outbusaddr);
- wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
- wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
-
+ caam_jr_reset_index(jrp);
jrp->inpring_avail = JOBR_DEPTH;
+ caam_jr_init_hw(dev, inpbusaddr, outbusaddr);
spin_lock_init(&jrp->inplock);
- /* Select interrupt coalescing parameters */
- clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
- (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
- (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
-
- tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
+ jrp->tasklet_params.dev = dev;
+ jrp->tasklet_params.enable_itr = 1;
+ tasklet_init(&jrp->irqtask, caam_jr_dequeue,
+ (unsigned long)&jrp->tasklet_params);
/* Connect job ring interrupt handler. */
error = devm_request_irq(dev, jrp->irq, caam_jr_interrupt, IRQF_SHARED,
@@ -635,11 +677,134 @@ static int caam_jr_probe(struct platform_device *pdev)
atomic_set(&jrpriv->tfm_count, 0);
+ device_init_wakeup(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, false);
+
register_algs(jrpriv, jrdev->parent);
return 0;
}
+static void caam_jr_get_hw_state(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+
+ jrp->state.inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
+ jrp->state.outbusaddr = rd_reg64(&jrp->rregs->outring_base);
+}
+
+static int caam_jr_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
+ struct caam_jr_dequeue_params suspend_params = {
+ .dev = dev,
+ .enable_itr = 0,
+ };
+
+ /* Remove the node from Physical JobR list maintained by driver */
+ spin_lock(&driver_data.jr_alloc_lock);
+ list_del(&jrpriv->list_node);
+ spin_unlock(&driver_data.jr_alloc_lock);
+
+ if (jrpriv->hwrng)
+ caam_rng_exit(dev->parent);
+
+ if (ctrlpriv->caam_off_during_pm) {
+ int err;
+
+ tasklet_disable(&jrpriv->irqtask);
+
+ /* mask itr to call flush */
+ clrsetbits_32(&jrpriv->rregs->rconfig_lo, 0, JRCFG_IMSK);
+
+ /* Invalid job in process */
+ err = caam_jr_flush(dev);
+ if (err) {
+ dev_err(dev, "Failed to flush\n");
+ return err;
+ }
+
+ /* Dequeing jobs flushed */
+ caam_jr_dequeue((unsigned long)&suspend_params);
+
+ /* Save state */
+ caam_jr_get_hw_state(dev);
+ } else if (device_may_wakeup(&pdev->dev)) {
+ enable_irq_wake(jrpriv->irq);
+ }
+
+ return 0;
+}
+
+static int caam_jr_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(dev->parent);
+
+ if (ctrlpriv->caam_off_during_pm) {
+ u64 inp_addr;
+ int err;
+
+ /*
+ * Check if the CAAM has been resetted checking the address of
+ * the input ring
+ */
+ inp_addr = rd_reg64(&jrpriv->rregs->inpring_base);
+ if (inp_addr != 0) {
+ /* JR still has some configuration */
+ if (inp_addr == jrpriv->state.inpbusaddr) {
+ /* JR has not been resetted */
+ err = caam_jr_restart_processing(dev);
+ if (err) {
+ dev_err(dev,
+ "Restart processing failed\n");
+ return err;
+ }
+
+ tasklet_enable(&jrpriv->irqtask);
+
+ clrsetbits_32(&jrpriv->rregs->rconfig_lo,
+ JRCFG_IMSK, 0);
+
+ goto add_jr;
+ } else if (ctrlpriv->optee_en) {
+ /* JR has been used by OPTEE, reset it */
+ err = caam_reset_hw_jr(dev);
+ if (err) {
+ dev_err(dev, "Failed to reset JR\n");
+ return err;
+ }
+ } else {
+ /* No explanation, return error */
+ return -EIO;
+ }
+ }
+
+ caam_jr_reset_index(jrpriv);
+ caam_jr_init_hw(dev, jrpriv->state.inpbusaddr,
+ jrpriv->state.outbusaddr);
+
+ tasklet_enable(&jrpriv->irqtask);
+ } else if (device_may_wakeup(&pdev->dev)) {
+ disable_irq_wake(jrpriv->irq);
+ }
+
+add_jr:
+ spin_lock(&driver_data.jr_alloc_lock);
+ list_add_tail(&jrpriv->list_node, &driver_data.jr_list);
+ spin_unlock(&driver_data.jr_alloc_lock);
+
+ if (jrpriv->hwrng)
+ jrpriv->hwrng = !caam_rng_init(dev->parent);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend, caam_jr_resume);
+
static const struct of_device_id caam_jr_match[] = {
{
.compatible = "fsl,sec-v4.0-job-ring",
@@ -655,6 +820,7 @@ static struct platform_driver caam_jr_driver = {
.driver = {
.name = "caam_jr",
.of_match_table = caam_jr_match,
+ .pm = pm_ptr(&caam_jr_pm_ops),
},
.probe = caam_jr_probe,
.remove = caam_jr_remove,
diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c
index 2ad2c1035856..46a083849a8e 100644
--- a/drivers/crypto/caam/qi.c
+++ b/drivers/crypto/caam/qi.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <soc/fsl/qman.h>
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 189e74c21f0c..873df9de9890 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -459,12 +459,6 @@ struct masterid {
u32 liodn_ls; /* LIODN for non-sequence and seq access */
};
-/* Partition ID for DMA configuration */
-struct partid {
- u32 rsvd1;
- u32 pidr; /* partition ID, DECO */
-};
-
/* RNGB test mode (replicated twice in some configurations) */
/* Padded out to 0x100 */
struct rngtst {
@@ -590,8 +584,7 @@ struct caam_ctrl {
u32 deco_rsr; /* DECORSR - Deco Request Source */
u32 rsvd11;
u32 deco_rq; /* DECORR - DECO Request */
- struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */
- u32 rsvd5[22];
+ struct masterid deco_mid[16]; /* DECOxLIODNR - 1 per DECO */
/* DECO Availability/Reset Section 120-3ff */
u32 deco_avail; /* DAR - DECO availability */
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile
index f6196495e862..aa0ba2d17e1e 100644
--- a/drivers/crypto/ccp/Makefile
+++ b/drivers/crypto/ccp/Makefile
@@ -11,7 +11,8 @@ ccp-$(CONFIG_PCI) += sp-pci.o
ccp-$(CONFIG_CRYPTO_DEV_SP_PSP) += psp-dev.o \
sev-dev.o \
tee-dev.o \
- platform-access.o
+ platform-access.o \
+ dbc.o
obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o
ccp-crypto-objs := ccp-crypto-main.o \
diff --git a/drivers/crypto/ccp/dbc.c b/drivers/crypto/ccp/dbc.c
new file mode 100644
index 000000000000..839ea14b9a85
--- /dev/null
+++ b/drivers/crypto/ccp/dbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD Secure Processor Dynamic Boost Control interface
+ *
+ * Copyright (C) 2023 Advanced Micro Devices, Inc.
+ *
+ * Author: Mario Limonciello <mario.limonciello@amd.com>
+ */
+
+#include "dbc.h"
+
+struct error_map {
+ u32 psp;
+ int ret;
+};
+
+#define DBC_ERROR_ACCESS_DENIED 0x0001
+#define DBC_ERROR_EXCESS_DATA 0x0004
+#define DBC_ERROR_BAD_PARAMETERS 0x0006
+#define DBC_ERROR_BAD_STATE 0x0007
+#define DBC_ERROR_NOT_IMPLEMENTED 0x0009
+#define DBC_ERROR_BUSY 0x000D
+#define DBC_ERROR_MESSAGE_FAILURE 0x0307
+#define DBC_ERROR_OVERFLOW 0x300F
+#define DBC_ERROR_SIGNATURE_INVALID 0x3072
+
+static struct error_map error_codes[] = {
+ {DBC_ERROR_ACCESS_DENIED, -EACCES},
+ {DBC_ERROR_EXCESS_DATA, -E2BIG},
+ {DBC_ERROR_BAD_PARAMETERS, -EINVAL},
+ {DBC_ERROR_BAD_STATE, -EAGAIN},
+ {DBC_ERROR_MESSAGE_FAILURE, -ENOENT},
+ {DBC_ERROR_NOT_IMPLEMENTED, -ENOENT},
+ {DBC_ERROR_BUSY, -EBUSY},
+ {DBC_ERROR_OVERFLOW, -ENFILE},
+ {DBC_ERROR_SIGNATURE_INVALID, -EPERM},
+ {0x0, 0x0},
+};
+
+static int send_dbc_cmd(struct psp_dbc_device *dbc_dev,
+ enum psp_platform_access_msg msg)
+{
+ int ret;
+
+ dbc_dev->mbox->req.header.status = 0;
+ ret = psp_send_platform_access_msg(msg, (struct psp_request *)dbc_dev->mbox);
+ if (ret == -EIO) {
+ int i;
+
+ dev_dbg(dbc_dev->dev,
+ "msg 0x%x failed with PSP error: 0x%x\n",
+ msg, dbc_dev->mbox->req.header.status);
+
+ for (i = 0; error_codes[i].psp; i++) {
+ if (dbc_dev->mbox->req.header.status == error_codes[i].psp)
+ return error_codes[i].ret;
+ }
+ }
+
+ return ret;
+}
+
+static int send_dbc_nonce(struct psp_dbc_device *dbc_dev)
+{
+ int ret;
+
+ dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_nonce);
+ ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_NONCE);
+ if (ret == -EAGAIN) {
+ dev_dbg(dbc_dev->dev, "retrying get nonce\n");
+ ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_NONCE);
+ }
+
+ return ret;
+}
+
+static int send_dbc_parameter(struct psp_dbc_device *dbc_dev)
+{
+ dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_param);
+
+ switch (dbc_dev->mbox->dbc_param.user.msg_index) {
+ case PARAM_SET_FMAX_CAP:
+ case PARAM_SET_PWR_CAP:
+ case PARAM_SET_GFX_MODE:
+ return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_SET_PARAMETER);
+ case PARAM_GET_FMAX_CAP:
+ case PARAM_GET_PWR_CAP:
+ case PARAM_GET_CURR_TEMP:
+ case PARAM_GET_FMAX_MAX:
+ case PARAM_GET_FMAX_MIN:
+ case PARAM_GET_SOC_PWR_MAX:
+ case PARAM_GET_SOC_PWR_MIN:
+ case PARAM_GET_SOC_PWR_CUR:
+ case PARAM_GET_GFX_MODE:
+ return send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_GET_PARAMETER);
+ }
+
+ return -EINVAL;
+}
+
+void dbc_dev_destroy(struct psp_device *psp)
+{
+ struct psp_dbc_device *dbc_dev = psp->dbc_data;
+
+ if (!dbc_dev)
+ return;
+
+ misc_deregister(&dbc_dev->char_dev);
+ mutex_destroy(&dbc_dev->ioctl_mutex);
+ psp->dbc_data = NULL;
+}
+
+static long dbc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct psp_device *psp_master = psp_get_master_device();
+ void __user *argp = (void __user *)arg;
+ struct psp_dbc_device *dbc_dev;
+ int ret;
+
+ if (!psp_master || !psp_master->dbc_data)
+ return -ENODEV;
+ dbc_dev = psp_master->dbc_data;
+
+ mutex_lock(&dbc_dev->ioctl_mutex);
+
+ switch (cmd) {
+ case DBCIOCNONCE:
+ if (copy_from_user(&dbc_dev->mbox->dbc_nonce.user, argp,
+ sizeof(struct dbc_user_nonce))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ ret = send_dbc_nonce(dbc_dev);
+ if (ret)
+ goto unlock;
+
+ if (copy_to_user(argp, &dbc_dev->mbox->dbc_nonce.user,
+ sizeof(struct dbc_user_nonce))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ break;
+ case DBCIOCUID:
+ dbc_dev->mbox->req.header.payload_size = sizeof(dbc_dev->mbox->dbc_set_uid);
+ if (copy_from_user(&dbc_dev->mbox->dbc_set_uid.user, argp,
+ sizeof(struct dbc_user_setuid))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ ret = send_dbc_cmd(dbc_dev, PSP_DYNAMIC_BOOST_SET_UID);
+ if (ret)
+ goto unlock;
+
+ if (copy_to_user(argp, &dbc_dev->mbox->dbc_set_uid.user,
+ sizeof(struct dbc_user_setuid))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ break;
+ case DBCIOCPARAM:
+ if (copy_from_user(&dbc_dev->mbox->dbc_param.user, argp,
+ sizeof(struct dbc_user_param))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ ret = send_dbc_parameter(dbc_dev);
+ if (ret)
+ goto unlock;
+
+ if (copy_to_user(argp, &dbc_dev->mbox->dbc_param.user,
+ sizeof(struct dbc_user_param))) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+
+ }
+unlock:
+ mutex_unlock(&dbc_dev->ioctl_mutex);
+
+ return ret;
+}
+
+static const struct file_operations dbc_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dbc_ioctl,
+};
+
+int dbc_dev_init(struct psp_device *psp)
+{
+ struct device *dev = psp->dev;
+ struct psp_dbc_device *dbc_dev;
+ int ret;
+
+ if (!PSP_FEATURE(psp, DBC))
+ return 0;
+
+ dbc_dev = devm_kzalloc(dev, sizeof(*dbc_dev), GFP_KERNEL);
+ if (!dbc_dev)
+ return -ENOMEM;
+
+ BUILD_BUG_ON(sizeof(union dbc_buffer) > PAGE_SIZE);
+ dbc_dev->mbox = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0);
+ if (!dbc_dev->mbox) {
+ ret = -ENOMEM;
+ goto cleanup_dev;
+ }
+
+ psp->dbc_data = dbc_dev;
+ dbc_dev->dev = dev;
+
+ ret = send_dbc_nonce(dbc_dev);
+ if (ret == -EACCES) {
+ dev_dbg(dbc_dev->dev,
+ "dynamic boost control was previously authenticated\n");
+ ret = 0;
+ }
+ dev_dbg(dbc_dev->dev, "dynamic boost control is %savailable\n",
+ ret ? "un" : "");
+ if (ret) {
+ ret = 0;
+ goto cleanup_mbox;
+ }
+
+ dbc_dev->char_dev.minor = MISC_DYNAMIC_MINOR;
+ dbc_dev->char_dev.name = "dbc";
+ dbc_dev->char_dev.fops = &dbc_fops;
+ dbc_dev->char_dev.mode = 0600;
+ ret = misc_register(&dbc_dev->char_dev);
+ if (ret)
+ goto cleanup_mbox;
+
+ mutex_init(&dbc_dev->ioctl_mutex);
+
+ return 0;
+
+cleanup_mbox:
+ devm_free_pages(dev, (unsigned long)dbc_dev->mbox);
+
+cleanup_dev:
+ psp->dbc_data = NULL;
+ devm_kfree(dev, dbc_dev);
+
+ return ret;
+}
diff --git a/drivers/crypto/ccp/dbc.h b/drivers/crypto/ccp/dbc.h
new file mode 100644
index 000000000000..e963099ca38e
--- /dev/null
+++ b/drivers/crypto/ccp/dbc.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AMD Platform Security Processor (PSP) Dynamic Boost Control support
+ *
+ * Copyright (C) 2023 Advanced Micro Devices, Inc.
+ *
+ * Author: Mario Limonciello <mario.limonciello@amd.com>
+ */
+
+#ifndef __DBC_H__
+#define __DBC_H__
+
+#include <uapi/linux/psp-dbc.h>
+
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/psp-platform-access.h>
+
+#include "psp-dev.h"
+
+struct psp_dbc_device {
+ struct device *dev;
+
+ union dbc_buffer *mbox;
+
+ struct mutex ioctl_mutex;
+
+ struct miscdevice char_dev;
+};
+
+struct dbc_nonce {
+ struct psp_req_buffer_hdr header;
+ struct dbc_user_nonce user;
+} __packed;
+
+struct dbc_set_uid {
+ struct psp_req_buffer_hdr header;
+ struct dbc_user_setuid user;
+} __packed;
+
+struct dbc_param {
+ struct psp_req_buffer_hdr header;
+ struct dbc_user_param user;
+} __packed;
+
+union dbc_buffer {
+ struct psp_request req;
+ struct dbc_nonce dbc_nonce;
+ struct dbc_set_uid dbc_set_uid;
+ struct dbc_param dbc_param;
+};
+
+void dbc_dev_destroy(struct psp_device *psp);
+int dbc_dev_init(struct psp_device *psp);
+
+#endif /* __DBC_H */
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index e3d6955d3265..d42d7bc62352 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -15,6 +15,7 @@
#include "sev-dev.h"
#include "tee-dev.h"
#include "platform-access.h"
+#include "dbc.h"
struct psp_device *psp_master;
@@ -112,6 +113,12 @@ static void psp_init_platform_access(struct psp_device *psp)
dev_warn(psp->dev, "platform access init failed: %d\n", ret);
return;
}
+
+ /* dbc must come after platform access as it tests the feature */
+ ret = dbc_dev_init(psp);
+ if (ret)
+ dev_warn(psp->dev, "failed to init dynamic boost control: %d\n",
+ ret);
}
static int psp_init(struct psp_device *psp)
@@ -173,13 +180,14 @@ int psp_dev_init(struct sp_device *sp)
goto e_err;
}
+ /* master device must be set for platform access */
+ if (psp->sp->set_psp_master_device)
+ psp->sp->set_psp_master_device(psp->sp);
+
ret = psp_init(psp);
if (ret)
goto e_irq;
- if (sp->set_psp_master_device)
- sp->set_psp_master_device(sp);
-
/* Enable interrupt */
iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);
@@ -188,6 +196,9 @@ int psp_dev_init(struct sp_device *sp)
return 0;
e_irq:
+ if (sp->clear_psp_master_device)
+ sp->clear_psp_master_device(sp);
+
sp_free_psp_irq(psp->sp, psp);
e_err:
sp->psp_data = NULL;
@@ -213,6 +224,8 @@ void psp_dev_destroy(struct sp_device *sp)
tee_dev_destroy(psp);
+ dbc_dev_destroy(psp);
+
platform_access_dev_destroy(psp);
sp_free_psp_irq(sp, psp);
diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h
index 505e4bdeaca8..8a4de69399c5 100644
--- a/drivers/crypto/ccp/psp-dev.h
+++ b/drivers/crypto/ccp/psp-dev.h
@@ -40,6 +40,7 @@ struct psp_device {
void *sev_data;
void *tee_data;
void *platform_access_data;
+ void *dbc_data;
unsigned int capability;
};
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index 1253a0217985..2329ad524b49 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -28,6 +28,10 @@
#define CACHE_NONE 0x00
#define CACHE_WB_NO_ALLOC 0xb7
+#define PLATFORM_FEATURE_DBC 0x1
+
+#define PSP_FEATURE(psp, feat) (psp->vdata && psp->vdata->platform_features & PLATFORM_FEATURE_##feat)
+
/* Structure to hold CCP device data */
struct ccp_device;
struct ccp_vdata {
@@ -51,6 +55,7 @@ struct tee_vdata {
const unsigned int cmdbuff_addr_hi_reg;
const unsigned int ring_wptr_reg;
const unsigned int ring_rptr_reg;
+ const unsigned int info_reg;
};
struct platform_access_vdata {
@@ -69,6 +74,8 @@ struct psp_vdata {
const unsigned int feature_reg;
const unsigned int inten_reg;
const unsigned int intsts_reg;
+ const unsigned int bootloader_info_reg;
+ const unsigned int platform_features;
};
/* Structure to hold SP device data */
diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c
index b603ad9b8341..b6ab56abeb68 100644
--- a/drivers/crypto/ccp/sp-pci.c
+++ b/drivers/crypto/ccp/sp-pci.c
@@ -8,6 +8,7 @@
* Author: Gary R Hook <gary.hook@amd.com>
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -24,6 +25,12 @@
#include "ccp-dev.h"
#include "psp-dev.h"
+/* used for version string AA.BB.CC.DD */
+#define AA GENMASK(31, 24)
+#define BB GENMASK(23, 16)
+#define CC GENMASK(15, 8)
+#define DD GENMASK(7, 0)
+
#define MSIX_VECTORS 2
struct sp_pci {
@@ -32,7 +39,7 @@ struct sp_pci {
};
static struct sp_device *sp_dev_master;
-#define attribute_show(name, def) \
+#define security_attribute_show(name, def) \
static ssize_t name##_show(struct device *d, struct device_attribute *attr, \
char *buf) \
{ \
@@ -42,24 +49,24 @@ static ssize_t name##_show(struct device *d, struct device_attribute *attr, \
return sysfs_emit(buf, "%d\n", (psp->capability & bit) > 0); \
}
-attribute_show(fused_part, FUSED_PART)
+security_attribute_show(fused_part, FUSED_PART)
static DEVICE_ATTR_RO(fused_part);
-attribute_show(debug_lock_on, DEBUG_LOCK_ON)
+security_attribute_show(debug_lock_on, DEBUG_LOCK_ON)
static DEVICE_ATTR_RO(debug_lock_on);
-attribute_show(tsme_status, TSME_STATUS)
+security_attribute_show(tsme_status, TSME_STATUS)
static DEVICE_ATTR_RO(tsme_status);
-attribute_show(anti_rollback_status, ANTI_ROLLBACK_STATUS)
+security_attribute_show(anti_rollback_status, ANTI_ROLLBACK_STATUS)
static DEVICE_ATTR_RO(anti_rollback_status);
-attribute_show(rpmc_production_enabled, RPMC_PRODUCTION_ENABLED)
+security_attribute_show(rpmc_production_enabled, RPMC_PRODUCTION_ENABLED)
static DEVICE_ATTR_RO(rpmc_production_enabled);
-attribute_show(rpmc_spirom_available, RPMC_SPIROM_AVAILABLE)
+security_attribute_show(rpmc_spirom_available, RPMC_SPIROM_AVAILABLE)
static DEVICE_ATTR_RO(rpmc_spirom_available);
-attribute_show(hsp_tpm_available, HSP_TPM_AVAILABLE)
+security_attribute_show(hsp_tpm_available, HSP_TPM_AVAILABLE)
static DEVICE_ATTR_RO(hsp_tpm_available);
-attribute_show(rom_armor_enforced, ROM_ARMOR_ENFORCED)
+security_attribute_show(rom_armor_enforced, ROM_ARMOR_ENFORCED)
static DEVICE_ATTR_RO(rom_armor_enforced);
-static struct attribute *psp_attrs[] = {
+static struct attribute *psp_security_attrs[] = {
&dev_attr_fused_part.attr,
&dev_attr_debug_lock_on.attr,
&dev_attr_tsme_status.attr,
@@ -83,13 +90,70 @@ static umode_t psp_security_is_visible(struct kobject *kobj, struct attribute *a
return 0;
}
-static struct attribute_group psp_attr_group = {
- .attrs = psp_attrs,
+static struct attribute_group psp_security_attr_group = {
+ .attrs = psp_security_attrs,
.is_visible = psp_security_is_visible,
};
+#define version_attribute_show(name, _offset) \
+static ssize_t name##_show(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sp_device *sp = dev_get_drvdata(d); \
+ struct psp_device *psp = sp->psp_data; \
+ unsigned int val = ioread32(psp->io_regs + _offset); \
+ return sysfs_emit(buf, "%02lx.%02lx.%02lx.%02lx\n", \
+ FIELD_GET(AA, val), \
+ FIELD_GET(BB, val), \
+ FIELD_GET(CC, val), \
+ FIELD_GET(DD, val)); \
+}
+
+version_attribute_show(bootloader_version, psp->vdata->bootloader_info_reg)
+static DEVICE_ATTR_RO(bootloader_version);
+version_attribute_show(tee_version, psp->vdata->tee->info_reg)
+static DEVICE_ATTR_RO(tee_version);
+
+static struct attribute *psp_firmware_attrs[] = {
+ &dev_attr_bootloader_version.attr,
+ &dev_attr_tee_version.attr,
+ NULL,
+};
+
+static umode_t psp_firmware_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct sp_device *sp = dev_get_drvdata(dev);
+ struct psp_device *psp = sp->psp_data;
+ unsigned int val = 0xffffffff;
+
+ if (!psp)
+ return 0;
+
+ if (attr == &dev_attr_bootloader_version.attr &&
+ psp->vdata->bootloader_info_reg)
+ val = ioread32(psp->io_regs + psp->vdata->bootloader_info_reg);
+
+ if (attr == &dev_attr_tee_version.attr &&
+ psp->capability & PSP_CAPABILITY_TEE &&
+ psp->vdata->tee->info_reg)
+ val = ioread32(psp->io_regs + psp->vdata->tee->info_reg);
+
+ /* If platform disallows accessing this register it will be all f's */
+ if (val != 0xffffffff)
+ return 0444;
+
+ return 0;
+}
+
+static struct attribute_group psp_firmware_attr_group = {
+ .attrs = psp_firmware_attrs,
+ .is_visible = psp_firmware_is_visible,
+};
+
static const struct attribute_group *psp_groups[] = {
- &psp_attr_group,
+ &psp_security_attr_group,
+ &psp_firmware_attr_group,
NULL,
};
@@ -359,6 +423,7 @@ static const struct tee_vdata teev1 = {
.cmdbuff_addr_hi_reg = 0x1054c, /* C2PMSG_19 */
.ring_wptr_reg = 0x10550, /* C2PMSG_20 */
.ring_rptr_reg = 0x10554, /* C2PMSG_21 */
+ .info_reg = 0x109e8, /* C2PMSG_58 */
};
static const struct tee_vdata teev2 = {
@@ -384,6 +449,7 @@ static const struct platform_access_vdata pa_v2 = {
static const struct psp_vdata pspv1 = {
.sev = &sevv1,
+ .bootloader_info_reg = 0x105ec, /* C2PMSG_59 */
.feature_reg = 0x105fc, /* C2PMSG_63 */
.inten_reg = 0x10610, /* P2CMSG_INTEN */
.intsts_reg = 0x10614, /* P2CMSG_INTSTS */
@@ -391,6 +457,7 @@ static const struct psp_vdata pspv1 = {
static const struct psp_vdata pspv2 = {
.sev = &sevv2,
+ .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */
.feature_reg = 0x109fc, /* C2PMSG_63 */
.inten_reg = 0x10690, /* P2CMSG_INTEN */
.intsts_reg = 0x10694, /* P2CMSG_INTSTS */
@@ -399,14 +466,17 @@ static const struct psp_vdata pspv2 = {
static const struct psp_vdata pspv3 = {
.tee = &teev1,
.platform_access = &pa_v1,
+ .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */
.feature_reg = 0x109fc, /* C2PMSG_63 */
.inten_reg = 0x10690, /* P2CMSG_INTEN */
.intsts_reg = 0x10694, /* P2CMSG_INTSTS */
+ .platform_features = PLATFORM_FEATURE_DBC,
};
static const struct psp_vdata pspv4 = {
.sev = &sevv2,
.tee = &teev1,
+ .bootloader_info_reg = 0x109ec, /* C2PMSG_59 */
.feature_reg = 0x109fc, /* C2PMSG_63 */
.inten_reg = 0x10690, /* P2CMSG_INTEN */
.intsts_reg = 0x10694, /* P2CMSG_INTSTS */
diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c
index c57f929805d5..0f0694037dd7 100644
--- a/drivers/crypto/ccree/cc_driver.c
+++ b/drivers/crypto/ccree/cc_driver.c
@@ -14,7 +14,6 @@
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include "cc_driver.h"
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index 0eade4fa6695..16298ae4a00b 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -2216,7 +2216,8 @@ static int chcr_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
memcpy(hmacctx->ipad, key, keylen);
}
memset(hmacctx->ipad + keylen, 0, bs - keylen);
- memcpy(hmacctx->opad, hmacctx->ipad, bs);
+ unsafe_memcpy(hmacctx->opad, hmacctx->ipad, bs,
+ "fortified memcpy causes -Wrestrict warning");
for (i = 0; i < bs / sizeof(int); i++) {
*((unsigned int *)(&hmacctx->ipad) + i) ^= IPAD_DATA;
diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h
index f7c8bb95a71b..5e9d568131fe 100644
--- a/drivers/crypto/chelsio/chcr_core.h
+++ b/drivers/crypto/chelsio/chcr_core.h
@@ -133,7 +133,6 @@ int start_crypto(void);
int stop_crypto(void);
int chcr_uld_rx_handler(void *handle, const __be64 *rsp,
const struct pkt_gl *pgl);
-int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev);
int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
int err);
#endif /* __CHCR_CORE_H__ */
diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h
index 7f88ddb08631..1d693b8436e6 100644
--- a/drivers/crypto/chelsio/chcr_crypto.h
+++ b/drivers/crypto/chelsio/chcr_crypto.h
@@ -344,7 +344,6 @@ void chcr_add_cipher_dst_ent(struct skcipher_request *req,
struct cpl_rx_phys_dsgl *phys_cpl,
struct cipher_wr_param *wrparam,
unsigned short qid);
-int sg_nents_len_skip(struct scatterlist *sg, u64 len, u64 skip);
void chcr_add_hash_src_ent(struct ahash_request *req, struct ulptx_sgl *ulptx,
struct hash_wr_param *param);
int chcr_hash_dma_map(struct device *dev, struct ahash_request *req);
diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c
index cbd8ca6e52ee..5d60a4bcb511 100644
--- a/drivers/crypto/exynos-rng.c
+++ b/drivers/crypto/exynos-rng.c
@@ -15,7 +15,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <crypto/internal/rng.h>
@@ -277,7 +277,7 @@ static int exynos_rng_probe(struct platform_device *pdev)
if (!rng)
return -ENOMEM;
- rng->type = (enum exynos_prng_type)of_device_get_match_data(&pdev->dev);
+ rng->type = (uintptr_t)of_device_get_match_data(&pdev->dev);
mutex_init(&rng->lock);
diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemini/sl3516-ce-cipher.c
index 14d0d83d388d..49dce9e0a834 100644
--- a/drivers/crypto/gemini/sl3516-ce-cipher.c
+++ b/drivers/crypto/gemini/sl3516-ce-cipher.c
@@ -8,13 +8,17 @@
* ECB mode.
*/
-#include <linux/crypto.h>
+#include <crypto/engine.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/pm_runtime.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/internal/skcipher.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include "sl3516-ce.h"
/* sl3516_ce_need_fallback - check if a request can be handled by the CE */
@@ -105,7 +109,7 @@ static int sl3516_ce_cipher_fallback(struct skcipher_request *areq)
struct sl3516_ce_alg_template *algt;
int err;
- algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
algt->stat_fb++;
skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
@@ -136,7 +140,7 @@ static int sl3516_ce_cipher(struct skcipher_request *areq)
int err = 0;
int i;
- algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
dev_dbg(ce->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__,
crypto_tfm_alg_name(areq->base.tfm),
@@ -258,7 +262,7 @@ theend:
return err;
}
-static int sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
+int sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq)
{
int err;
struct skcipher_request *breq = container_of(areq, struct skcipher_request, base);
@@ -318,7 +322,7 @@ int sl3516_ce_cipher_init(struct crypto_tfm *tfm)
memset(op, 0, sizeof(struct sl3516_ce_cipher_tfm_ctx));
- algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher);
+ algt = container_of(alg, struct sl3516_ce_alg_template, alg.skcipher.base);
op->ce = algt->ce;
op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
@@ -335,10 +339,6 @@ int sl3516_ce_cipher_init(struct crypto_tfm *tfm)
crypto_tfm_alg_driver_name(&sktfm->base),
crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)));
- op->enginectx.op.do_one_request = sl3516_ce_handle_cipher_request;
- op->enginectx.op.prepare_request = NULL;
- op->enginectx.op.unprepare_request = NULL;
-
err = pm_runtime_get_sync(op->ce->dev);
if (err < 0)
goto error_pm;
diff --git a/drivers/crypto/gemini/sl3516-ce-core.c b/drivers/crypto/gemini/sl3516-ce-core.c
index b7524b649068..0f43c6e39bb9 100644
--- a/drivers/crypto/gemini/sl3516-ce-core.c
+++ b/drivers/crypto/gemini/sl3516-ce-core.c
@@ -6,22 +6,24 @@
*
* Core file which registers crypto algorithms supported by the CryptoEngine
*/
+
+#include <crypto/engine.h>
+#include <crypto/internal/rng.h>
+#include <crypto/internal/skcipher.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <crypto/internal/rng.h>
-#include <crypto/internal/skcipher.h>
#include "sl3516-ce.h"
@@ -217,7 +219,7 @@ static struct sl3516_ce_alg_template ce_algs[] = {
{
.type = CRYPTO_ALG_TYPE_SKCIPHER,
.mode = ECB_AES,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-sl3516",
@@ -236,11 +238,13 @@ static struct sl3516_ce_alg_template ce_algs[] = {
.setkey = sl3516_ce_aes_setkey,
.encrypt = sl3516_ce_skencrypt,
.decrypt = sl3516_ce_skdecrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = sl3516_ce_handle_cipher_request,
+ },
},
};
-#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
static int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
{
struct sl3516_ce_dev *ce = seq->private;
@@ -264,8 +268,8 @@ static int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
switch (ce_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- ce_algs[i].alg.skcipher.base.cra_driver_name,
- ce_algs[i].alg.skcipher.base.cra_name,
+ ce_algs[i].alg.skcipher.base.base.cra_driver_name,
+ ce_algs[i].alg.skcipher.base.base.cra_name,
ce_algs[i].stat_req, ce_algs[i].stat_fb);
break;
}
@@ -274,7 +278,6 @@ static int sl3516_ce_debugfs_show(struct seq_file *seq, void *v)
}
DEFINE_SHOW_ATTRIBUTE(sl3516_ce_debugfs);
-#endif
static int sl3516_ce_register_algs(struct sl3516_ce_dev *ce)
{
@@ -286,11 +289,11 @@ static int sl3516_ce_register_algs(struct sl3516_ce_dev *ce)
switch (ce_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(ce->dev, "DEBUG: Register %s\n",
- ce_algs[i].alg.skcipher.base.cra_name);
- err = crypto_register_skcipher(&ce_algs[i].alg.skcipher);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
+ err = crypto_engine_register_skcipher(&ce_algs[i].alg.skcipher);
if (err) {
dev_err(ce->dev, "Fail to register %s\n",
- ce_algs[i].alg.skcipher.base.cra_name);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
ce_algs[i].ce = NULL;
return err;
}
@@ -313,8 +316,8 @@ static void sl3516_ce_unregister_algs(struct sl3516_ce_dev *ce)
switch (ce_algs[i].type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(ce->dev, "Unregister %d %s\n", i,
- ce_algs[i].alg.skcipher.base.cra_name);
- crypto_unregister_skcipher(&ce_algs[i].alg.skcipher);
+ ce_algs[i].alg.skcipher.base.base.cra_name);
+ crypto_engine_unregister_skcipher(&ce_algs[i].alg.skcipher);
break;
}
}
@@ -473,13 +476,20 @@ static int sl3516_ce_probe(struct platform_device *pdev)
pm_runtime_put_sync(ce->dev);
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SL3516_DEBUG)) {
+ struct dentry *dbgfs_dir __maybe_unused;
+ struct dentry *dbgfs_stats __maybe_unused;
+
+ /* Ignore error of debugfs */
+ dbgfs_dir = debugfs_create_dir("sl3516", NULL);
+ dbgfs_stats = debugfs_create_file("stats", 0444,
+ dbgfs_dir, ce,
+ &sl3516_ce_debugfs_fops);
#ifdef CONFIG_CRYPTO_DEV_SL3516_DEBUG
- /* Ignore error of debugfs */
- ce->dbgfs_dir = debugfs_create_dir("sl3516", NULL);
- ce->dbgfs_stats = debugfs_create_file("stats", 0444,
- ce->dbgfs_dir, ce,
- &sl3516_ce_debugfs_fops);
+ ce->dbgfs_dir = dbgfs_dir;
+ ce->dbgfs_stats = dbgfs_stats;
#endif
+ }
return 0;
error_pmuse:
diff --git a/drivers/crypto/gemini/sl3516-ce.h b/drivers/crypto/gemini/sl3516-ce.h
index 4c0ec6c920d1..9e1a7e7f8961 100644
--- a/drivers/crypto/gemini/sl3516-ce.h
+++ b/drivers/crypto/gemini/sl3516-ce.h
@@ -17,7 +17,6 @@
#include <crypto/engine.h>
#include <crypto/scatterwalk.h>
#include <crypto/skcipher.h>
-#include <linux/crypto.h>
#include <linux/debugfs.h>
#include <linux/hw_random.h>
@@ -292,16 +291,12 @@ struct sl3516_ce_cipher_req_ctx {
/*
* struct sl3516_ce_cipher_tfm_ctx - context for a skcipher TFM
- * @enginectx: crypto_engine used by this TFM
* @key: pointer to key data
* @keylen: len of the key
* @ce: pointer to the private data of driver handling this TFM
* @fallback_tfm: pointer to the fallback TFM
- *
- * enginectx must be the first element
*/
struct sl3516_ce_cipher_tfm_ctx {
- struct crypto_engine_ctx enginectx;
u32 *key;
u32 keylen;
struct sl3516_ce_dev *ce;
@@ -324,7 +319,7 @@ struct sl3516_ce_alg_template {
u32 mode;
struct sl3516_ce_dev *ce;
union {
- struct skcipher_alg skcipher;
+ struct skcipher_engine_alg skcipher;
} alg;
unsigned long stat_req;
unsigned long stat_fb;
@@ -345,3 +340,4 @@ int sl3516_ce_run_task(struct sl3516_ce_dev *ce,
int sl3516_ce_rng_register(struct sl3516_ce_dev *ce);
void sl3516_ce_rng_unregister(struct sl3516_ce_dev *ce);
+int sl3516_ce_handle_cipher_request(struct crypto_engine *engine, void *areq);
diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
index 8ede77310dc5..9a1c61be32cc 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c
@@ -1392,9 +1392,9 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
unsigned int len)
{
struct hpre_ctx *ctx = kpp_tfm_ctx(tfm);
+ unsigned int sz, sz_shift, curve_sz;
struct device *dev = ctx->dev;
char key[HPRE_ECC_MAX_KSZ];
- unsigned int sz, sz_shift;
struct ecdh params;
int ret;
@@ -1406,7 +1406,13 @@ static int hpre_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
/* Use stdrng to generate private key */
if (!params.key || !params.key_size) {
params.key = key;
- params.key_size = hpre_ecdh_get_curvesz(ctx->curve_id);
+ curve_sz = hpre_ecdh_get_curvesz(ctx->curve_id);
+ if (!curve_sz) {
+ dev_err(dev, "Invalid curve size!\n");
+ return -EINVAL;
+ }
+
+ params.key_size = curve_sz - 1;
ret = ecdh_gen_privkey(ctx, &params);
if (ret)
return ret;
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
index 5d0adfb54a34..39297ce70f44 100644
--- a/drivers/crypto/hisilicon/hpre/hpre_main.c
+++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
@@ -209,7 +209,7 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = {
{HPRE_QM_RESET_MASK_CAP, 0x3128, 0, GENMASK(31, 0), 0x0, 0xC37, 0x6C37},
{HPRE_QM_OOO_SHUTDOWN_MASK_CAP, 0x3128, 0, GENMASK(31, 0), 0x0, 0x4, 0x6C37},
{HPRE_QM_CE_MASK_CAP, 0x312C, 0, GENMASK(31, 0), 0x0, 0x8, 0x8},
- {HPRE_NFE_MASK_CAP, 0x3130, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0xFFFFFE},
+ {HPRE_NFE_MASK_CAP, 0x3130, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0x1FFFFFE},
{HPRE_RESET_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0xBFFFFE},
{HPRE_OOO_SHUTDOWN_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x22, 0xBFFFFE},
{HPRE_CE_MASK_CAP, 0x3138, 0, GENMASK(31, 0), 0x0, 0x1, 0x1},
@@ -276,6 +276,9 @@ static const struct hpre_hw_error hpre_hw_errors[] = {
.int_msk = BIT(23),
.msg = "sva_fsm_timeout_int_set"
}, {
+ .int_msk = BIT(24),
+ .msg = "sva_int_set"
+ }, {
/* sentinel */
}
};
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index edc6fd44e7ca..a99fd589445c 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -88,6 +88,8 @@
#define QM_DB_PRIORITY_SHIFT_V1 48
#define QM_PAGE_SIZE 0x0034
#define QM_QP_DB_INTERVAL 0x10000
+#define QM_DB_TIMEOUT_CFG 0x100074
+#define QM_DB_TIMEOUT_SET 0x1fffff
#define QM_MEM_START_INIT 0x100040
#define QM_MEM_INIT_DONE 0x100044
@@ -954,6 +956,11 @@ static irqreturn_t qm_mb_cmd_irq(int irq, void *data)
if (!val)
return IRQ_NONE;
+ if (test_bit(QM_DRIVER_REMOVING, &qm->misc_ctl)) {
+ dev_warn(&qm->pdev->dev, "Driver is down, message cannot be processed!\n");
+ return IRQ_HANDLED;
+ }
+
schedule_work(&qm->cmd_process);
return IRQ_HANDLED;
@@ -997,7 +1004,7 @@ static void qm_reset_function(struct hisi_qm *qm)
return;
}
- ret = hisi_qm_stop(qm, QM_FLR);
+ ret = hisi_qm_stop(qm, QM_DOWN);
if (ret) {
dev_err(dev, "failed to stop qm when reset function\n");
goto clear_bit;
@@ -2743,6 +2750,9 @@ void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list)
test_bit(QM_RESETTING, &qm->misc_ctl))
msleep(WAIT_PERIOD);
+ if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps))
+ flush_work(&qm->cmd_process);
+
udelay(REMOVE_WAIT_DELAY);
}
EXPORT_SYMBOL_GPL(hisi_qm_wait_task_finish);
@@ -3243,7 +3253,7 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r)
}
if (qm->status.stop_reason == QM_SOFT_RESET ||
- qm->status.stop_reason == QM_FLR) {
+ qm->status.stop_reason == QM_DOWN) {
hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET);
ret = qm_stop_started_qp(qm);
if (ret < 0) {
@@ -4539,11 +4549,11 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
if (qm->fun_type == QM_HW_PF)
qm_cmd_uninit(qm);
- ret = qm_try_stop_vfs(qm, QM_PF_FLR_PREPARE, QM_FLR);
+ ret = qm_try_stop_vfs(qm, QM_PF_FLR_PREPARE, QM_DOWN);
if (ret)
pci_err(pdev, "failed to stop vfs by pf in FLR.\n");
- ret = hisi_qm_stop(qm, QM_FLR);
+ ret = hisi_qm_stop(qm, QM_DOWN);
if (ret) {
pci_err(pdev, "Failed to stop QM, ret = %d.\n", ret);
hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET);
@@ -4641,9 +4651,11 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev)
struct hisi_qm *qm = pci_get_drvdata(pdev);
int ret;
- ret = hisi_qm_stop(qm, QM_NORMAL);
+ ret = hisi_qm_stop(qm, QM_DOWN);
if (ret)
dev_err(&pdev->dev, "Fail to stop qm in shutdown!\n");
+
+ hisi_qm_cache_wb(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown);
@@ -4807,7 +4819,7 @@ static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num)
cmd = msg & QM_MB_CMD_DATA_MASK;
switch (cmd) {
case QM_PF_FLR_PREPARE:
- qm_pf_reset_vf_process(qm, QM_FLR);
+ qm_pf_reset_vf_process(qm, QM_DOWN);
break;
case QM_PF_SRST_PREPARE:
qm_pf_reset_vf_process(qm, QM_SOFT_RESET);
@@ -5371,6 +5383,8 @@ int hisi_qm_init(struct hisi_qm *qm)
goto err_pci_init;
if (qm->fun_type == QM_HW_PF) {
+ /* Set the doorbell timeout to QM_DB_TIMEOUT_CFG ns. */
+ writel(QM_DB_TIMEOUT_SET, qm->io_base + QM_DB_TIMEOUT_CFG);
qm_disable_clock_gate(qm);
ret = qm_dev_mem_reset(qm);
if (ret) {
@@ -5538,6 +5552,8 @@ static int qm_rebuild_for_resume(struct hisi_qm *qm)
qm_cmd_init(qm);
hisi_qm_dev_err_init(qm);
+ /* Set the doorbell timeout to QM_DB_TIMEOUT_CFG ns. */
+ writel(QM_DB_TIMEOUT_SET, qm->io_base + QM_DB_TIMEOUT_CFG);
qm_disable_clock_gate(qm);
ret = qm_dev_mem_reset(qm);
if (ret)
diff --git a/drivers/crypto/hisilicon/sec/sec_drv.c b/drivers/crypto/hisilicon/sec/sec_drv.c
index e75851326c1e..e1e08993de12 100644
--- a/drivers/crypto/hisilicon/sec/sec_drv.c
+++ b/drivers/crypto/hisilicon/sec/sec_drv.c
@@ -1107,8 +1107,8 @@ static int sec_queue_res_cfg(struct sec_queue *queue)
}
queue->task_irq = platform_get_irq(to_platform_device(dev),
queue->queue_id * 2 + 1);
- if (queue->task_irq <= 0) {
- ret = -EINVAL;
+ if (queue->task_irq < 0) {
+ ret = queue->task_irq;
goto err_free_ring_db;
}
diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c
index 359aa2b41016..45063693859c 100644
--- a/drivers/crypto/img-hash.c
+++ b/drivers/crypto/img-hash.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
@@ -1105,7 +1105,7 @@ static struct platform_driver img_hash_driver = {
.driver = {
.name = "img-hash-accelerator",
.pm = &img_hash_pm_ops,
- .of_match_table = of_match_ptr(img_hash_match),
+ .of_match_table = img_hash_match,
}
};
module_platform_driver(img_hash_driver);
diff --git a/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c b/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c
index ae31be00357a..1e2fd9a754ec 100644
--- a/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c
+++ b/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c
@@ -5,24 +5,23 @@
* Copyright (C) 2018-2020 Intel Corporation
*/
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/gcm.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
#include <linux/clk.h>
#include <linux/completion.h>
-#include <linux/crypto.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/types.h>
-
-#include <crypto/aes.h>
-#include <crypto/engine.h>
-#include <crypto/gcm.h>
-#include <crypto/scatterwalk.h>
-
-#include <crypto/internal/aead.h>
-#include <crypto/internal/skcipher.h>
+#include <linux/string.h>
#include "ocs-aes.h"
@@ -38,7 +37,6 @@
/**
* struct ocs_aes_tctx - OCS AES Transform context
- * @engine_ctx: Engine context.
* @aes_dev: The OCS AES device.
* @key: AES/SM4 key.
* @key_len: The length (in bytes) of @key.
@@ -47,7 +45,6 @@
* @use_fallback: Whether or not fallback cipher should be used.
*/
struct ocs_aes_tctx {
- struct crypto_engine_ctx engine_ctx;
struct ocs_aes_dev *aes_dev;
u8 key[OCS_AES_KEYSIZE_256];
unsigned int key_len;
@@ -1148,15 +1145,6 @@ static int kmb_ocs_sm4_ccm_decrypt(struct aead_request *req)
return kmb_ocs_aead_common(req, OCS_SM4, OCS_DECRYPT, OCS_MODE_CCM);
}
-static inline int ocs_common_init(struct ocs_aes_tctx *tctx)
-{
- tctx->engine_ctx.op.prepare_request = NULL;
- tctx->engine_ctx.op.do_one_request = kmb_ocs_aes_sk_do_one_request;
- tctx->engine_ctx.op.unprepare_request = NULL;
-
- return 0;
-}
-
static int ocs_aes_init_tfm(struct crypto_skcipher *tfm)
{
const char *alg_name = crypto_tfm_alg_name(&tfm->base);
@@ -1172,16 +1160,14 @@ static int ocs_aes_init_tfm(struct crypto_skcipher *tfm)
crypto_skcipher_set_reqsize(tfm, sizeof(struct ocs_aes_rctx));
- return ocs_common_init(tctx);
+ return 0;
}
static int ocs_sm4_init_tfm(struct crypto_skcipher *tfm)
{
- struct ocs_aes_tctx *tctx = crypto_skcipher_ctx(tfm);
-
crypto_skcipher_set_reqsize(tfm, sizeof(struct ocs_aes_rctx));
- return ocs_common_init(tctx);
+ return 0;
}
static inline void clear_key(struct ocs_aes_tctx *tctx)
@@ -1206,15 +1192,6 @@ static void ocs_exit_tfm(struct crypto_skcipher *tfm)
}
}
-static inline int ocs_common_aead_init(struct ocs_aes_tctx *tctx)
-{
- tctx->engine_ctx.op.prepare_request = NULL;
- tctx->engine_ctx.op.do_one_request = kmb_ocs_aes_aead_do_one_request;
- tctx->engine_ctx.op.unprepare_request = NULL;
-
- return 0;
-}
-
static int ocs_aes_aead_cra_init(struct crypto_aead *tfm)
{
const char *alg_name = crypto_tfm_alg_name(&tfm->base);
@@ -1233,7 +1210,7 @@ static int ocs_aes_aead_cra_init(struct crypto_aead *tfm)
(sizeof(struct aead_request) +
crypto_aead_reqsize(tctx->sw_cipher.aead))));
- return ocs_common_aead_init(tctx);
+ return 0;
}
static int kmb_ocs_aead_ccm_setauthsize(struct crypto_aead *tfm,
@@ -1261,11 +1238,9 @@ static int kmb_ocs_aead_gcm_setauthsize(struct crypto_aead *tfm,
static int ocs_sm4_aead_cra_init(struct crypto_aead *tfm)
{
- struct ocs_aes_tctx *tctx = crypto_aead_ctx(tfm);
-
crypto_aead_set_reqsize(tfm, sizeof(struct ocs_aes_rctx));
- return ocs_common_aead_init(tctx);
+ return 0;
}
static void ocs_aead_cra_exit(struct crypto_aead *tfm)
@@ -1280,182 +1255,190 @@ static void ocs_aead_cra_exit(struct crypto_aead *tfm)
}
}
-static struct skcipher_alg algs[] = {
+static struct skcipher_engine_alg algs[] = {
#ifdef CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_ECB
{
- .base.cra_name = "ecb(aes)",
- .base.cra_driver_name = "ecb-aes-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_AES_MIN_KEY_SIZE,
- .max_keysize = OCS_AES_MAX_KEY_SIZE,
- .setkey = kmb_ocs_aes_set_key,
- .encrypt = kmb_ocs_aes_ecb_encrypt,
- .decrypt = kmb_ocs_aes_ecb_decrypt,
- .init = ocs_aes_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "ecb(aes)",
+ .base.base.cra_driver_name = "ecb-aes-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_AES_MIN_KEY_SIZE,
+ .base.max_keysize = OCS_AES_MAX_KEY_SIZE,
+ .base.setkey = kmb_ocs_aes_set_key,
+ .base.encrypt = kmb_ocs_aes_ecb_encrypt,
+ .base.decrypt = kmb_ocs_aes_ecb_decrypt,
+ .base.init = ocs_aes_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
#endif /* CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_ECB */
{
- .base.cra_name = "cbc(aes)",
- .base.cra_driver_name = "cbc-aes-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_AES_MIN_KEY_SIZE,
- .max_keysize = OCS_AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_aes_set_key,
- .encrypt = kmb_ocs_aes_cbc_encrypt,
- .decrypt = kmb_ocs_aes_cbc_decrypt,
- .init = ocs_aes_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "cbc(aes)",
+ .base.base.cra_driver_name = "cbc-aes-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_AES_MIN_KEY_SIZE,
+ .base.max_keysize = OCS_AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_aes_set_key,
+ .base.encrypt = kmb_ocs_aes_cbc_encrypt,
+ .base.decrypt = kmb_ocs_aes_cbc_decrypt,
+ .base.init = ocs_aes_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
{
- .base.cra_name = "ctr(aes)",
- .base.cra_driver_name = "ctr-aes-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = 1,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_AES_MIN_KEY_SIZE,
- .max_keysize = OCS_AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_aes_set_key,
- .encrypt = kmb_ocs_aes_ctr_encrypt,
- .decrypt = kmb_ocs_aes_ctr_decrypt,
- .init = ocs_aes_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "ctr(aes)",
+ .base.base.cra_driver_name = "ctr-aes-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.base.cra_blocksize = 1,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_AES_MIN_KEY_SIZE,
+ .base.max_keysize = OCS_AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_aes_set_key,
+ .base.encrypt = kmb_ocs_aes_ctr_encrypt,
+ .base.decrypt = kmb_ocs_aes_ctr_decrypt,
+ .base.init = ocs_aes_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
#ifdef CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_CTS
{
- .base.cra_name = "cts(cbc(aes))",
- .base.cra_driver_name = "cts-aes-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_AES_MIN_KEY_SIZE,
- .max_keysize = OCS_AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_aes_set_key,
- .encrypt = kmb_ocs_aes_cts_encrypt,
- .decrypt = kmb_ocs_aes_cts_decrypt,
- .init = ocs_aes_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "cts(cbc(aes))",
+ .base.base.cra_driver_name = "cts-aes-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_AES_MIN_KEY_SIZE,
+ .base.max_keysize = OCS_AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_aes_set_key,
+ .base.encrypt = kmb_ocs_aes_cts_encrypt,
+ .base.decrypt = kmb_ocs_aes_cts_decrypt,
+ .base.init = ocs_aes_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
#endif /* CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_CTS */
#ifdef CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_ECB
{
- .base.cra_name = "ecb(sm4)",
- .base.cra_driver_name = "ecb-sm4-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_SM4_KEY_SIZE,
- .max_keysize = OCS_SM4_KEY_SIZE,
- .setkey = kmb_ocs_sm4_set_key,
- .encrypt = kmb_ocs_sm4_ecb_encrypt,
- .decrypt = kmb_ocs_sm4_ecb_decrypt,
- .init = ocs_sm4_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "ecb(sm4)",
+ .base.base.cra_driver_name = "ecb-sm4-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_SM4_KEY_SIZE,
+ .base.max_keysize = OCS_SM4_KEY_SIZE,
+ .base.setkey = kmb_ocs_sm4_set_key,
+ .base.encrypt = kmb_ocs_sm4_ecb_encrypt,
+ .base.decrypt = kmb_ocs_sm4_ecb_decrypt,
+ .base.init = ocs_sm4_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
#endif /* CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_ECB */
{
- .base.cra_name = "cbc(sm4)",
- .base.cra_driver_name = "cbc-sm4-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_SM4_KEY_SIZE,
- .max_keysize = OCS_SM4_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_sm4_set_key,
- .encrypt = kmb_ocs_sm4_cbc_encrypt,
- .decrypt = kmb_ocs_sm4_cbc_decrypt,
- .init = ocs_sm4_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "cbc(sm4)",
+ .base.base.cra_driver_name = "cbc-sm4-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_SM4_KEY_SIZE,
+ .base.max_keysize = OCS_SM4_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_sm4_set_key,
+ .base.encrypt = kmb_ocs_sm4_cbc_encrypt,
+ .base.decrypt = kmb_ocs_sm4_cbc_decrypt,
+ .base.init = ocs_sm4_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
{
- .base.cra_name = "ctr(sm4)",
- .base.cra_driver_name = "ctr-sm4-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .base.cra_blocksize = 1,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_SM4_KEY_SIZE,
- .max_keysize = OCS_SM4_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_sm4_set_key,
- .encrypt = kmb_ocs_sm4_ctr_encrypt,
- .decrypt = kmb_ocs_sm4_ctr_decrypt,
- .init = ocs_sm4_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "ctr(sm4)",
+ .base.base.cra_driver_name = "ctr-sm4-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .base.base.cra_blocksize = 1,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_SM4_KEY_SIZE,
+ .base.max_keysize = OCS_SM4_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_sm4_set_key,
+ .base.encrypt = kmb_ocs_sm4_ctr_encrypt,
+ .base.decrypt = kmb_ocs_sm4_ctr_decrypt,
+ .base.init = ocs_sm4_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
},
#ifdef CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_CTS
{
- .base.cra_name = "cts(cbc(sm4))",
- .base.cra_driver_name = "cts-sm4-keembay-ocs",
- .base.cra_priority = KMB_OCS_PRIORITY,
- .base.cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
- .base.cra_module = THIS_MODULE,
- .base.cra_alignmask = 0,
-
- .min_keysize = OCS_SM4_KEY_SIZE,
- .max_keysize = OCS_SM4_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = kmb_ocs_sm4_set_key,
- .encrypt = kmb_ocs_sm4_cts_encrypt,
- .decrypt = kmb_ocs_sm4_cts_decrypt,
- .init = ocs_sm4_init_tfm,
- .exit = ocs_exit_tfm,
+ .base.base.cra_name = "cts(cbc(sm4))",
+ .base.base.cra_driver_name = "cts-sm4-keembay-ocs",
+ .base.base.cra_priority = KMB_OCS_PRIORITY,
+ .base.base.cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .base.base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.base.cra_ctxsize = sizeof(struct ocs_aes_tctx),
+ .base.base.cra_module = THIS_MODULE,
+ .base.base.cra_alignmask = 0,
+
+ .base.min_keysize = OCS_SM4_KEY_SIZE,
+ .base.max_keysize = OCS_SM4_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.setkey = kmb_ocs_sm4_set_key,
+ .base.encrypt = kmb_ocs_sm4_cts_encrypt,
+ .base.decrypt = kmb_ocs_sm4_cts_decrypt,
+ .base.init = ocs_sm4_init_tfm,
+ .base.exit = ocs_exit_tfm,
+ .op.do_one_request = kmb_ocs_aes_sk_do_one_request,
}
#endif /* CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_CTS */
};
-static struct aead_alg algs_aead[] = {
+static struct aead_engine_alg algs_aead[] = {
{
- .base = {
+ .base.base = {
.cra_name = "gcm(aes)",
.cra_driver_name = "gcm-aes-keembay-ocs",
.cra_priority = KMB_OCS_PRIORITY,
@@ -1467,17 +1450,18 @@ static struct aead_alg algs_aead[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
- .init = ocs_aes_aead_cra_init,
- .exit = ocs_aead_cra_exit,
- .ivsize = GCM_AES_IV_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setauthsize = kmb_ocs_aead_gcm_setauthsize,
- .setkey = kmb_ocs_aes_aead_set_key,
- .encrypt = kmb_ocs_aes_gcm_encrypt,
- .decrypt = kmb_ocs_aes_gcm_decrypt,
+ .base.init = ocs_aes_aead_cra_init,
+ .base.exit = ocs_aead_cra_exit,
+ .base.ivsize = GCM_AES_IV_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.setauthsize = kmb_ocs_aead_gcm_setauthsize,
+ .base.setkey = kmb_ocs_aes_aead_set_key,
+ .base.encrypt = kmb_ocs_aes_gcm_encrypt,
+ .base.decrypt = kmb_ocs_aes_gcm_decrypt,
+ .op.do_one_request = kmb_ocs_aes_aead_do_one_request,
},
{
- .base = {
+ .base.base = {
.cra_name = "ccm(aes)",
.cra_driver_name = "ccm-aes-keembay-ocs",
.cra_priority = KMB_OCS_PRIORITY,
@@ -1489,17 +1473,18 @@ static struct aead_alg algs_aead[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
- .init = ocs_aes_aead_cra_init,
- .exit = ocs_aead_cra_exit,
- .ivsize = AES_BLOCK_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setauthsize = kmb_ocs_aead_ccm_setauthsize,
- .setkey = kmb_ocs_aes_aead_set_key,
- .encrypt = kmb_ocs_aes_ccm_encrypt,
- .decrypt = kmb_ocs_aes_ccm_decrypt,
+ .base.init = ocs_aes_aead_cra_init,
+ .base.exit = ocs_aead_cra_exit,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.setauthsize = kmb_ocs_aead_ccm_setauthsize,
+ .base.setkey = kmb_ocs_aes_aead_set_key,
+ .base.encrypt = kmb_ocs_aes_ccm_encrypt,
+ .base.decrypt = kmb_ocs_aes_ccm_decrypt,
+ .op.do_one_request = kmb_ocs_aes_aead_do_one_request,
},
{
- .base = {
+ .base.base = {
.cra_name = "gcm(sm4)",
.cra_driver_name = "gcm-sm4-keembay-ocs",
.cra_priority = KMB_OCS_PRIORITY,
@@ -1510,17 +1495,18 @@ static struct aead_alg algs_aead[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
- .init = ocs_sm4_aead_cra_init,
- .exit = ocs_aead_cra_exit,
- .ivsize = GCM_AES_IV_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setauthsize = kmb_ocs_aead_gcm_setauthsize,
- .setkey = kmb_ocs_sm4_aead_set_key,
- .encrypt = kmb_ocs_sm4_gcm_encrypt,
- .decrypt = kmb_ocs_sm4_gcm_decrypt,
+ .base.init = ocs_sm4_aead_cra_init,
+ .base.exit = ocs_aead_cra_exit,
+ .base.ivsize = GCM_AES_IV_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.setauthsize = kmb_ocs_aead_gcm_setauthsize,
+ .base.setkey = kmb_ocs_sm4_aead_set_key,
+ .base.encrypt = kmb_ocs_sm4_gcm_encrypt,
+ .base.decrypt = kmb_ocs_sm4_gcm_decrypt,
+ .op.do_one_request = kmb_ocs_aes_aead_do_one_request,
},
{
- .base = {
+ .base.base = {
.cra_name = "ccm(sm4)",
.cra_driver_name = "ccm-sm4-keembay-ocs",
.cra_priority = KMB_OCS_PRIORITY,
@@ -1531,21 +1517,22 @@ static struct aead_alg algs_aead[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
- .init = ocs_sm4_aead_cra_init,
- .exit = ocs_aead_cra_exit,
- .ivsize = AES_BLOCK_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setauthsize = kmb_ocs_aead_ccm_setauthsize,
- .setkey = kmb_ocs_sm4_aead_set_key,
- .encrypt = kmb_ocs_sm4_ccm_encrypt,
- .decrypt = kmb_ocs_sm4_ccm_decrypt,
+ .base.init = ocs_sm4_aead_cra_init,
+ .base.exit = ocs_aead_cra_exit,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.setauthsize = kmb_ocs_aead_ccm_setauthsize,
+ .base.setkey = kmb_ocs_sm4_aead_set_key,
+ .base.encrypt = kmb_ocs_sm4_ccm_encrypt,
+ .base.decrypt = kmb_ocs_sm4_ccm_decrypt,
+ .op.do_one_request = kmb_ocs_aes_aead_do_one_request,
}
};
static void unregister_aes_algs(struct ocs_aes_dev *aes_dev)
{
- crypto_unregister_aeads(algs_aead, ARRAY_SIZE(algs_aead));
- crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ crypto_engine_unregister_aeads(algs_aead, ARRAY_SIZE(algs_aead));
+ crypto_engine_unregister_skciphers(algs, ARRAY_SIZE(algs));
}
static int register_aes_algs(struct ocs_aes_dev *aes_dev)
@@ -1556,13 +1543,13 @@ static int register_aes_algs(struct ocs_aes_dev *aes_dev)
* If any algorithm fails to register, all preceding algorithms that
* were successfully registered will be automatically unregistered.
*/
- ret = crypto_register_aeads(algs_aead, ARRAY_SIZE(algs_aead));
+ ret = crypto_engine_register_aeads(algs_aead, ARRAY_SIZE(algs_aead));
if (ret)
return ret;
- ret = crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+ ret = crypto_engine_register_skciphers(algs, ARRAY_SIZE(algs));
if (ret)
- crypto_unregister_aeads(algs_aead, ARRAY_SIZE(algs));
+ crypto_engine_unregister_aeads(algs_aead, ARRAY_SIZE(algs));
return ret;
}
diff --git a/drivers/crypto/intel/keembay/keembay-ocs-ecc.c b/drivers/crypto/intel/keembay/keembay-ocs-ecc.c
index 2269df17514c..fb95deed9057 100644
--- a/drivers/crypto/intel/keembay/keembay-ocs-ecc.c
+++ b/drivers/crypto/intel/keembay/keembay-ocs-ecc.c
@@ -7,30 +7,27 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <crypto/ecc_curve.h>
+#include <crypto/ecdh.h>
+#include <crypto/engine.h>
+#include <crypto/internal/ecc.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/kpp.h>
+#include <crypto/rng.h>
#include <linux/clk.h>
#include <linux/completion.h>
-#include <linux/crypto.h>
-#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/fips.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <crypto/ecc_curve.h>
-#include <crypto/ecdh.h>
-#include <crypto/engine.h>
-#include <crypto/kpp.h>
-#include <crypto/rng.h>
-
-#include <crypto/internal/ecc.h>
-#include <crypto/internal/kpp.h>
+#include <linux/string.h>
#define DRV_NAME "keembay-ocs-ecc"
@@ -95,13 +92,11 @@ struct ocs_ecc_dev {
/**
* struct ocs_ecc_ctx - Transformation context.
- * @engine_ctx: Crypto engine ctx.
* @ecc_dev: The ECC driver associated with this context.
* @curve: The elliptic curve used by this transformation.
* @private_key: The private key.
*/
struct ocs_ecc_ctx {
- struct crypto_engine_ctx engine_ctx;
struct ocs_ecc_dev *ecc_dev;
const struct ecc_curve *curve;
u64 private_key[KMB_ECC_VLI_MAX_DIGITS];
@@ -794,10 +789,6 @@ static int kmb_ecc_tctx_init(struct ocs_ecc_ctx *tctx, unsigned int curve_id)
if (!tctx->curve)
return -EOPNOTSUPP;
- tctx->engine_ctx.op.prepare_request = NULL;
- tctx->engine_ctx.op.do_one_request = kmb_ocs_ecc_do_one_request;
- tctx->engine_ctx.op.unprepare_request = NULL;
-
return 0;
}
@@ -830,36 +821,38 @@ static unsigned int kmb_ocs_ecdh_max_size(struct crypto_kpp *tfm)
return digits_to_bytes(tctx->curve->g.ndigits) * 2;
}
-static struct kpp_alg ocs_ecdh_p256 = {
- .set_secret = kmb_ocs_ecdh_set_secret,
- .generate_public_key = kmb_ocs_ecdh_generate_public_key,
- .compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
- .init = kmb_ocs_ecdh_nist_p256_init_tfm,
- .exit = kmb_ocs_ecdh_exit_tfm,
- .max_size = kmb_ocs_ecdh_max_size,
- .base = {
+static struct kpp_engine_alg ocs_ecdh_p256 = {
+ .base.set_secret = kmb_ocs_ecdh_set_secret,
+ .base.generate_public_key = kmb_ocs_ecdh_generate_public_key,
+ .base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
+ .base.init = kmb_ocs_ecdh_nist_p256_init_tfm,
+ .base.exit = kmb_ocs_ecdh_exit_tfm,
+ .base.max_size = kmb_ocs_ecdh_max_size,
+ .base.base = {
.cra_name = "ecdh-nist-p256",
.cra_driver_name = "ecdh-nist-p256-keembay-ocs",
.cra_priority = KMB_OCS_ECC_PRIORITY,
.cra_module = THIS_MODULE,
.cra_ctxsize = sizeof(struct ocs_ecc_ctx),
},
+ .op.do_one_request = kmb_ocs_ecc_do_one_request,
};
-static struct kpp_alg ocs_ecdh_p384 = {
- .set_secret = kmb_ocs_ecdh_set_secret,
- .generate_public_key = kmb_ocs_ecdh_generate_public_key,
- .compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
- .init = kmb_ocs_ecdh_nist_p384_init_tfm,
- .exit = kmb_ocs_ecdh_exit_tfm,
- .max_size = kmb_ocs_ecdh_max_size,
- .base = {
+static struct kpp_engine_alg ocs_ecdh_p384 = {
+ .base.set_secret = kmb_ocs_ecdh_set_secret,
+ .base.generate_public_key = kmb_ocs_ecdh_generate_public_key,
+ .base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
+ .base.init = kmb_ocs_ecdh_nist_p384_init_tfm,
+ .base.exit = kmb_ocs_ecdh_exit_tfm,
+ .base.max_size = kmb_ocs_ecdh_max_size,
+ .base.base = {
.cra_name = "ecdh-nist-p384",
.cra_driver_name = "ecdh-nist-p384-keembay-ocs",
.cra_priority = KMB_OCS_ECC_PRIORITY,
.cra_module = THIS_MODULE,
.cra_ctxsize = sizeof(struct ocs_ecc_ctx),
},
+ .op.do_one_request = kmb_ocs_ecc_do_one_request,
};
static irqreturn_t ocs_ecc_irq_handler(int irq, void *dev_id)
@@ -941,14 +934,14 @@ static int kmb_ocs_ecc_probe(struct platform_device *pdev)
}
/* Register the KPP algo. */
- rc = crypto_register_kpp(&ocs_ecdh_p256);
+ rc = crypto_engine_register_kpp(&ocs_ecdh_p256);
if (rc) {
dev_err(dev,
"Could not register OCS algorithms with Crypto API\n");
goto cleanup;
}
- rc = crypto_register_kpp(&ocs_ecdh_p384);
+ rc = crypto_engine_register_kpp(&ocs_ecdh_p384);
if (rc) {
dev_err(dev,
"Could not register OCS algorithms with Crypto API\n");
@@ -958,7 +951,7 @@ static int kmb_ocs_ecc_probe(struct platform_device *pdev)
return 0;
ocs_ecdh_p384_error:
- crypto_unregister_kpp(&ocs_ecdh_p256);
+ crypto_engine_unregister_kpp(&ocs_ecdh_p256);
cleanup:
crypto_engine_exit(ecc_dev->engine);
@@ -977,8 +970,8 @@ static int kmb_ocs_ecc_remove(struct platform_device *pdev)
ecc_dev = platform_get_drvdata(pdev);
- crypto_unregister_kpp(&ocs_ecdh_p384);
- crypto_unregister_kpp(&ocs_ecdh_p256);
+ crypto_engine_unregister_kpp(&ocs_ecdh_p384);
+ crypto_engine_unregister_kpp(&ocs_ecdh_p256);
spin_lock(&ocs_ecc.lock);
list_del(&ecc_dev->list);
diff --git a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c
index d4bcbed1f546..daba8ca05dbe 100644
--- a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c
+++ b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c
@@ -5,19 +5,21 @@
* Copyright (C) 2018-2020 Intel Corporation
*/
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-
#include <crypto/engine.h>
+#include <crypto/hmac.h>
+#include <crypto/internal/hash.h>
#include <crypto/scatterwalk.h>
#include <crypto/sha2.h>
#include <crypto/sm3.h>
-#include <crypto/hmac.h>
-#include <crypto/internal/hash.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
#include "ocs-hcu.h"
@@ -34,7 +36,6 @@
/**
* struct ocs_hcu_ctx: OCS HCU Transform context.
- * @engine_ctx: Crypto Engine context.
* @hcu_dev: The OCS HCU device used by the transformation.
* @key: The key (used only for HMAC transformations).
* @key_len: The length of the key.
@@ -42,7 +43,6 @@
* @is_hmac_tfm: Whether or not this is a HMAC transformation.
*/
struct ocs_hcu_ctx {
- struct crypto_engine_ctx engine_ctx;
struct ocs_hcu_dev *hcu_dev;
u8 key[SHA512_BLOCK_SIZE];
size_t key_len;
@@ -824,11 +824,6 @@ static void __cra_init(struct crypto_tfm *tfm, struct ocs_hcu_ctx *ctx)
{
crypto_ahash_set_reqsize_dma(__crypto_ahash_cast(tfm),
sizeof(struct ocs_hcu_rctx));
-
- /* Init context to 0. */
- memzero_explicit(ctx, sizeof(*ctx));
- /* Set engine ops. */
- ctx->engine_ctx.op.do_one_request = kmb_ocs_hcu_do_one_request;
}
static int kmb_ocs_hcu_sha_cra_init(struct crypto_tfm *tfm)
@@ -883,17 +878,17 @@ static void kmb_ocs_hcu_hmac_cra_exit(struct crypto_tfm *tfm)
memzero_explicit(ctx->key, sizeof(ctx->key));
}
-static struct ahash_alg ocs_hcu_algs[] = {
+static struct ahash_engine_alg ocs_hcu_algs[] = {
#ifdef CONFIG_CRYPTO_DEV_KEEMBAY_OCS_HCU_HMAC_SHA224
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -907,18 +902,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_module = THIS_MODULE,
.cra_init = kmb_ocs_hcu_sha_cra_init,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .setkey = kmb_ocs_hcu_setkey,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.setkey = kmb_ocs_hcu_setkey,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -933,18 +929,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_init = kmb_ocs_hcu_hmac_cra_init,
.cra_exit = kmb_ocs_hcu_hmac_cra_exit,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
#endif /* CONFIG_CRYPTO_DEV_KEEMBAY_OCS_HCU_HMAC_SHA224 */
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -958,18 +955,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_module = THIS_MODULE,
.cra_init = kmb_ocs_hcu_sha_cra_init,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .setkey = kmb_ocs_hcu_setkey,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.setkey = kmb_ocs_hcu_setkey,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -984,17 +982,18 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_init = kmb_ocs_hcu_hmac_cra_init,
.cra_exit = kmb_ocs_hcu_hmac_cra_exit,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.halg = {
.digestsize = SM3_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1008,18 +1007,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_module = THIS_MODULE,
.cra_init = kmb_ocs_hcu_sm3_cra_init,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .setkey = kmb_ocs_hcu_setkey,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.setkey = kmb_ocs_hcu_setkey,
+ .base.halg = {
.digestsize = SM3_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1034,17 +1034,18 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_init = kmb_ocs_hcu_hmac_sm3_cra_init,
.cra_exit = kmb_ocs_hcu_hmac_cra_exit,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1058,18 +1059,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_module = THIS_MODULE,
.cra_init = kmb_ocs_hcu_sha_cra_init,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .setkey = kmb_ocs_hcu_setkey,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.setkey = kmb_ocs_hcu_setkey,
+ .base.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1084,17 +1086,18 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_init = kmb_ocs_hcu_hmac_cra_init,
.cra_exit = kmb_ocs_hcu_hmac_cra_exit,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.halg = {
.digestsize = SHA512_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1108,18 +1111,19 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_module = THIS_MODULE,
.cra_init = kmb_ocs_hcu_sha_cra_init,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
{
- .init = kmb_ocs_hcu_init,
- .update = kmb_ocs_hcu_update,
- .final = kmb_ocs_hcu_final,
- .finup = kmb_ocs_hcu_finup,
- .digest = kmb_ocs_hcu_digest,
- .export = kmb_ocs_hcu_export,
- .import = kmb_ocs_hcu_import,
- .setkey = kmb_ocs_hcu_setkey,
- .halg = {
+ .base.init = kmb_ocs_hcu_init,
+ .base.update = kmb_ocs_hcu_update,
+ .base.final = kmb_ocs_hcu_final,
+ .base.finup = kmb_ocs_hcu_finup,
+ .base.digest = kmb_ocs_hcu_digest,
+ .base.export = kmb_ocs_hcu_export,
+ .base.import = kmb_ocs_hcu_import,
+ .base.setkey = kmb_ocs_hcu_setkey,
+ .base.halg = {
.digestsize = SHA512_DIGEST_SIZE,
.statesize = sizeof(struct ocs_hcu_rctx),
.base = {
@@ -1134,7 +1138,8 @@ static struct ahash_alg ocs_hcu_algs[] = {
.cra_init = kmb_ocs_hcu_hmac_cra_init,
.cra_exit = kmb_ocs_hcu_hmac_cra_exit,
}
- }
+ },
+ .op.do_one_request = kmb_ocs_hcu_do_one_request,
},
};
@@ -1155,7 +1160,7 @@ static int kmb_ocs_hcu_remove(struct platform_device *pdev)
if (!hcu_dev)
return -ENODEV;
- crypto_unregister_ahashes(ocs_hcu_algs, ARRAY_SIZE(ocs_hcu_algs));
+ crypto_engine_unregister_ahashes(ocs_hcu_algs, ARRAY_SIZE(ocs_hcu_algs));
rc = crypto_engine_exit(hcu_dev->engine);
@@ -1170,7 +1175,6 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ocs_hcu_dev *hcu_dev;
- struct resource *hcu_mem;
int rc;
hcu_dev = devm_kzalloc(dev, sizeof(*hcu_dev), GFP_KERNEL);
@@ -1184,14 +1188,7 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev)
if (rc)
return rc;
- /* Get the memory address and remap. */
- hcu_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!hcu_mem) {
- dev_err(dev, "Could not retrieve io mem resource.\n");
- return -ENODEV;
- }
-
- hcu_dev->io_base = devm_ioremap_resource(dev, hcu_mem);
+ hcu_dev->io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hcu_dev->io_base))
return PTR_ERR(hcu_dev->io_base);
@@ -1231,7 +1228,7 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev)
/* Security infrastructure guarantees OCS clock is enabled. */
- rc = crypto_register_ahashes(ocs_hcu_algs, ARRAY_SIZE(ocs_hcu_algs));
+ rc = crypto_engine_register_ahashes(ocs_hcu_algs, ARRAY_SIZE(ocs_hcu_algs));
if (rc) {
dev_err(dev, "Could not register algorithms.\n");
goto cleanup;
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
index e543a9e24a06..dd4464b7e00b 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c
@@ -3,11 +3,13 @@
#include <linux/iopoll.h>
#include <adf_accel_devices.h>
#include <adf_cfg.h>
+#include <adf_clock.h>
#include <adf_common_drv.h>
#include <adf_gen4_dc.h>
#include <adf_gen4_hw_data.h>
#include <adf_gen4_pfvf.h>
#include <adf_gen4_pm.h>
+#include <adf_gen4_timer.h>
#include "adf_4xxx_hw_data.h"
#include "icp_qat_hw.h"
@@ -223,6 +225,8 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev)
ICP_ACCEL_CAPABILITIES_HKDF |
ICP_ACCEL_CAPABILITIES_CHACHA_POLY |
ICP_ACCEL_CAPABILITIES_AESGCM_SPC |
+ ICP_ACCEL_CAPABILITIES_SM3 |
+ ICP_ACCEL_CAPABILITIES_SM4 |
ICP_ACCEL_CAPABILITIES_AES_V2;
/* A set bit in fusectl1 means the feature is OFF in this SKU */
@@ -246,12 +250,19 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev)
capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER;
}
+ if (fusectl1 & ICP_ACCEL_4XXX_MASK_SMX_SLICE) {
+ capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM3;
+ capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM4;
+ }
+
capabilities_asym = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC |
ICP_ACCEL_CAPABILITIES_CIPHER |
+ ICP_ACCEL_CAPABILITIES_SM2 |
ICP_ACCEL_CAPABILITIES_ECEDMONT;
if (fusectl1 & ICP_ACCEL_4XXX_MASK_PKE_SLICE) {
capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
+ capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_SM2;
capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_ECEDMONT;
}
@@ -317,6 +328,14 @@ static void get_admin_info(struct admin_info *admin_csrs_info)
admin_csrs_info->admin_msg_lr = ADF_4XXX_ADMINMSGLR_OFFSET;
}
+static u32 get_heartbeat_clock(struct adf_hw_device_data *self)
+{
+ /*
+ * 4XXX uses KPT counter for HB
+ */
+ return ADF_4XXX_KPT_COUNTER_FREQ;
+}
+
static void adf_enable_error_correction(struct adf_accel_dev *accel_dev)
{
struct adf_bar *misc_bar = &GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR];
@@ -508,6 +527,10 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id)
hw_data->enable_pm = adf_gen4_enable_pm;
hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt;
hw_data->dev_config = adf_gen4_dev_config;
+ hw_data->start_timer = adf_gen4_timer_start;
+ hw_data->stop_timer = adf_gen4_timer_stop;
+ hw_data->get_hb_clock = get_heartbeat_clock;
+ hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE;
adf_gen4_init_hw_csr_ops(&hw_data->csr_ops);
adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h
index e5b314d2b60e..bb3d95a8fb21 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h
@@ -3,6 +3,7 @@
#ifndef ADF_4XXX_HW_DATA_H_
#define ADF_4XXX_HW_DATA_H_
+#include <linux/units.h>
#include <adf_accel_devices.h>
/* PCIe configuration space */
@@ -64,6 +65,9 @@
#define ADF_402XX_ASYM_OBJ "qat_402xx_asym.bin"
#define ADF_402XX_ADMIN_OBJ "qat_402xx_admin.bin"
+/* Clocks frequency */
+#define ADF_4XXX_KPT_COUNTER_FREQ (100 * HZ_PER_MHZ)
+
/* qat_4xxx fuse bits are different from old GENs, redefine them */
enum icp_qat_4xxx_slice_mask {
ICP_ACCEL_4XXX_MASK_CIPHER_SLICE = BIT(0),
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
index 1a15600361d0..6d4e2e139ffa 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
@@ -8,6 +8,7 @@
#include <adf_cfg.h>
#include <adf_common_drv.h>
#include <adf_dbgfs.h>
+#include <adf_heartbeat.h>
#include "adf_4xxx_hw_data.h"
#include "qat_compression.h"
@@ -77,6 +78,8 @@ static int adf_cfg_dev_init(struct adf_accel_dev *accel_dev)
if (ret)
return ret;
+ adf_heartbeat_save_cfg_param(accel_dev, ADF_CFG_HB_TIMER_MIN_MS);
+
return 0;
}
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c
index 475643654e64..9c00c441b602 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
/* Copyright(c) 2014 - 2021 Intel Corporation */
#include <adf_accel_devices.h>
+#include <adf_clock.h>
#include <adf_common_drv.h>
#include <adf_gen2_config.h>
#include <adf_gen2_dc.h>
#include <adf_gen2_hw_data.h>
#include <adf_gen2_pfvf.h>
#include "adf_c3xxx_hw_data.h"
+#include "adf_heartbeat.h"
#include "icp_qat_hw.h"
/* Worker thread to service arbiter mappings */
@@ -50,6 +52,28 @@ static u32 get_ae_mask(struct adf_hw_device_data *self)
return ~(fuses | straps) & ADF_C3XXX_ACCELENGINES_MASK;
}
+static u32 get_ts_clock(struct adf_hw_device_data *self)
+{
+ /*
+ * Timestamp update interval is 16 AE clock ticks for c3xxx.
+ */
+ return self->clock_frequency / 16;
+}
+
+static int measure_clock(struct adf_accel_dev *accel_dev)
+{
+ u32 frequency;
+ int ret;
+
+ ret = adf_dev_measure_clock(accel_dev, &frequency, ADF_C3XXX_MIN_AE_FREQ,
+ ADF_C3XXX_MAX_AE_FREQ);
+ if (ret)
+ return ret;
+
+ accel_dev->hw_device->clock_frequency = frequency;
+ return 0;
+}
+
static u32 get_misc_bar_id(struct adf_hw_device_data *self)
{
return ADF_C3XXX_PMISC_BAR;
@@ -127,6 +151,10 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data)
hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer;
hw_data->disable_iov = adf_disable_sriov;
hw_data->dev_config = adf_gen2_dev_config;
+ hw_data->measure_clock = measure_clock;
+ hw_data->get_hb_clock = get_ts_clock;
+ hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE;
+ hw_data->check_hb_ctrs = adf_heartbeat_check_ctrs;
adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops);
adf_gen2_init_hw_csr_ops(&hw_data->csr_ops);
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.h b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.h
index 336a06f11dbd..690c6a1aa172 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.h
@@ -3,6 +3,8 @@
#ifndef ADF_C3XXX_HW_DATA_H_
#define ADF_C3XXX_HW_DATA_H_
+#include <linux/units.h>
+
/* PCIe configuration space */
#define ADF_C3XXX_PMISC_BAR 0
#define ADF_C3XXX_ETR_BAR 1
@@ -19,6 +21,11 @@
#define ADF_C3XXX_AE2FUNC_MAP_GRP_A_NUM_REGS 48
#define ADF_C3XXX_AE2FUNC_MAP_GRP_B_NUM_REGS 6
+/* Clocks frequency */
+#define ADF_C3XXX_AE_FREQ (685 * HZ_PER_MHZ)
+#define ADF_C3XXX_MIN_AE_FREQ (533 * HZ_PER_MHZ)
+#define ADF_C3XXX_MAX_AE_FREQ (685 * HZ_PER_MHZ)
+
/* Firmware Binary */
#define ADF_C3XXX_FW "qat_c3xxx.bin"
#define ADF_C3XXX_MMP "qat_c3xxx_mmp.bin"
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c
index e14270703670..355a781693eb 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
/* Copyright(c) 2014 - 2021 Intel Corporation */
#include <adf_accel_devices.h>
+#include <adf_clock.h>
#include <adf_common_drv.h>
#include <adf_gen2_config.h>
#include <adf_gen2_dc.h>
#include <adf_gen2_hw_data.h>
#include <adf_gen2_pfvf.h>
#include "adf_c62x_hw_data.h"
+#include "adf_heartbeat.h"
#include "icp_qat_hw.h"
/* Worker thread to service arbiter mappings */
@@ -50,6 +52,28 @@ static u32 get_ae_mask(struct adf_hw_device_data *self)
return ~(fuses | straps) & ADF_C62X_ACCELENGINES_MASK;
}
+static u32 get_ts_clock(struct adf_hw_device_data *self)
+{
+ /*
+ * Timestamp update interval is 16 AE clock ticks for c62x.
+ */
+ return self->clock_frequency / 16;
+}
+
+static int measure_clock(struct adf_accel_dev *accel_dev)
+{
+ u32 frequency;
+ int ret;
+
+ ret = adf_dev_measure_clock(accel_dev, &frequency, ADF_C62X_MIN_AE_FREQ,
+ ADF_C62X_MAX_AE_FREQ);
+ if (ret)
+ return ret;
+
+ accel_dev->hw_device->clock_frequency = frequency;
+ return 0;
+}
+
static u32 get_misc_bar_id(struct adf_hw_device_data *self)
{
return ADF_C62X_PMISC_BAR;
@@ -129,6 +153,10 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data)
hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer;
hw_data->disable_iov = adf_disable_sriov;
hw_data->dev_config = adf_gen2_dev_config;
+ hw_data->measure_clock = measure_clock;
+ hw_data->get_hb_clock = get_ts_clock;
+ hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE;
+ hw_data->check_hb_ctrs = adf_heartbeat_check_ctrs;
adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops);
adf_gen2_init_hw_csr_ops(&hw_data->csr_ops);
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.h b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.h
index 008c0a3a9769..13e6ebf6fd91 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.h
@@ -3,6 +3,8 @@
#ifndef ADF_C62X_HW_DATA_H_
#define ADF_C62X_HW_DATA_H_
+#include <linux/units.h>
+
/* PCIe configuration space */
#define ADF_C62X_SRAM_BAR 0
#define ADF_C62X_PMISC_BAR 1
@@ -19,6 +21,11 @@
#define ADF_C62X_AE2FUNC_MAP_GRP_A_NUM_REGS 80
#define ADF_C62X_AE2FUNC_MAP_GRP_B_NUM_REGS 10
+/* Clocks frequency */
+#define ADF_C62X_AE_FREQ (685 * HZ_PER_MHZ)
+#define ADF_C62X_MIN_AE_FREQ (533 * HZ_PER_MHZ)
+#define ADF_C62X_MAX_AE_FREQ (800 * HZ_PER_MHZ)
+
/* Firmware Binary */
#define ADF_C62X_FW "qat_c62x.bin"
#define ADF_C62X_MMP "qat_c62x_mmp.bin"
diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile
index 38de3aba6e8c..43622c7fca71 100644
--- a/drivers/crypto/intel/qat/qat_common/Makefile
+++ b/drivers/crypto/intel/qat/qat_common/Makefile
@@ -17,6 +17,8 @@ intel_qat-objs := adf_cfg.o \
adf_gen4_pm.o \
adf_gen2_dc.o \
adf_gen4_dc.o \
+ adf_gen4_timer.o \
+ adf_clock.o \
qat_crypto.o \
qat_compression.o \
qat_comp_algs.o \
@@ -28,6 +30,9 @@ intel_qat-objs := adf_cfg.o \
qat_bl.o
intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o \
+ adf_fw_counters.o \
+ adf_heartbeat.o \
+ adf_heartbeat_dbgfs.o \
adf_dbgfs.o
intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_vf_isr.o adf_pfvf_utils.o \
diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
index 0399417b91fc..e57abde66f4f 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
@@ -188,6 +188,11 @@ struct adf_hw_device_data {
int (*init_admin_comms)(struct adf_accel_dev *accel_dev);
void (*exit_admin_comms)(struct adf_accel_dev *accel_dev);
int (*send_admin_init)(struct adf_accel_dev *accel_dev);
+ int (*start_timer)(struct adf_accel_dev *accel_dev);
+ void (*stop_timer)(struct adf_accel_dev *accel_dev);
+ void (*check_hb_ctrs)(struct adf_accel_dev *accel_dev);
+ uint32_t (*get_hb_clock)(struct adf_hw_device_data *self);
+ int (*measure_clock)(struct adf_accel_dev *accel_dev);
int (*init_arb)(struct adf_accel_dev *accel_dev);
void (*exit_arb)(struct adf_accel_dev *accel_dev);
const u32 *(*get_arb_mapping)(struct adf_accel_dev *accel_dev);
@@ -229,6 +234,7 @@ struct adf_hw_device_data {
u8 num_accel;
u8 num_logical_accel;
u8 num_engines;
+ u32 num_hb_ctrs;
};
/* CSR write macro */
@@ -241,6 +247,11 @@ struct adf_hw_device_data {
#define ADF_CFG_NUM_SERVICES 4
#define ADF_SRV_TYPE_BIT_LEN 3
#define ADF_SRV_TYPE_MASK 0x7
+#define ADF_AE_ADMIN_THREAD 7
+#define ADF_NUM_THREADS_PER_AE 8
+#define ADF_NUM_PKE_STRAND 2
+#define ADF_AE_STRAND0_THREAD 8
+#define ADF_AE_STRAND1_THREAD 9
#define GET_DEV(accel_dev) ((accel_dev)->accel_pci_dev.pci_dev->dev)
#define GET_BARS(accel_dev) ((accel_dev)->accel_pci_dev.pci_bars)
@@ -292,9 +303,12 @@ struct adf_accel_dev {
unsigned long status;
atomic_t ref_count;
struct dentry *debugfs_dir;
+ struct dentry *fw_cntr_dbgfile;
struct list_head list;
struct module *owner;
struct adf_accel_pci accel_pci_dev;
+ struct adf_timer *timer;
+ struct adf_heartbeat *heartbeat;
union {
struct {
/* protects VF2PF interrupts access */
diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.c b/drivers/crypto/intel/qat/qat_common/adf_admin.c
index 118775ee02f2..ff790823b868 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_admin.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_admin.c
@@ -8,6 +8,7 @@
#include <linux/dma-mapping.h>
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
+#include "adf_heartbeat.h"
#include "icp_qat_fw_init_admin.h"
#define ADF_ADMIN_MAILBOX_STRIDE 0x1000
@@ -15,6 +16,7 @@
#define ADF_CONST_TABLE_SIZE 1024
#define ADF_ADMIN_POLL_DELAY_US 20
#define ADF_ADMIN_POLL_TIMEOUT_US (5 * USEC_PER_SEC)
+#define ADF_ONE_AE 1
static const u8 const_tab[1024] __aligned(1024) = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -194,6 +196,22 @@ static int adf_set_fw_constants(struct adf_accel_dev *accel_dev)
return adf_send_admin(accel_dev, &req, &resp, ae_mask);
}
+int adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp)
+{
+ struct icp_qat_fw_init_admin_req req = { };
+ struct icp_qat_fw_init_admin_resp resp;
+ unsigned int ae_mask = ADF_ONE_AE;
+ int ret;
+
+ req.cmd_id = ICP_QAT_FW_TIMER_GET;
+ ret = adf_send_admin(accel_dev, &req, &resp, ae_mask);
+ if (ret)
+ return ret;
+
+ *timestamp = resp.timestamp;
+ return 0;
+}
+
static int adf_get_dc_capabilities(struct adf_accel_dev *accel_dev,
u32 *capabilities)
{
@@ -223,6 +241,49 @@ static int adf_get_dc_capabilities(struct adf_accel_dev *accel_dev,
return 0;
}
+int adf_get_ae_fw_counters(struct adf_accel_dev *accel_dev, u16 ae, u64 *reqs, u64 *resps)
+{
+ struct icp_qat_fw_init_admin_resp resp = { };
+ struct icp_qat_fw_init_admin_req req = { };
+ int ret;
+
+ req.cmd_id = ICP_QAT_FW_COUNTERS_GET;
+
+ ret = adf_put_admin_msg_sync(accel_dev, ae, &req, &resp);
+ if (ret || resp.status)
+ return -EFAULT;
+
+ *reqs = resp.req_rec_count;
+ *resps = resp.resp_sent_count;
+
+ return 0;
+}
+
+int adf_send_admin_tim_sync(struct adf_accel_dev *accel_dev, u32 cnt)
+{
+ u32 ae_mask = accel_dev->hw_device->ae_mask;
+ struct icp_qat_fw_init_admin_req req = { };
+ struct icp_qat_fw_init_admin_resp resp = { };
+
+ req.cmd_id = ICP_QAT_FW_SYNC;
+ req.int_timer_ticks = cnt;
+
+ return adf_send_admin(accel_dev, &req, &resp, ae_mask);
+}
+
+int adf_send_admin_hb_timer(struct adf_accel_dev *accel_dev, uint32_t ticks)
+{
+ u32 ae_mask = accel_dev->hw_device->ae_mask;
+ struct icp_qat_fw_init_admin_req req = { };
+ struct icp_qat_fw_init_admin_resp resp;
+
+ req.cmd_id = ICP_QAT_FW_HEARTBEAT_TIMER_SET;
+ req.init_cfg_ptr = accel_dev->heartbeat->dma.phy_addr;
+ req.heartbeat_ticks = ticks;
+
+ return adf_send_admin(accel_dev, &req, &resp, ae_mask);
+}
+
/**
* adf_send_admin_init() - Function sends init message to FW
* @accel_dev: Pointer to acceleration device.
diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h
index 3ae1e5caee0e..6066dc637352 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_strings.h
@@ -47,4 +47,6 @@
#define ADF_ETRMGR_CORE_AFFINITY_FORMAT \
ADF_ETRMGR_BANK "%d" ADF_ETRMGR_CORE_AFFINITY
#define ADF_ACCEL_STR "Accelerator%d"
+#define ADF_HEARTBEAT_TIMER "HeartbeatTimer"
+
#endif
diff --git a/drivers/crypto/intel/qat/qat_common/adf_clock.c b/drivers/crypto/intel/qat/qat_common/adf_clock.c
new file mode 100644
index 000000000000..dc0778691eb0
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_clock.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation */
+
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/export.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/time64.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <asm/errno.h>
+#include "adf_accel_devices.h"
+#include "adf_clock.h"
+#include "adf_common_drv.h"
+
+#define MEASURE_CLOCK_RETRIES 10
+#define MEASURE_CLOCK_DELAY_US 10000
+#define ME_CLK_DIVIDER 16
+#define MEASURE_CLOCK_DELTA_THRESHOLD_US 100
+
+static inline u64 timespec_to_us(const struct timespec64 *ts)
+{
+ return (u64)DIV_ROUND_CLOSEST_ULL(timespec64_to_ns(ts), NSEC_PER_USEC);
+}
+
+static inline u64 timespec_to_ms(const struct timespec64 *ts)
+{
+ return (u64)DIV_ROUND_CLOSEST_ULL(timespec64_to_ns(ts), NSEC_PER_MSEC);
+}
+
+u64 adf_clock_get_current_time(void)
+{
+ struct timespec64 ts;
+
+ ktime_get_real_ts64(&ts);
+ return timespec_to_ms(&ts);
+}
+
+static int measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency)
+{
+ struct timespec64 ts1, ts2, ts3, ts4;
+ u64 timestamp1, timestamp2, temp;
+ u32 delta_us, tries;
+ int ret;
+
+ tries = MEASURE_CLOCK_RETRIES;
+ do {
+ ktime_get_real_ts64(&ts1);
+ ret = adf_get_fw_timestamp(accel_dev, &timestamp1);
+ if (ret) {
+ dev_err(&GET_DEV(accel_dev),
+ "Failed to get fw timestamp\n");
+ return ret;
+ }
+ ktime_get_real_ts64(&ts2);
+ delta_us = timespec_to_us(&ts2) - timespec_to_us(&ts1);
+ } while (delta_us > MEASURE_CLOCK_DELTA_THRESHOLD_US && --tries);
+
+ if (!tries) {
+ dev_err(&GET_DEV(accel_dev), "Excessive clock measure delay\n");
+ return -ETIMEDOUT;
+ }
+
+ fsleep(MEASURE_CLOCK_DELAY_US);
+
+ tries = MEASURE_CLOCK_RETRIES;
+ do {
+ ktime_get_real_ts64(&ts3);
+ if (adf_get_fw_timestamp(accel_dev, &timestamp2)) {
+ dev_err(&GET_DEV(accel_dev),
+ "Failed to get fw timestamp\n");
+ return -EIO;
+ }
+ ktime_get_real_ts64(&ts4);
+ delta_us = timespec_to_us(&ts4) - timespec_to_us(&ts3);
+ } while (delta_us > MEASURE_CLOCK_DELTA_THRESHOLD_US && --tries);
+
+ if (!tries) {
+ dev_err(&GET_DEV(accel_dev), "Excessive clock measure delay\n");
+ return -ETIMEDOUT;
+ }
+
+ delta_us = timespec_to_us(&ts3) - timespec_to_us(&ts1);
+ temp = (timestamp2 - timestamp1) * ME_CLK_DIVIDER * 10;
+ temp = DIV_ROUND_CLOSEST_ULL(temp, delta_us);
+ /*
+ * Enclose the division to allow the preprocessor to precalculate it,
+ * and avoid promoting r-value to 64-bit before division.
+ */
+ *frequency = temp * (HZ_PER_MHZ / 10);
+
+ return 0;
+}
+
+/**
+ * adf_dev_measure_clock() - measures device clock frequency
+ * @accel_dev: Pointer to acceleration device.
+ * @frequency: Pointer to variable where result will be stored
+ * @min: Minimal allowed frequency value
+ * @max: Maximal allowed frequency value
+ *
+ * If the measurement result will go beyond the min/max thresholds the value
+ * will take the value of the crossed threshold.
+ *
+ * This algorithm compares the device firmware timestamp with the kernel
+ * timestamp. So we can't expect too high accuracy from this measurement.
+ *
+ * Return:
+ * * 0 - measurement succeed
+ * * -ETIMEDOUT - measurement failed
+ */
+int adf_dev_measure_clock(struct adf_accel_dev *accel_dev,
+ u32 *frequency, u32 min, u32 max)
+{
+ int ret;
+ u32 freq;
+
+ ret = measure_clock(accel_dev, &freq);
+ if (ret)
+ return ret;
+
+ *frequency = clamp(freq, min, max);
+
+ if (*frequency != freq)
+ dev_warn(&GET_DEV(accel_dev),
+ "Measured clock %d Hz is out of range, assuming %d\n",
+ freq, *frequency);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adf_dev_measure_clock);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_clock.h b/drivers/crypto/intel/qat/qat_common/adf_clock.h
new file mode 100644
index 000000000000..e309bc0dc35c
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_clock.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2023 Intel Corporation */
+#ifndef ADF_CLOCK_H
+#define ADF_CLOCK_H
+
+#include <linux/types.h>
+
+struct adf_accel_dev;
+
+int adf_dev_measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency,
+ u32 min, u32 max);
+u64 adf_clock_get_current_time(void);
+
+#endif
diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
index b8132eb9bc2a..673b5044c62a 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
@@ -58,12 +58,6 @@ int adf_dev_restart(struct adf_accel_dev *accel_dev);
void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data);
void adf_clean_vf_map(bool);
-
-int adf_ctl_dev_register(void);
-void adf_ctl_dev_unregister(void);
-int adf_processes_dev_register(void);
-void adf_processes_dev_unregister(void);
-
int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev,
struct adf_accel_dev *pf);
void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev,
@@ -94,7 +88,11 @@ void adf_exit_aer(void);
int adf_init_admin_comms(struct adf_accel_dev *accel_dev);
void adf_exit_admin_comms(struct adf_accel_dev *accel_dev);
int adf_send_admin_init(struct adf_accel_dev *accel_dev);
+int adf_get_ae_fw_counters(struct adf_accel_dev *accel_dev, u16 ae, u64 *reqs, u64 *resps);
int adf_init_admin_pm(struct adf_accel_dev *accel_dev, u32 idle_delay);
+int adf_send_admin_tim_sync(struct adf_accel_dev *accel_dev, u32 cnt);
+int adf_send_admin_hb_timer(struct adf_accel_dev *accel_dev, uint32_t ticks);
+int adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp);
int adf_init_arb(struct adf_accel_dev *accel_dev);
void adf_exit_arb(struct adf_accel_dev *accel_dev);
void adf_update_ring_arb(struct adf_etr_ring_data *ring);
@@ -178,8 +176,6 @@ int qat_hal_init_rd_xfer(struct icp_qat_fw_loader_handle *handle,
int qat_hal_init_nn(struct icp_qat_fw_loader_handle *handle,
unsigned char ae, unsigned long ctx_mask,
unsigned short reg_num, unsigned int regdata);
-int qat_hal_wr_lm(struct icp_qat_fw_loader_handle *handle,
- unsigned char ae, unsigned short lm_addr, unsigned int value);
void qat_hal_set_ae_tindex_mode(struct icp_qat_fw_loader_handle *handle,
unsigned char ae, unsigned char mode);
int qat_uclo_wr_all_uimage(struct icp_qat_fw_loader_handle *handle);
@@ -193,6 +189,8 @@ int qat_uclo_set_cfg_ae_mask(struct icp_qat_fw_loader_handle *handle,
int adf_init_misc_wq(void);
void adf_exit_misc_wq(void);
bool adf_misc_wq_queue_work(struct work_struct *work);
+bool adf_misc_wq_queue_delayed_work(struct delayed_work *work,
+ unsigned long delay);
#if defined(CONFIG_PCI_IOV)
int adf_sriov_configure(struct pci_dev *pdev, int numvfs);
void adf_disable_sriov(struct adf_accel_dev *accel_dev);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c
index d0a2f892e6eb..04845f8d72be 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c
@@ -6,6 +6,8 @@
#include "adf_cfg.h"
#include "adf_common_drv.h"
#include "adf_dbgfs.h"
+#include "adf_fw_counters.h"
+#include "adf_heartbeat_dbgfs.h"
/**
* adf_dbgfs_init() - add persistent debugfs entries
@@ -56,6 +58,11 @@ void adf_dbgfs_add(struct adf_accel_dev *accel_dev)
{
if (!accel_dev->debugfs_dir)
return;
+
+ if (!accel_dev->is_vf) {
+ adf_fw_counters_dbgfs_add(accel_dev);
+ adf_heartbeat_dbgfs_add(accel_dev);
+ }
}
/**
@@ -66,4 +73,9 @@ void adf_dbgfs_rm(struct adf_accel_dev *accel_dev)
{
if (!accel_dev->debugfs_dir)
return;
+
+ if (!accel_dev->is_vf) {
+ adf_heartbeat_dbgfs_rm(accel_dev);
+ adf_fw_counters_dbgfs_rm(accel_dev);
+ }
}
diff --git a/drivers/crypto/intel/qat/qat_common/adf_fw_counters.c b/drivers/crypto/intel/qat/qat_common/adf_fw_counters.c
new file mode 100644
index 000000000000..cb6e09ef5c9f
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_fw_counters.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation */
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+#include "adf_accel_devices.h"
+#include "adf_common_drv.h"
+#include "adf_fw_counters.h"
+
+#define ADF_FW_COUNTERS_MAX_PADDING 16
+
+enum adf_fw_counters_types {
+ ADF_FW_REQUESTS,
+ ADF_FW_RESPONSES,
+ ADF_FW_COUNTERS_COUNT
+};
+
+static const char * const adf_fw_counter_names[] = {
+ [ADF_FW_REQUESTS] = "Requests",
+ [ADF_FW_RESPONSES] = "Responses",
+};
+
+static_assert(ARRAY_SIZE(adf_fw_counter_names) == ADF_FW_COUNTERS_COUNT);
+
+struct adf_ae_counters {
+ u16 ae;
+ u64 values[ADF_FW_COUNTERS_COUNT];
+};
+
+struct adf_fw_counters {
+ u16 ae_count;
+ struct adf_ae_counters ae_counters[];
+};
+
+static void adf_fw_counters_parse_ae_values(struct adf_ae_counters *ae_counters, u32 ae,
+ u64 req_count, u64 resp_count)
+{
+ ae_counters->ae = ae;
+ ae_counters->values[ADF_FW_REQUESTS] = req_count;
+ ae_counters->values[ADF_FW_RESPONSES] = resp_count;
+}
+
+static int adf_fw_counters_load_from_device(struct adf_accel_dev *accel_dev,
+ struct adf_fw_counters *fw_counters)
+{
+ struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
+ unsigned long ae_mask;
+ unsigned int i;
+ unsigned long ae;
+
+ /* Ignore the admin AEs */
+ ae_mask = hw_data->ae_mask & ~hw_data->admin_ae_mask;
+
+ if (hweight_long(ae_mask) > fw_counters->ae_count)
+ return -EINVAL;
+
+ i = 0;
+ for_each_set_bit(ae, &ae_mask, GET_MAX_ACCELENGINES(accel_dev)) {
+ u64 req_count, resp_count;
+ int ret;
+
+ ret = adf_get_ae_fw_counters(accel_dev, ae, &req_count, &resp_count);
+ if (ret)
+ return ret;
+
+ adf_fw_counters_parse_ae_values(&fw_counters->ae_counters[i++], ae,
+ req_count, resp_count);
+ }
+
+ return 0;
+}
+
+static struct adf_fw_counters *adf_fw_counters_allocate(unsigned long ae_count)
+{
+ struct adf_fw_counters *fw_counters;
+
+ if (unlikely(!ae_count))
+ return ERR_PTR(-EINVAL);
+
+ fw_counters = kmalloc(struct_size(fw_counters, ae_counters, ae_count), GFP_KERNEL);
+ if (!fw_counters)
+ return ERR_PTR(-ENOMEM);
+
+ fw_counters->ae_count = ae_count;
+
+ return fw_counters;
+}
+
+/**
+ * adf_fw_counters_get() - Return FW counters for the provided device.
+ * @accel_dev: Pointer to a QAT acceleration device
+ *
+ * Allocates and returns a table of counters containing execution statistics
+ * for each non-admin AE available through the supplied acceleration device.
+ * The caller becomes the owner of such memory and is responsible for
+ * the deallocation through a call to kfree().
+ *
+ * Returns: a pointer to a dynamically allocated struct adf_fw_counters
+ * on success, or a negative value on error.
+ */
+static struct adf_fw_counters *adf_fw_counters_get(struct adf_accel_dev *accel_dev)
+{
+ struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
+ struct adf_fw_counters *fw_counters;
+ unsigned long ae_count;
+ int ret;
+
+ if (!adf_dev_started(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev), "QAT Device not started\n");
+ return ERR_PTR(-EFAULT);
+ }
+
+ /* Ignore the admin AEs */
+ ae_count = hweight_long(hw_data->ae_mask & ~hw_data->admin_ae_mask);
+
+ fw_counters = adf_fw_counters_allocate(ae_count);
+ if (IS_ERR(fw_counters))
+ return fw_counters;
+
+ ret = adf_fw_counters_load_from_device(accel_dev, fw_counters);
+ if (ret) {
+ kfree(fw_counters);
+ dev_err(&GET_DEV(accel_dev),
+ "Failed to create QAT fw_counters file table [%d].\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return fw_counters;
+}
+
+static void *qat_fw_counters_seq_start(struct seq_file *sfile, loff_t *pos)
+{
+ struct adf_fw_counters *fw_counters = sfile->private;
+
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
+
+ if (*pos > fw_counters->ae_count)
+ return NULL;
+
+ return &fw_counters->ae_counters[*pos - 1];
+}
+
+static void *qat_fw_counters_seq_next(struct seq_file *sfile, void *v, loff_t *pos)
+{
+ struct adf_fw_counters *fw_counters = sfile->private;
+
+ (*pos)++;
+
+ if (*pos > fw_counters->ae_count)
+ return NULL;
+
+ return &fw_counters->ae_counters[*pos - 1];
+}
+
+static void qat_fw_counters_seq_stop(struct seq_file *sfile, void *v) {}
+
+static int qat_fw_counters_seq_show(struct seq_file *sfile, void *v)
+{
+ int i;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(sfile, "AE ");
+ for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
+ seq_printf(sfile, " %*s", ADF_FW_COUNTERS_MAX_PADDING,
+ adf_fw_counter_names[i]);
+ } else {
+ struct adf_ae_counters *ae_counters = (struct adf_ae_counters *)v;
+
+ seq_printf(sfile, "%2d:", ae_counters->ae);
+ for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
+ seq_printf(sfile, " %*llu", ADF_FW_COUNTERS_MAX_PADDING,
+ ae_counters->values[i]);
+ }
+ seq_putc(sfile, '\n');
+
+ return 0;
+}
+
+static const struct seq_operations qat_fw_counters_sops = {
+ .start = qat_fw_counters_seq_start,
+ .next = qat_fw_counters_seq_next,
+ .stop = qat_fw_counters_seq_stop,
+ .show = qat_fw_counters_seq_show,
+};
+
+static int qat_fw_counters_file_open(struct inode *inode, struct file *file)
+{
+ struct adf_accel_dev *accel_dev = inode->i_private;
+ struct seq_file *fw_counters_seq_file;
+ struct adf_fw_counters *fw_counters;
+ int ret;
+
+ fw_counters = adf_fw_counters_get(accel_dev);
+ if (IS_ERR(fw_counters))
+ return PTR_ERR(fw_counters);
+
+ ret = seq_open(file, &qat_fw_counters_sops);
+ if (unlikely(ret)) {
+ kfree(fw_counters);
+ return ret;
+ }
+
+ fw_counters_seq_file = file->private_data;
+ fw_counters_seq_file->private = fw_counters;
+ return ret;
+}
+
+static int qat_fw_counters_file_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+
+ kfree(seq->private);
+ seq->private = NULL;
+
+ return seq_release(inode, file); }
+
+static const struct file_operations qat_fw_counters_fops = {
+ .owner = THIS_MODULE,
+ .open = qat_fw_counters_file_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = qat_fw_counters_file_release,
+};
+
+/**
+ * adf_fw_counters_dbgfs_add() - Create a debugfs file containing FW
+ * execution counters.
+ * @accel_dev: Pointer to a QAT acceleration device
+ *
+ * Function creates a file to display a table with statistics for the given
+ * QAT acceleration device. The table stores device specific execution values
+ * for each AE, such as the number of requests sent to the FW and responses
+ * received from the FW.
+ *
+ * Return: void
+ */
+void adf_fw_counters_dbgfs_add(struct adf_accel_dev *accel_dev)
+{
+ accel_dev->fw_cntr_dbgfile = debugfs_create_file("fw_counters", 0400,
+ accel_dev->debugfs_dir,
+ accel_dev,
+ &qat_fw_counters_fops);
+}
+
+/**
+ * adf_fw_counters_dbgfs_rm() - Remove the debugfs file containing FW counters.
+ * @accel_dev: Pointer to a QAT acceleration device.
+ *
+ * Function removes the file providing the table of statistics for the given
+ * QAT acceleration device.
+ *
+ * Return: void
+ */
+void adf_fw_counters_dbgfs_rm(struct adf_accel_dev *accel_dev)
+{
+ debugfs_remove(accel_dev->fw_cntr_dbgfile);
+ accel_dev->fw_cntr_dbgfile = NULL;
+}
diff --git a/drivers/crypto/intel/qat/qat_common/adf_fw_counters.h b/drivers/crypto/intel/qat/qat_common/adf_fw_counters.h
new file mode 100644
index 000000000000..91b3b6a95f1f
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_fw_counters.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2023 Intel Corporation */
+#ifndef ADF_FW_COUNTERS_H
+#define ADF_FW_COUNTERS_H
+
+struct adf_accel_dev;
+
+void adf_fw_counters_dbgfs_add(struct adf_accel_dev *accel_dev);
+void adf_fw_counters_dbgfs_rm(struct adf_accel_dev *accel_dev);
+
+#endif
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen2_config.c b/drivers/crypto/intel/qat/qat_common/adf_gen2_config.c
index eeb30da7587a..c27ff6d18e11 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_gen2_config.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen2_config.c
@@ -7,6 +7,7 @@
#include "adf_common_drv.h"
#include "qat_crypto.h"
#include "qat_compression.h"
+#include "adf_heartbeat.h"
#include "adf_transport_access_macros.h"
static int adf_gen2_crypto_dev_config(struct adf_accel_dev *accel_dev)
@@ -195,6 +196,12 @@ int adf_gen2_dev_config(struct adf_accel_dev *accel_dev)
if (ret)
goto err;
+ ret = adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC);
+ if (ret)
+ goto err;
+
+ adf_heartbeat_save_cfg_param(accel_dev, ADF_CFG_HB_TIMER_DEFAULT_MS);
+
set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
return ret;
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.h b/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.h
index e4bc07529be4..6bd341061de4 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.h
@@ -145,6 +145,9 @@ do { \
#define ADF_GEN2_CERRSSMSH(i) ((i) * 0x4000 + 0x10)
#define ADF_GEN2_ERRSSMSH_EN BIT(3)
+/* Number of heartbeat counter pairs */
+#define ADF_NUM_HB_CNT_PER_AE ADF_NUM_THREADS_PER_AE
+
/* Interrupts */
#define ADF_GEN2_SMIAPF0_MASK_OFFSET (0x3A000 + 0x28)
#define ADF_GEN2_SMIAPF1_MASK_OFFSET (0x3A000 + 0x30)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h
index 4fb4b3df5a18..02d7a019ebf8 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h
@@ -136,6 +136,9 @@ do { \
#define ADF_GEN4_VFLNOTIFY BIT(7)
+/* Number of heartbeat counter pairs */
+#define ADF_NUM_HB_CNT_PER_AE ADF_NUM_THREADS_PER_AE
+
void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev);
void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops);
int adf_gen4_ring_pair_reset(struct adf_accel_dev *accel_dev, u32 bank_number);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h
index dd112923e006..c2768762cca3 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm.h
@@ -35,7 +35,7 @@
#define ADF_GEN4_PM_MSG_PENDING BIT(0)
#define ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK GENMASK(28, 1)
-#define ADF_GEN4_PM_DEFAULT_IDLE_FILTER (0x0)
+#define ADF_GEN4_PM_DEFAULT_IDLE_FILTER (0x6)
#define ADF_GEN4_PM_MAX_IDLE_FILTER (0x7)
#define ADF_GEN4_PM_DEFAULT_IDLE_SUPPORT (0x1)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.c
new file mode 100644
index 000000000000..646c57922fcd
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation */
+
+#include <linux/container_of.h>
+#include <linux/dev_printk.h>
+#include <linux/export.h>
+#include <linux/jiffies.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "adf_accel_devices.h"
+#include "adf_common_drv.h"
+#include "adf_gen4_timer.h"
+
+#define ADF_GEN4_TIMER_PERIOD_MS 200
+
+/* This periodic update is used to trigger HB, RL & TL fw events */
+static void work_handler(struct work_struct *work)
+{
+ struct adf_accel_dev *accel_dev;
+ struct adf_timer *timer_ctx;
+ u32 time_periods;
+
+ timer_ctx = container_of(to_delayed_work(work), struct adf_timer, work_ctx);
+ accel_dev = timer_ctx->accel_dev;
+
+ adf_misc_wq_queue_delayed_work(&timer_ctx->work_ctx,
+ msecs_to_jiffies(ADF_GEN4_TIMER_PERIOD_MS));
+
+ time_periods = div_u64(ktime_ms_delta(ktime_get_real(), timer_ctx->initial_ktime),
+ ADF_GEN4_TIMER_PERIOD_MS);
+
+ if (adf_send_admin_tim_sync(accel_dev, time_periods))
+ dev_err(&GET_DEV(accel_dev), "Failed to synchronize qat timer\n");
+}
+
+int adf_gen4_timer_start(struct adf_accel_dev *accel_dev)
+{
+ struct adf_timer *timer_ctx;
+
+ timer_ctx = kzalloc(sizeof(*timer_ctx), GFP_KERNEL);
+ if (!timer_ctx)
+ return -ENOMEM;
+
+ timer_ctx->accel_dev = accel_dev;
+ accel_dev->timer = timer_ctx;
+ timer_ctx->initial_ktime = ktime_get_real();
+
+ INIT_DELAYED_WORK(&timer_ctx->work_ctx, work_handler);
+ adf_misc_wq_queue_delayed_work(&timer_ctx->work_ctx,
+ msecs_to_jiffies(ADF_GEN4_TIMER_PERIOD_MS));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adf_gen4_timer_start);
+
+void adf_gen4_timer_stop(struct adf_accel_dev *accel_dev)
+{
+ struct adf_timer *timer_ctx = accel_dev->timer;
+
+ if (!timer_ctx)
+ return;
+
+ cancel_delayed_work_sync(&timer_ctx->work_ctx);
+
+ kfree(timer_ctx);
+ accel_dev->timer = NULL;
+}
+EXPORT_SYMBOL_GPL(adf_gen4_timer_stop);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.h
new file mode 100644
index 000000000000..66a709e7b358
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_timer.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2023 Intel Corporation */
+
+#ifndef ADF_GEN4_TIMER_H_
+#define ADF_GEN4_TIMER_H_
+
+#include <linux/ktime.h>
+#include <linux/workqueue.h>
+
+struct adf_accel_dev;
+
+struct adf_timer {
+ struct adf_accel_dev *accel_dev;
+ struct delayed_work work_ctx;
+ ktime_t initial_ktime;
+};
+
+int adf_gen4_timer_start(struct adf_accel_dev *accel_dev);
+void adf_gen4_timer_stop(struct adf_accel_dev *accel_dev);
+
+#endif /* ADF_GEN4_TIMER_H_ */
diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c
new file mode 100644
index 000000000000..beef9a5f6c75
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation */
+
+#include <linux/dev_printk.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/kstrtox.h>
+#include <linux/overflow.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <asm/errno.h>
+#include "adf_accel_devices.h"
+#include "adf_cfg.h"
+#include "adf_cfg_strings.h"
+#include "adf_clock.h"
+#include "adf_common_drv.h"
+#include "adf_heartbeat.h"
+#include "adf_transport_internal.h"
+#include "icp_qat_fw_init_admin.h"
+
+#define ADF_HB_EMPTY_SIG 0xA5A5A5A5
+
+/* Heartbeat counter pair */
+struct hb_cnt_pair {
+ __u16 resp_heartbeat_cnt;
+ __u16 req_heartbeat_cnt;
+};
+
+static int adf_hb_check_polling_freq(struct adf_accel_dev *accel_dev)
+{
+ u64 curr_time = adf_clock_get_current_time();
+ u64 polling_time = curr_time - accel_dev->heartbeat->last_hb_check_time;
+
+ if (polling_time < accel_dev->heartbeat->hb_timer) {
+ dev_warn(&GET_DEV(accel_dev),
+ "HB polling too frequent. Configured HB timer %d ms\n",
+ accel_dev->heartbeat->hb_timer);
+ return -EINVAL;
+ }
+
+ accel_dev->heartbeat->last_hb_check_time = curr_time;
+ return 0;
+}
+
+/**
+ * validate_hb_ctrs_cnt() - checks if the number of heartbeat counters should
+ * be updated by one to support the currently loaded firmware.
+ * @accel_dev: Pointer to acceleration device.
+ *
+ * Return:
+ * * true - hb_ctrs must increased by ADF_NUM_PKE_STRAND
+ * * false - no changes needed
+ */
+static bool validate_hb_ctrs_cnt(struct adf_accel_dev *accel_dev)
+{
+ const size_t hb_ctrs = accel_dev->hw_device->num_hb_ctrs;
+ const size_t max_aes = accel_dev->hw_device->num_engines;
+ const size_t hb_struct_size = sizeof(struct hb_cnt_pair);
+ const size_t exp_diff_size = array3_size(ADF_NUM_PKE_STRAND, max_aes,
+ hb_struct_size);
+ const size_t dev_ctrs = size_mul(max_aes, hb_ctrs);
+ const size_t stats_size = size_mul(dev_ctrs, hb_struct_size);
+ const u32 exp_diff_cnt = exp_diff_size / sizeof(u32);
+ const u32 stats_el_cnt = stats_size / sizeof(u32);
+ struct hb_cnt_pair *hb_stats = accel_dev->heartbeat->dma.virt_addr;
+ const u32 *mem_to_chk = (u32 *)(hb_stats + dev_ctrs);
+ u32 el_diff_cnt = 0;
+ int i;
+
+ /* count how many bytes are different from pattern */
+ for (i = 0; i < stats_el_cnt; i++) {
+ if (mem_to_chk[i] == ADF_HB_EMPTY_SIG)
+ break;
+
+ el_diff_cnt++;
+ }
+
+ return el_diff_cnt && el_diff_cnt == exp_diff_cnt;
+}
+
+void adf_heartbeat_check_ctrs(struct adf_accel_dev *accel_dev)
+{
+ struct hb_cnt_pair *hb_stats = accel_dev->heartbeat->dma.virt_addr;
+ const size_t hb_ctrs = accel_dev->hw_device->num_hb_ctrs;
+ const size_t max_aes = accel_dev->hw_device->num_engines;
+ const size_t dev_ctrs = size_mul(max_aes, hb_ctrs);
+ const size_t stats_size = size_mul(dev_ctrs, sizeof(struct hb_cnt_pair));
+ const size_t mem_items_to_fill = size_mul(stats_size, 2) / sizeof(u32);
+
+ /* fill hb stats memory with pattern */
+ memset32((uint32_t *)hb_stats, ADF_HB_EMPTY_SIG, mem_items_to_fill);
+ accel_dev->heartbeat->ctrs_cnt_checked = false;
+}
+EXPORT_SYMBOL_GPL(adf_heartbeat_check_ctrs);
+
+static int get_timer_ticks(struct adf_accel_dev *accel_dev, unsigned int *value)
+{
+ char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
+ u32 timer_ms = ADF_CFG_HB_TIMER_DEFAULT_MS;
+ int cfg_read_status;
+ u32 ticks;
+ int ret;
+
+ cfg_read_status = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
+ ADF_HEARTBEAT_TIMER, timer_str);
+ if (cfg_read_status == 0) {
+ if (kstrtouint(timer_str, 10, &timer_ms))
+ dev_dbg(&GET_DEV(accel_dev),
+ "kstrtouint failed to parse the %s, param value",
+ ADF_HEARTBEAT_TIMER);
+ }
+
+ if (timer_ms < ADF_CFG_HB_TIMER_MIN_MS) {
+ dev_err(&GET_DEV(accel_dev), "Timer cannot be less than %u\n",
+ ADF_CFG_HB_TIMER_MIN_MS);
+ return -EINVAL;
+ }
+
+ /*
+ * On 4xxx devices adf_timer is responsible for HB updates and
+ * its period is fixed to 200ms
+ */
+ if (accel_dev->timer)
+ timer_ms = ADF_CFG_HB_TIMER_MIN_MS;
+
+ ret = adf_heartbeat_ms_to_ticks(accel_dev, timer_ms, &ticks);
+ if (ret)
+ return ret;
+
+ adf_heartbeat_save_cfg_param(accel_dev, timer_ms);
+
+ accel_dev->heartbeat->hb_timer = timer_ms;
+ *value = ticks;
+
+ return 0;
+}
+
+static int check_ae(struct hb_cnt_pair *curr, struct hb_cnt_pair *prev,
+ u16 *count, const size_t hb_ctrs)
+{
+ size_t thr;
+
+ /* loop through all threads in AE */
+ for (thr = 0; thr < hb_ctrs; thr++) {
+ u16 req = curr[thr].req_heartbeat_cnt;
+ u16 resp = curr[thr].resp_heartbeat_cnt;
+ u16 last = prev[thr].resp_heartbeat_cnt;
+
+ if ((thr == ADF_AE_ADMIN_THREAD || req != resp) && resp == last) {
+ u16 retry = ++count[thr];
+
+ if (retry >= ADF_CFG_HB_COUNT_THRESHOLD)
+ return -EIO;
+
+ } else {
+ count[thr] = 0;
+ }
+ }
+ return 0;
+}
+
+static int adf_hb_get_status(struct adf_accel_dev *accel_dev)
+{
+ struct adf_hw_device_data *hw_device = accel_dev->hw_device;
+ struct hb_cnt_pair *live_stats, *last_stats, *curr_stats;
+ const size_t hb_ctrs = hw_device->num_hb_ctrs;
+ const unsigned long ae_mask = hw_device->ae_mask;
+ const size_t max_aes = hw_device->num_engines;
+ const size_t dev_ctrs = size_mul(max_aes, hb_ctrs);
+ const size_t stats_size = size_mul(dev_ctrs, sizeof(*curr_stats));
+ struct hb_cnt_pair *ae_curr_p, *ae_prev_p;
+ u16 *count_fails, *ae_count_p;
+ size_t ae_offset;
+ size_t ae = 0;
+ int ret = 0;
+
+ if (!accel_dev->heartbeat->ctrs_cnt_checked) {
+ if (validate_hb_ctrs_cnt(accel_dev))
+ hw_device->num_hb_ctrs += ADF_NUM_PKE_STRAND;
+
+ accel_dev->heartbeat->ctrs_cnt_checked = true;
+ }
+
+ live_stats = accel_dev->heartbeat->dma.virt_addr;
+ last_stats = live_stats + dev_ctrs;
+ count_fails = (u16 *)(last_stats + dev_ctrs);
+
+ curr_stats = kmemdup(live_stats, stats_size, GFP_KERNEL);
+ if (!curr_stats)
+ return -ENOMEM;
+
+ /* loop through active AEs */
+ for_each_set_bit(ae, &ae_mask, max_aes) {
+ ae_offset = size_mul(ae, hb_ctrs);
+ ae_curr_p = curr_stats + ae_offset;
+ ae_prev_p = last_stats + ae_offset;
+ ae_count_p = count_fails + ae_offset;
+
+ ret = check_ae(ae_curr_p, ae_prev_p, ae_count_p, hb_ctrs);
+ if (ret)
+ break;
+ }
+
+ /* Copy current stats for the next iteration */
+ memcpy(last_stats, curr_stats, stats_size);
+ kfree(curr_stats);
+
+ return ret;
+}
+
+void adf_heartbeat_status(struct adf_accel_dev *accel_dev,
+ enum adf_device_heartbeat_status *hb_status)
+{
+ struct adf_heartbeat *hb;
+
+ if (!adf_dev_started(accel_dev) ||
+ test_bit(ADF_STATUS_RESTARTING, &accel_dev->status)) {
+ *hb_status = HB_DEV_UNRESPONSIVE;
+ return;
+ }
+
+ if (adf_hb_check_polling_freq(accel_dev) == -EINVAL) {
+ *hb_status = HB_DEV_UNSUPPORTED;
+ return;
+ }
+
+ hb = accel_dev->heartbeat;
+ hb->hb_sent_counter++;
+
+ if (adf_hb_get_status(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev),
+ "Heartbeat ERROR: QAT is not responding.\n");
+ *hb_status = HB_DEV_UNRESPONSIVE;
+ hb->hb_failed_counter++;
+ return;
+ }
+
+ *hb_status = HB_DEV_ALIVE;
+}
+
+int adf_heartbeat_ms_to_ticks(struct adf_accel_dev *accel_dev, unsigned int time_ms,
+ u32 *value)
+{
+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+ u32 clk_per_sec;
+
+ /* HB clock may be different than AE clock */
+ if (!hw_data->get_hb_clock)
+ return -EINVAL;
+
+ clk_per_sec = hw_data->get_hb_clock(hw_data);
+ *value = time_ms * (clk_per_sec / MSEC_PER_SEC);
+
+ return 0;
+}
+
+int adf_heartbeat_save_cfg_param(struct adf_accel_dev *accel_dev,
+ unsigned int timer_ms)
+{
+ char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
+
+ snprintf(timer_str, sizeof(timer_str), "%u", timer_ms);
+ return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
+ ADF_HEARTBEAT_TIMER, timer_str,
+ ADF_STR);
+}
+EXPORT_SYMBOL_GPL(adf_heartbeat_save_cfg_param);
+
+int adf_heartbeat_init(struct adf_accel_dev *accel_dev)
+{
+ struct adf_heartbeat *hb;
+
+ hb = kzalloc(sizeof(*hb), GFP_KERNEL);
+ if (!hb)
+ goto err_ret;
+
+ hb->dma.virt_addr = dma_alloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE,
+ &hb->dma.phy_addr, GFP_KERNEL);
+ if (!hb->dma.virt_addr)
+ goto err_free;
+
+ /*
+ * Default set this flag as true to avoid unnecessary checks,
+ * it will be reset on platforms that need such a check
+ */
+ hb->ctrs_cnt_checked = true;
+ accel_dev->heartbeat = hb;
+
+ return 0;
+
+err_free:
+ kfree(hb);
+err_ret:
+ return -ENOMEM;
+}
+
+int adf_heartbeat_start(struct adf_accel_dev *accel_dev)
+{
+ unsigned int timer_ticks;
+ int ret;
+
+ if (!accel_dev->heartbeat) {
+ dev_warn(&GET_DEV(accel_dev), "Heartbeat instance not found!");
+ return -EFAULT;
+ }
+
+ if (accel_dev->hw_device->check_hb_ctrs)
+ accel_dev->hw_device->check_hb_ctrs(accel_dev);
+
+ ret = get_timer_ticks(accel_dev, &timer_ticks);
+ if (ret)
+ return ret;
+
+ ret = adf_send_admin_hb_timer(accel_dev, timer_ticks);
+ if (ret)
+ dev_warn(&GET_DEV(accel_dev), "Heartbeat not supported!");
+
+ return ret;
+}
+
+void adf_heartbeat_shutdown(struct adf_accel_dev *accel_dev)
+{
+ struct adf_heartbeat *hb = accel_dev->heartbeat;
+
+ if (!hb)
+ return;
+
+ if (hb->dma.virt_addr)
+ dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE,
+ hb->dma.virt_addr, hb->dma.phy_addr);
+
+ kfree(hb);
+ accel_dev->heartbeat = NULL;
+}
diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h
new file mode 100644
index 000000000000..b22e3cb29798
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2023 Intel Corporation */
+
+#ifndef ADF_HEARTBEAT_H_
+#define ADF_HEARTBEAT_H_
+
+#include <linux/types.h>
+
+struct adf_accel_dev;
+struct dentry;
+
+#define ADF_CFG_HB_TIMER_MIN_MS 200
+#define ADF_CFG_HB_TIMER_DEFAULT_MS 500
+#define ADF_CFG_HB_COUNT_THRESHOLD 3
+
+enum adf_device_heartbeat_status {
+ HB_DEV_UNRESPONSIVE = 0,
+ HB_DEV_ALIVE,
+ HB_DEV_UNSUPPORTED,
+};
+
+struct adf_heartbeat {
+ unsigned int hb_sent_counter;
+ unsigned int hb_failed_counter;
+ unsigned int hb_timer;
+ u64 last_hb_check_time;
+ bool ctrs_cnt_checked;
+ struct hb_dma_addr {
+ dma_addr_t phy_addr;
+ void *virt_addr;
+ } dma;
+ struct {
+ struct dentry *base_dir;
+ struct dentry *status;
+ struct dentry *cfg;
+ struct dentry *sent;
+ struct dentry *failed;
+ } dbgfs;
+};
+
+#ifdef CONFIG_DEBUG_FS
+int adf_heartbeat_init(struct adf_accel_dev *accel_dev);
+int adf_heartbeat_start(struct adf_accel_dev *accel_dev);
+void adf_heartbeat_shutdown(struct adf_accel_dev *accel_dev);
+
+int adf_heartbeat_ms_to_ticks(struct adf_accel_dev *accel_dev, unsigned int time_ms,
+ uint32_t *value);
+int adf_heartbeat_save_cfg_param(struct adf_accel_dev *accel_dev,
+ unsigned int timer_ms);
+void adf_heartbeat_status(struct adf_accel_dev *accel_dev,
+ enum adf_device_heartbeat_status *hb_status);
+void adf_heartbeat_check_ctrs(struct adf_accel_dev *accel_dev);
+
+#else
+static inline int adf_heartbeat_init(struct adf_accel_dev *accel_dev)
+{
+ return 0;
+}
+
+static inline int adf_heartbeat_start(struct adf_accel_dev *accel_dev)
+{
+ return 0;
+}
+
+static inline void adf_heartbeat_shutdown(struct adf_accel_dev *accel_dev)
+{
+}
+
+static inline int adf_heartbeat_save_cfg_param(struct adf_accel_dev *accel_dev,
+ unsigned int timer_ms)
+{
+ return 0;
+}
+
+static inline void adf_heartbeat_check_ctrs(struct adf_accel_dev *accel_dev)
+{
+}
+#endif
+#endif /* ADF_HEARTBEAT_H_ */
diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c
new file mode 100644
index 000000000000..803cbfd838f0
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation */
+
+#include <linux/debugfs.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kstrtox.h>
+#include <linux/types.h>
+#include "adf_cfg.h"
+#include "adf_common_drv.h"
+#include "adf_heartbeat.h"
+#include "adf_heartbeat_dbgfs.h"
+
+#define HB_OK 0
+#define HB_ERROR -1
+#define HB_STATUS_MAX_STRLEN 4
+#define HB_STATS_MAX_STRLEN 16
+
+static ssize_t adf_hb_stats_read(struct file *file, char __user *user_buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[HB_STATS_MAX_STRLEN];
+ unsigned int *value;
+ int len;
+
+ if (*ppos > 0)
+ return 0;
+
+ value = file->private_data;
+ len = scnprintf(buf, sizeof(buf), "%u\n", *value);
+
+ return simple_read_from_buffer(user_buffer, count, ppos, buf, len + 1);
+}
+
+static const struct file_operations adf_hb_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = adf_hb_stats_read,
+};
+
+static ssize_t adf_hb_status_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ enum adf_device_heartbeat_status hb_status;
+ char ret_str[HB_STATUS_MAX_STRLEN];
+ struct adf_accel_dev *accel_dev;
+ int ret_code;
+ size_t len;
+
+ if (*ppos > 0)
+ return 0;
+
+ accel_dev = file->private_data;
+ ret_code = HB_OK;
+
+ adf_heartbeat_status(accel_dev, &hb_status);
+
+ if (hb_status != HB_DEV_ALIVE)
+ ret_code = HB_ERROR;
+
+ len = scnprintf(ret_str, sizeof(ret_str), "%d\n", ret_code);
+
+ return simple_read_from_buffer(user_buf, count, ppos, ret_str, len + 1);
+}
+
+static const struct file_operations adf_hb_status_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = adf_hb_status_read,
+};
+
+static ssize_t adf_hb_cfg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char timer_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
+ struct adf_accel_dev *accel_dev;
+ unsigned int timer_ms;
+ int len;
+
+ if (*ppos > 0)
+ return 0;
+
+ accel_dev = file->private_data;
+ timer_ms = accel_dev->heartbeat->hb_timer;
+ len = scnprintf(timer_str, sizeof(timer_str), "%u\n", timer_ms);
+
+ return simple_read_from_buffer(user_buf, count, ppos, timer_str,
+ len + 1);
+}
+
+static ssize_t adf_hb_cfg_write(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char input_str[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
+ struct adf_accel_dev *accel_dev;
+ int ret, written_chars;
+ unsigned int timer_ms;
+ u32 ticks;
+
+ accel_dev = file->private_data;
+ timer_ms = ADF_CFG_HB_TIMER_DEFAULT_MS;
+
+ /* last byte left as string termination */
+ if (count > sizeof(input_str) - 1)
+ return -EINVAL;
+
+ written_chars = simple_write_to_buffer(input_str, sizeof(input_str) - 1,
+ ppos, user_buf, count);
+ if (written_chars > 0) {
+ ret = kstrtouint(input_str, 10, &timer_ms);
+ if (ret) {
+ dev_err(&GET_DEV(accel_dev),
+ "heartbeat_cfg: Invalid value\n");
+ return ret;
+ }
+
+ if (timer_ms < ADF_CFG_HB_TIMER_MIN_MS) {
+ dev_err(&GET_DEV(accel_dev),
+ "heartbeat_cfg: Invalid value\n");
+ return -EINVAL;
+ }
+
+ /*
+ * On 4xxx devices adf_timer is responsible for HB updates and
+ * its period is fixed to 200ms
+ */
+ if (accel_dev->timer)
+ timer_ms = ADF_CFG_HB_TIMER_MIN_MS;
+
+ ret = adf_heartbeat_save_cfg_param(accel_dev, timer_ms);
+ if (ret)
+ return ret;
+
+ ret = adf_heartbeat_ms_to_ticks(accel_dev, timer_ms, &ticks);
+ if (ret)
+ return ret;
+
+ ret = adf_send_admin_hb_timer(accel_dev, ticks);
+ if (ret)
+ return ret;
+
+ accel_dev->heartbeat->hb_timer = timer_ms;
+ }
+
+ return written_chars;
+}
+
+static const struct file_operations adf_hb_cfg_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = adf_hb_cfg_read,
+ .write = adf_hb_cfg_write,
+};
+
+void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev)
+{
+ struct adf_heartbeat *hb = accel_dev->heartbeat;
+
+ if (!hb)
+ return;
+
+ hb->dbgfs.base_dir = debugfs_create_dir("heartbeat", accel_dev->debugfs_dir);
+ hb->dbgfs.status = debugfs_create_file("status", 0400, hb->dbgfs.base_dir,
+ accel_dev, &adf_hb_status_fops);
+ hb->dbgfs.sent = debugfs_create_file("queries_sent", 0400, hb->dbgfs.base_dir,
+ &hb->hb_sent_counter, &adf_hb_stats_fops);
+ hb->dbgfs.failed = debugfs_create_file("queries_failed", 0400, hb->dbgfs.base_dir,
+ &hb->hb_failed_counter, &adf_hb_stats_fops);
+ hb->dbgfs.cfg = debugfs_create_file("config", 0600, hb->dbgfs.base_dir,
+ accel_dev, &adf_hb_cfg_fops);
+}
+EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_add);
+
+void adf_heartbeat_dbgfs_rm(struct adf_accel_dev *accel_dev)
+{
+ struct adf_heartbeat *hb = accel_dev->heartbeat;
+
+ if (!hb)
+ return;
+
+ debugfs_remove(hb->dbgfs.status);
+ hb->dbgfs.status = NULL;
+ debugfs_remove(hb->dbgfs.sent);
+ hb->dbgfs.sent = NULL;
+ debugfs_remove(hb->dbgfs.failed);
+ hb->dbgfs.failed = NULL;
+ debugfs_remove(hb->dbgfs.cfg);
+ hb->dbgfs.cfg = NULL;
+ debugfs_remove(hb->dbgfs.base_dir);
+ hb->dbgfs.base_dir = NULL;
+}
+EXPORT_SYMBOL_GPL(adf_heartbeat_dbgfs_rm);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.h b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.h
new file mode 100644
index 000000000000..84dd29ea6454
--- /dev/null
+++ b/drivers/crypto/intel/qat/qat_common/adf_heartbeat_dbgfs.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2023 Intel Corporation */
+
+#ifndef ADF_HEARTBEAT_DBGFS_H_
+#define ADF_HEARTBEAT_DBGFS_H_
+
+struct adf_accel_dev;
+
+void adf_heartbeat_dbgfs_add(struct adf_accel_dev *accel_dev);
+void adf_heartbeat_dbgfs_rm(struct adf_accel_dev *accel_dev);
+
+#endif /* ADF_HEARTBEAT_DBGFS_H_ */
diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c
index 826179c98524..89001fe92e76 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_init.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_init.c
@@ -8,6 +8,7 @@
#include "adf_cfg.h"
#include "adf_common_drv.h"
#include "adf_dbgfs.h"
+#include "adf_heartbeat.h"
static LIST_HEAD(service_table);
static DEFINE_MUTEX(service_lock);
@@ -129,6 +130,8 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev)
return -EFAULT;
}
+ adf_heartbeat_init(accel_dev);
+
/*
* Subservice initialisation is divided into two stages: init and start.
* This is to facilitate any ordering dependencies between services
@@ -163,6 +166,7 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
struct adf_hw_device_data *hw_data = accel_dev->hw_device;
struct service_hndl *service;
struct list_head *list_itr;
+ int ret;
set_bit(ADF_STATUS_STARTING, &accel_dev->status);
@@ -177,6 +181,14 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
return -EFAULT;
}
+ if (hw_data->measure_clock) {
+ ret = hw_data->measure_clock(accel_dev);
+ if (ret) {
+ dev_err(&GET_DEV(accel_dev), "Failed measure device clock\n");
+ return ret;
+ }
+ }
+
/* Set ssm watch dog timer */
if (hw_data->set_ssm_wdtimer)
hw_data->set_ssm_wdtimer(accel_dev);
@@ -187,6 +199,16 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
return -EFAULT;
}
+ if (hw_data->start_timer) {
+ ret = hw_data->start_timer(accel_dev);
+ if (ret) {
+ dev_err(&GET_DEV(accel_dev), "Failed to start internal sync timer\n");
+ return ret;
+ }
+ }
+
+ adf_heartbeat_start(accel_dev);
+
list_for_each(list_itr, &service_table) {
service = list_entry(list_itr, struct service_hndl, list);
if (service->event_hld(accel_dev, ADF_EVENT_START)) {
@@ -235,6 +257,7 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
*/
static void adf_dev_stop(struct adf_accel_dev *accel_dev)
{
+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;
struct service_hndl *service;
struct list_head *list_itr;
bool wait = false;
@@ -270,6 +293,9 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev)
}
}
+ if (hw_data->stop_timer)
+ hw_data->stop_timer(accel_dev);
+
if (wait)
msleep(100);
@@ -326,6 +352,8 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
clear_bit(accel_dev->accel_id, service->init_status);
}
+ adf_heartbeat_shutdown(accel_dev);
+
hw_data->disable_iov(accel_dev);
if (test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status)) {
diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c
index ad9e135b8560..2aba194a7c29 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_isr.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c
@@ -380,3 +380,9 @@ bool adf_misc_wq_queue_work(struct work_struct *work)
{
return queue_work(adf_misc_wq, work);
}
+
+bool adf_misc_wq_queue_delayed_work(struct delayed_work *work,
+ unsigned long delay)
+{
+ return queue_delayed_work(adf_misc_wq, work, delay);
+}
diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h
index 56cb827f93ea..3e968a4bcc9c 100644
--- a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h
+++ b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h
@@ -16,6 +16,8 @@ enum icp_qat_fw_init_admin_cmd_id {
ICP_QAT_FW_HEARTBEAT_SYNC = 7,
ICP_QAT_FW_HEARTBEAT_GET = 8,
ICP_QAT_FW_COMP_CAPABILITY_GET = 9,
+ ICP_QAT_FW_HEARTBEAT_TIMER_SET = 13,
+ ICP_QAT_FW_TIMER_GET = 19,
ICP_QAT_FW_PM_STATE_CONFIG = 128,
};
@@ -37,6 +39,12 @@ struct icp_qat_fw_init_admin_req {
__u16 ibuf_size_in_kb;
__u16 resrvd3;
};
+ struct {
+ __u32 int_timer_ticks;
+ };
+ struct {
+ __u32 heartbeat_ticks;
+ };
__u32 idle_filter;
};
@@ -97,19 +105,6 @@ struct icp_qat_fw_init_admin_resp {
};
} __packed;
-#define ICP_QAT_FW_COMN_HEARTBEAT_OK 0
-#define ICP_QAT_FW_COMN_HEARTBEAT_BLOCKED 1
-#define ICP_QAT_FW_COMN_HEARTBEAT_FLAG_BITPOS 0
-#define ICP_QAT_FW_COMN_HEARTBEAT_FLAG_MASK 0x1
-#define ICP_QAT_FW_COMN_STATUS_RESRVD_FLD_MASK 0xFE
-#define ICP_QAT_FW_COMN_HEARTBEAT_HDR_FLAG_GET(hdr_t) \
- ICP_QAT_FW_COMN_HEARTBEAT_FLAG_GET(hdr_t.flags)
-
-#define ICP_QAT_FW_COMN_HEARTBEAT_HDR_FLAG_SET(hdr_t, val) \
- ICP_QAT_FW_COMN_HEARTBEAT_FLAG_SET(hdr_t, val)
+#define ICP_QAT_FW_SYNC ICP_QAT_FW_HEARTBEAT_SYNC
-#define ICP_QAT_FW_COMN_HEARTBEAT_FLAG_GET(flags) \
- QAT_FIELD_GET(flags, \
- ICP_QAT_FW_COMN_HEARTBEAT_FLAG_BITPOS, \
- ICP_QAT_FW_COMN_HEARTBEAT_FLAG_MASK)
#endif
diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h
index a65059e56248..0c8883e2ccc6 100644
--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h
+++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h
@@ -97,7 +97,10 @@ enum icp_qat_capabilities_mask {
ICP_ACCEL_CAPABILITIES_SHA3_EXT = BIT(15),
ICP_ACCEL_CAPABILITIES_AESGCM_SPC = BIT(16),
ICP_ACCEL_CAPABILITIES_CHACHA_POLY = BIT(17),
- /* Bits 18-21 are currently reserved */
+ ICP_ACCEL_CAPABILITIES_SM2 = BIT(18),
+ ICP_ACCEL_CAPABILITIES_SM3 = BIT(19),
+ ICP_ACCEL_CAPABILITIES_SM4 = BIT(20),
+ /* Bit 21 is currently reserved */
ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY = BIT(22),
ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64 = BIT(23),
ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION = BIT(24),
diff --git a/drivers/crypto/intel/qat/qat_common/qat_compression.c b/drivers/crypto/intel/qat/qat_common/qat_compression.c
index 3f1f35283266..7842a9f22178 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_compression.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_compression.c
@@ -234,8 +234,7 @@ static void qat_free_dc_data(struct adf_accel_dev *accel_dev)
dma_unmap_single(dev, dc_data->ovf_buff_p, dc_data->ovf_buff_sz,
DMA_FROM_DEVICE);
- memset(dc_data->ovf_buff, 0, dc_data->ovf_buff_sz);
- kfree(dc_data->ovf_buff);
+ kfree_sensitive(dc_data->ovf_buff);
devm_kfree(dev, dc_data);
accel_dev->dc_data = NULL;
}
diff --git a/drivers/crypto/intel/qat/qat_common/qat_uclo.c b/drivers/crypto/intel/qat/qat_common/qat_uclo.c
index ce837bcc1cab..4bd150d1441a 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_uclo.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_uclo.c
@@ -11,7 +11,7 @@
#include "icp_qat_hal.h"
#include "icp_qat_fw_loader_handle.h"
-#define UWORD_CPYBUF_SIZE 1024
+#define UWORD_CPYBUF_SIZE 1024U
#define INVLD_UWORD 0xffffffffffull
#define PID_MINOR_REV 0xf
#define PID_MAJOR_REV (0xf << 4)
@@ -1986,10 +1986,7 @@ static void qat_uclo_wr_uimage_raw_page(struct icp_qat_fw_loader_handle *handle,
uw_relative_addr = 0;
words_num = encap_page->micro_words_num;
while (words_num) {
- if (words_num < UWORD_CPYBUF_SIZE)
- cpylen = words_num;
- else
- cpylen = UWORD_CPYBUF_SIZE;
+ cpylen = min(words_num, UWORD_CPYBUF_SIZE);
/* load the buffer */
for (i = 0; i < cpylen; i++)
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
index 1ebe0b351fae..09551f949126 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
@@ -7,6 +7,7 @@
#include <adf_gen2_hw_data.h>
#include <adf_gen2_pfvf.h>
#include "adf_dh895xcc_hw_data.h"
+#include "adf_heartbeat.h"
#include "icp_qat_hw.h"
#define ADF_DH895XCC_VF_MSK 0xFFFFFFFF
@@ -44,6 +45,14 @@ static u32 get_misc_bar_id(struct adf_hw_device_data *self)
return ADF_DH895XCC_PMISC_BAR;
}
+static u32 get_ts_clock(struct adf_hw_device_data *self)
+{
+ /*
+ * Timestamp update interval is 16 AE clock ticks for dh895xcc.
+ */
+ return self->clock_frequency / 16;
+}
+
static u32 get_etr_bar_id(struct adf_hw_device_data *self)
{
return ADF_DH895XCC_ETR_BAR;
@@ -237,6 +246,10 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
hw_data->reset_device = adf_reset_sbr;
hw_data->disable_iov = adf_disable_sriov;
hw_data->dev_config = adf_gen2_dev_config;
+ hw_data->clock_frequency = ADF_DH895X_AE_FREQ;
+ hw_data->get_hb_clock = get_ts_clock;
+ hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE;
+ hw_data->check_hb_ctrs = adf_heartbeat_check_ctrs;
adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops);
hw_data->pfvf_ops.enable_vf2pf_interrupts = enable_vf2pf_interrupts;
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h
index 7b674bbe4192..cd3a21985455 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h
@@ -3,6 +3,8 @@
#ifndef ADF_DH895x_HW_DATA_H_
#define ADF_DH895x_HW_DATA_H_
+#include <linux/units.h>
+
/* PCIe configuration space */
#define ADF_DH895XCC_SRAM_BAR 0
#define ADF_DH895XCC_PMISC_BAR 1
@@ -30,6 +32,9 @@
#define ADF_DH895XCC_AE2FUNC_MAP_GRP_A_NUM_REGS 96
#define ADF_DH895XCC_AE2FUNC_MAP_GRP_B_NUM_REGS 12
+/* Clocks frequency */
+#define ADF_DH895X_AE_FREQ (933 * HZ_PER_MHZ)
+
/* FW names */
#define ADF_DH895XCC_FW "qat_895xcc.bin"
#define ADF_DH895XCC_MMP "qat_895xcc_mmp.bin"
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 4f6ca229ee5e..d5a32d71a3e9 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/cpumask.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
diff --git a/drivers/crypto/omap-aes-gcm.c b/drivers/crypto/omap-aes-gcm.c
index 9f937bdc53a7..c498950402e8 100644
--- a/drivers/crypto/omap-aes-gcm.c
+++ b/drivers/crypto/omap-aes-gcm.c
@@ -7,18 +7,21 @@
* Copyright (c) 2016 Texas Instruments Incorporated
*/
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/gcm.h>
+#include <crypto/internal/aead.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/skcipher.h>
#include <linux/errno.h>
-#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/omap-dma.h>
#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/omap-dma.h>
#include <linux/pm_runtime.h>
-#include <crypto/aes.h>
-#include <crypto/gcm.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/skcipher.h>
-#include <crypto/internal/aead.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
#include "omap-crypto.h"
#include "omap-aes.h"
@@ -212,12 +215,10 @@ static int omap_aes_gcm_handle_queue(struct omap_aes_dev *dd,
return 0;
}
-static int omap_aes_gcm_prepare_req(struct crypto_engine *engine, void *areq)
+static int omap_aes_gcm_prepare_req(struct aead_request *req,
+ struct omap_aes_dev *dd)
{
- struct aead_request *req = container_of(areq, struct aead_request,
- base);
struct omap_aes_reqctx *rctx = aead_request_ctx(req);
- struct omap_aes_dev *dd = rctx->dd;
struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
int err;
@@ -356,17 +357,21 @@ int omap_aes_4106gcm_setauthsize(struct crypto_aead *parent,
return crypto_rfc4106_check_authsize(authsize);
}
-static int omap_aes_gcm_crypt_req(struct crypto_engine *engine, void *areq)
+int omap_aes_gcm_crypt_req(struct crypto_engine *engine, void *areq)
{
struct aead_request *req = container_of(areq, struct aead_request,
base);
struct omap_aes_reqctx *rctx = aead_request_ctx(req);
struct omap_aes_dev *dd = rctx->dd;
- int ret = 0;
+ int ret;
if (!dd)
return -ENODEV;
+ ret = omap_aes_gcm_prepare_req(req, dd);
+ if (ret)
+ return ret;
+
if (dd->in_sg_len)
ret = omap_aes_crypt_dma_start(dd);
else
@@ -377,12 +382,6 @@ static int omap_aes_gcm_crypt_req(struct crypto_engine *engine, void *areq)
int omap_aes_gcm_cra_init(struct crypto_aead *tfm)
{
- struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
-
- ctx->enginectx.op.prepare_request = omap_aes_gcm_prepare_req;
- ctx->enginectx.op.unprepare_request = NULL;
- ctx->enginectx.op.do_one_request = omap_aes_gcm_crypt_req;
-
crypto_aead_set_reqsize(tfm, sizeof(struct omap_aes_reqctx));
return 0;
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 67a99c760bc4..ed83023dd77a 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -13,28 +13,26 @@
#define prn(num) pr_debug(#num "=%d\n", num)
#define prx(num) pr_debug(#num "=%x\n", num)
+#include <crypto/aes.h>
+#include <crypto/gcm.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/engine.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/pm_runtime.h>
+#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_address.h>
-#include <linux/io.h>
-#include <linux/crypto.h>
-#include <linux/interrupt.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/aes.h>
-#include <crypto/gcm.h>
-#include <crypto/engine.h>
-#include <crypto/internal/skcipher.h>
-#include <crypto/internal/aead.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
#include "omap-crypto.h"
#include "omap-aes.h"
@@ -426,20 +424,15 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
return 0;
}
-static int omap_aes_prepare_req(struct crypto_engine *engine,
- void *areq)
+static int omap_aes_prepare_req(struct skcipher_request *req,
+ struct omap_aes_dev *dd)
{
- struct skcipher_request *req = container_of(areq, struct skcipher_request, base);
struct omap_aes_ctx *ctx = crypto_skcipher_ctx(
crypto_skcipher_reqtfm(req));
struct omap_aes_reqctx *rctx = skcipher_request_ctx(req);
- struct omap_aes_dev *dd = rctx->dd;
int ret;
u16 flags;
- if (!dd)
- return -ENODEV;
-
/* assign new request to device */
dd->req = req;
dd->total = req->cryptlen;
@@ -491,7 +484,8 @@ static int omap_aes_crypt_req(struct crypto_engine *engine,
if (!dd)
return -ENODEV;
- return omap_aes_crypt_dma_start(dd);
+ return omap_aes_prepare_req(req, dd) ?:
+ omap_aes_crypt_dma_start(dd);
}
static void omap_aes_copy_ivout(struct omap_aes_dev *dd, u8 *ivbuf)
@@ -629,11 +623,6 @@ static int omap_aes_ctr_decrypt(struct skcipher_request *req)
return omap_aes_crypt(req, FLAGS_CTR);
}
-static int omap_aes_prepare_req(struct crypto_engine *engine,
- void *req);
-static int omap_aes_crypt_req(struct crypto_engine *engine,
- void *req);
-
static int omap_aes_init_tfm(struct crypto_skcipher *tfm)
{
const char *name = crypto_tfm_alg_name(&tfm->base);
@@ -649,10 +638,6 @@ static int omap_aes_init_tfm(struct crypto_skcipher *tfm)
crypto_skcipher_set_reqsize(tfm, sizeof(struct omap_aes_reqctx) +
crypto_skcipher_reqsize(blk));
- ctx->enginectx.op.prepare_request = omap_aes_prepare_req;
- ctx->enginectx.op.unprepare_request = NULL;
- ctx->enginectx.op.do_one_request = omap_aes_crypt_req;
-
return 0;
}
@@ -668,68 +653,77 @@ static void omap_aes_exit_tfm(struct crypto_skcipher *tfm)
/* ********************** ALGS ************************************ */
-static struct skcipher_alg algs_ecb_cbc[] = {
+static struct skcipher_engine_alg algs_ecb_cbc[] = {
{
- .base.cra_name = "ecb(aes)",
- .base.cra_driver_name = "ecb-aes-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = omap_aes_setkey,
- .encrypt = omap_aes_ecb_encrypt,
- .decrypt = omap_aes_ecb_decrypt,
- .init = omap_aes_init_tfm,
- .exit = omap_aes_exit_tfm,
+ .base = {
+ .base.cra_name = "ecb(aes)",
+ .base.cra_driver_name = "ecb-aes-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_ecb_encrypt,
+ .decrypt = omap_aes_ecb_decrypt,
+ .init = omap_aes_init_tfm,
+ .exit = omap_aes_exit_tfm,
+ },
+ .op.do_one_request = omap_aes_crypt_req,
},
{
- .base.cra_name = "cbc(aes)",
- .base.cra_driver_name = "cbc-aes-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = omap_aes_setkey,
- .encrypt = omap_aes_cbc_encrypt,
- .decrypt = omap_aes_cbc_decrypt,
- .init = omap_aes_init_tfm,
- .exit = omap_aes_exit_tfm,
+ .base = {
+ .base.cra_name = "cbc(aes)",
+ .base.cra_driver_name = "cbc-aes-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_cbc_encrypt,
+ .decrypt = omap_aes_cbc_decrypt,
+ .init = omap_aes_init_tfm,
+ .exit = omap_aes_exit_tfm,
+ },
+ .op.do_one_request = omap_aes_crypt_req,
}
};
-static struct skcipher_alg algs_ctr[] = {
+static struct skcipher_engine_alg algs_ctr[] = {
{
- .base.cra_name = "ctr(aes)",
- .base.cra_driver_name = "ctr-aes-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .base.cra_blocksize = 1,
- .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = omap_aes_setkey,
- .encrypt = omap_aes_ctr_encrypt,
- .decrypt = omap_aes_ctr_decrypt,
- .init = omap_aes_init_tfm,
- .exit = omap_aes_exit_tfm,
+ .base = {
+ .base.cra_name = "ctr(aes)",
+ .base.cra_driver_name = "ctr-aes-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct omap_aes_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = omap_aes_setkey,
+ .encrypt = omap_aes_ctr_encrypt,
+ .decrypt = omap_aes_ctr_decrypt,
+ .init = omap_aes_init_tfm,
+ .exit = omap_aes_exit_tfm,
+ },
+ .op.do_one_request = omap_aes_crypt_req,
}
};
@@ -740,46 +734,52 @@ static struct omap_aes_algs_info omap_aes_algs_info_ecb_cbc[] = {
},
};
-static struct aead_alg algs_aead_gcm[] = {
+static struct aead_engine_alg algs_aead_gcm[] = {
{
.base = {
- .cra_name = "gcm(aes)",
- .cra_driver_name = "gcm-aes-omap",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct omap_aes_gcm_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-omap",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct omap_aes_gcm_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .init = omap_aes_gcm_cra_init,
+ .ivsize = GCM_AES_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = omap_aes_gcm_setkey,
+ .setauthsize = omap_aes_gcm_setauthsize,
+ .encrypt = omap_aes_gcm_encrypt,
+ .decrypt = omap_aes_gcm_decrypt,
},
- .init = omap_aes_gcm_cra_init,
- .ivsize = GCM_AES_IV_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setkey = omap_aes_gcm_setkey,
- .setauthsize = omap_aes_gcm_setauthsize,
- .encrypt = omap_aes_gcm_encrypt,
- .decrypt = omap_aes_gcm_decrypt,
+ .op.do_one_request = omap_aes_gcm_crypt_req,
},
{
.base = {
- .cra_name = "rfc4106(gcm(aes))",
- .cra_driver_name = "rfc4106-gcm-aes-omap",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct omap_aes_gcm_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-omap",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct omap_aes_gcm_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .init = omap_aes_gcm_cra_init,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .ivsize = GCM_RFC4106_IV_SIZE,
+ .setkey = omap_aes_4106gcm_setkey,
+ .setauthsize = omap_aes_4106gcm_setauthsize,
+ .encrypt = omap_aes_4106gcm_encrypt,
+ .decrypt = omap_aes_4106gcm_decrypt,
},
- .init = omap_aes_gcm_cra_init,
- .maxauthsize = AES_BLOCK_SIZE,
- .ivsize = GCM_RFC4106_IV_SIZE,
- .setkey = omap_aes_4106gcm_setkey,
- .setauthsize = omap_aes_4106gcm_setauthsize,
- .encrypt = omap_aes_4106gcm_encrypt,
- .decrypt = omap_aes_4106gcm_decrypt,
+ .op.do_one_request = omap_aes_gcm_crypt_req,
},
};
@@ -1101,8 +1101,8 @@ static int omap_aes_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct omap_aes_dev *dd;
- struct skcipher_alg *algp;
- struct aead_alg *aalg;
+ struct skcipher_engine_alg *algp;
+ struct aead_engine_alg *aalg;
struct resource res;
int err = -ENOMEM, i, j, irq = -1;
u32 reg;
@@ -1195,9 +1195,9 @@ static int omap_aes_probe(struct platform_device *pdev)
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
algp = &dd->pdata->algs_info[i].algs_list[j];
- pr_debug("reg alg: %s\n", algp->base.cra_name);
+ pr_debug("reg alg: %s\n", algp->base.base.cra_name);
- err = crypto_register_skcipher(algp);
+ err = crypto_engine_register_skcipher(algp);
if (err)
goto err_algs;
@@ -1211,9 +1211,9 @@ static int omap_aes_probe(struct platform_device *pdev)
for (i = 0; i < dd->pdata->aead_algs_info->size; i++) {
aalg = &dd->pdata->aead_algs_info->algs_list[i];
- pr_debug("reg alg: %s\n", aalg->base.cra_name);
+ pr_debug("reg alg: %s\n", aalg->base.base.cra_name);
- err = crypto_register_aead(aalg);
+ err = crypto_engine_register_aead(aalg);
if (err)
goto err_aead_algs;
@@ -1231,12 +1231,12 @@ static int omap_aes_probe(struct platform_device *pdev)
err_aead_algs:
for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) {
aalg = &dd->pdata->aead_algs_info->algs_list[i];
- crypto_unregister_aead(aalg);
+ crypto_engine_unregister_aead(aalg);
}
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
- crypto_unregister_skcipher(
+ crypto_engine_unregister_skcipher(
&dd->pdata->algs_info[i].algs_list[j]);
err_engine:
@@ -1258,7 +1258,7 @@ err_data:
static int omap_aes_remove(struct platform_device *pdev)
{
struct omap_aes_dev *dd = platform_get_drvdata(pdev);
- struct aead_alg *aalg;
+ struct aead_engine_alg *aalg;
int i, j;
spin_lock_bh(&list_lock);
@@ -1267,14 +1267,14 @@ static int omap_aes_remove(struct platform_device *pdev)
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) {
- crypto_unregister_skcipher(
+ crypto_engine_unregister_skcipher(
&dd->pdata->algs_info[i].algs_list[j]);
dd->pdata->algs_info[i].registered--;
}
for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) {
aalg = &dd->pdata->aead_algs_info->algs_list[i];
- crypto_unregister_aead(aalg);
+ crypto_engine_unregister_aead(aalg);
dd->pdata->aead_algs_info->registered--;
}
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index 23d073e87bb8..0f35c9164764 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -10,7 +10,6 @@
#define __OMAP_AES_H__
#include <crypto/aes.h>
-#include <crypto/engine.h>
#define DST_MAXBURST 4
#define DMA_MIN (DST_MAXBURST * sizeof(u32))
@@ -93,7 +92,6 @@ struct omap_aes_gcm_result {
};
struct omap_aes_ctx {
- struct crypto_engine_ctx enginectx;
int keylen;
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
u8 nonce[4];
@@ -117,15 +115,15 @@ struct omap_aes_reqctx {
#define OMAP_AES_CACHE_SIZE 0
struct omap_aes_algs_info {
- struct skcipher_alg *algs_list;
- unsigned int size;
- unsigned int registered;
+ struct skcipher_engine_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
};
struct omap_aes_aead_algs {
- struct aead_alg *algs_list;
- unsigned int size;
- unsigned int registered;
+ struct aead_engine_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
};
struct omap_aes_pdata {
@@ -218,5 +216,6 @@ int omap_aes_crypt_dma_start(struct omap_aes_dev *dd);
int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd);
void omap_aes_gcm_dma_out_callback(void *data);
void omap_aes_clear_copy_flags(struct omap_aes_dev *dd);
+int omap_aes_gcm_crypt_req(struct crypto_engine *engine, void *areq);
#endif
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index f783769ea110..089dd45eaedd 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -16,27 +16,23 @@
#define prx(num) do { } while (0)
#endif
+#include <crypto/engine.h>
+#include <crypto/internal/des.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
-#include <linux/io.h>
-#include <linux/crypto.h>
-#include <linux/interrupt.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/internal/des.h>
-#include <crypto/internal/skcipher.h>
-#include <crypto/algapi.h>
-#include <crypto/engine.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
#include "omap-crypto.h"
@@ -83,7 +79,6 @@
#define FLAGS_OUT_DATA_ST_SHIFT 10
struct omap_des_ctx {
- struct crypto_engine_ctx enginectx;
struct omap_des_dev *dd;
int keylen;
@@ -99,9 +94,9 @@ struct omap_des_reqctx {
#define OMAP_DES_CACHE_SIZE 0
struct omap_des_algs_info {
- struct skcipher_alg *algs_list;
- unsigned int size;
- unsigned int registered;
+ struct skcipher_engine_alg *algs_list;
+ unsigned int size;
+ unsigned int registered;
};
struct omap_des_pdata {
@@ -522,20 +517,15 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
return 0;
}
-static int omap_des_prepare_req(struct crypto_engine *engine,
- void *areq)
+static int omap_des_prepare_req(struct skcipher_request *req,
+ struct omap_des_dev *dd)
{
- struct skcipher_request *req = container_of(areq, struct skcipher_request, base);
struct omap_des_ctx *ctx = crypto_skcipher_ctx(
crypto_skcipher_reqtfm(req));
- struct omap_des_dev *dd = omap_des_find_dev(ctx);
struct omap_des_reqctx *rctx;
int ret;
u16 flags;
- if (!dd)
- return -ENODEV;
-
/* assign new request to device */
dd->req = req;
dd->total = req->cryptlen;
@@ -590,7 +580,8 @@ static int omap_des_crypt_req(struct crypto_engine *engine,
if (!dd)
return -ENODEV;
- return omap_des_crypt_dma_start(dd);
+ return omap_des_prepare_req(req, dd) ?:
+ omap_des_crypt_dma_start(dd);
}
static void omap_des_done_task(unsigned long data)
@@ -709,98 +700,99 @@ static int omap_des_cbc_decrypt(struct skcipher_request *req)
return omap_des_crypt(req, FLAGS_CBC);
}
-static int omap_des_prepare_req(struct crypto_engine *engine,
- void *areq);
-static int omap_des_crypt_req(struct crypto_engine *engine,
- void *areq);
-
static int omap_des_init_tfm(struct crypto_skcipher *tfm)
{
- struct omap_des_ctx *ctx = crypto_skcipher_ctx(tfm);
-
pr_debug("enter\n");
crypto_skcipher_set_reqsize(tfm, sizeof(struct omap_des_reqctx));
- ctx->enginectx.op.prepare_request = omap_des_prepare_req;
- ctx->enginectx.op.unprepare_request = NULL;
- ctx->enginectx.op.do_one_request = omap_des_crypt_req;
-
return 0;
}
/* ********************** ALGS ************************************ */
-static struct skcipher_alg algs_ecb_cbc[] = {
+static struct skcipher_engine_alg algs_ecb_cbc[] = {
{
- .base.cra_name = "ecb(des)",
- .base.cra_driver_name = "ecb-des-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_des_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = DES_KEY_SIZE,
- .max_keysize = DES_KEY_SIZE,
- .setkey = omap_des_setkey,
- .encrypt = omap_des_ecb_encrypt,
- .decrypt = omap_des_ecb_decrypt,
- .init = omap_des_init_tfm,
+ .base = {
+ .base.cra_name = "ecb(des)",
+ .base.cra_driver_name = "ecb-des-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_des_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_ecb_encrypt,
+ .decrypt = omap_des_ecb_decrypt,
+ .init = omap_des_init_tfm,
+ },
+ .op.do_one_request = omap_des_crypt_req,
},
{
- .base.cra_name = "cbc(des)",
- .base.cra_driver_name = "cbc-des-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_des_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = DES_KEY_SIZE,
- .max_keysize = DES_KEY_SIZE,
- .ivsize = DES_BLOCK_SIZE,
- .setkey = omap_des_setkey,
- .encrypt = omap_des_cbc_encrypt,
- .decrypt = omap_des_cbc_decrypt,
- .init = omap_des_init_tfm,
+ .base = {
+ .base.cra_name = "cbc(des)",
+ .base.cra_driver_name = "cbc-des-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_des_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = omap_des_setkey,
+ .encrypt = omap_des_cbc_encrypt,
+ .decrypt = omap_des_cbc_decrypt,
+ .init = omap_des_init_tfm,
+ },
+ .op.do_one_request = omap_des_crypt_req,
},
{
- .base.cra_name = "ecb(des3_ede)",
- .base.cra_driver_name = "ecb-des3-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_des_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .setkey = omap_des3_setkey,
- .encrypt = omap_des_ecb_encrypt,
- .decrypt = omap_des_ecb_decrypt,
- .init = omap_des_init_tfm,
+ .base = {
+ .base.cra_name = "ecb(des3_ede)",
+ .base.cra_driver_name = "ecb-des3-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_des_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = omap_des3_setkey,
+ .encrypt = omap_des_ecb_encrypt,
+ .decrypt = omap_des_ecb_decrypt,
+ .init = omap_des_init_tfm,
+ },
+ .op.do_one_request = omap_des_crypt_req,
},
{
- .base.cra_name = "cbc(des3_ede)",
- .base.cra_driver_name = "cbc-des3-omap",
- .base.cra_priority = 300,
- .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
- CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct omap_des_ctx),
- .base.cra_module = THIS_MODULE,
-
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = omap_des3_setkey,
- .encrypt = omap_des_cbc_encrypt,
- .decrypt = omap_des_cbc_decrypt,
- .init = omap_des_init_tfm,
+ .base = {
+ .base.cra_name = "cbc(des3_ede)",
+ .base.cra_driver_name = "cbc-des3-omap",
+ .base.cra_priority = 300,
+ .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct omap_des_ctx),
+ .base.cra_module = THIS_MODULE,
+
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = omap_des3_setkey,
+ .encrypt = omap_des_cbc_encrypt,
+ .decrypt = omap_des_cbc_decrypt,
+ .init = omap_des_init_tfm,
+ },
+ .op.do_one_request = omap_des_crypt_req,
}
};
@@ -958,7 +950,7 @@ static int omap_des_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct omap_des_dev *dd;
- struct skcipher_alg *algp;
+ struct skcipher_engine_alg *algp;
struct resource *res;
int err = -ENOMEM, i, j, irq = -1;
u32 reg;
@@ -971,18 +963,12 @@ static int omap_des_probe(struct platform_device *pdev)
dd->dev = dev;
platform_set_drvdata(pdev, dd);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no MEM resource info\n");
- goto err_res;
- }
-
err = (dev->of_node) ? omap_des_get_of(dd, pdev) :
omap_des_get_pdev(dd, pdev);
if (err)
goto err_res;
- dd->io_base = devm_ioremap_resource(dev, res);
+ dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(dd->io_base)) {
err = PTR_ERR(dd->io_base);
goto err_res;
@@ -1052,9 +1038,9 @@ static int omap_des_probe(struct platform_device *pdev)
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
algp = &dd->pdata->algs_info[i].algs_list[j];
- pr_debug("reg alg: %s\n", algp->base.cra_name);
+ pr_debug("reg alg: %s\n", algp->base.base.cra_name);
- err = crypto_register_skcipher(algp);
+ err = crypto_engine_register_skcipher(algp);
if (err)
goto err_algs;
@@ -1067,7 +1053,7 @@ static int omap_des_probe(struct platform_device *pdev)
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
- crypto_unregister_skcipher(
+ crypto_engine_unregister_skcipher(
&dd->pdata->algs_info[i].algs_list[j]);
err_engine:
@@ -1097,7 +1083,7 @@ static int omap_des_remove(struct platform_device *pdev)
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
- crypto_unregister_skcipher(
+ crypto_engine_unregister_skcipher(
&dd->pdata->algs_info[i].algs_list[j]);
tasklet_kill(&dd->done_task);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index cbeda59c6b19..a6b4a0b3ace3 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -13,34 +13,30 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <crypto/engine.h>
+#include <crypto/hmac.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
#include <linux/err.h>
#include <linux/device.h>
-#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/init.h>
-#include <linux/errno.h>
#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/pm_runtime.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/delay.h>
-#include <linux/crypto.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/algapi.h>
-#include <crypto/sha1.h>
-#include <crypto/sha2.h>
-#include <crypto/hash.h>
-#include <crypto/hmac.h>
-#include <crypto/internal/hash.h>
-#include <crypto/engine.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#define MD5_DIGEST_SIZE 16
@@ -168,7 +164,6 @@ struct omap_sham_hmac_ctx {
};
struct omap_sham_ctx {
- struct crypto_engine_ctx enginectx;
unsigned long flags;
/* fallback stuff */
@@ -180,7 +175,7 @@ struct omap_sham_ctx {
#define OMAP_SHAM_QUEUE_LENGTH 10
struct omap_sham_algs_info {
- struct ahash_alg *algs_list;
+ struct ahash_engine_alg *algs_list;
unsigned int size;
unsigned int registered;
};
@@ -1074,6 +1069,10 @@ static int omap_sham_hash_one_req(struct crypto_engine *engine, void *areq)
dev_dbg(dd->dev, "hash-one: op: %u, total: %u, digcnt: %zd, final: %d",
ctx->op, ctx->total, ctx->digcnt, final);
+ err = omap_sham_prepare_request(engine, areq);
+ if (err)
+ return err;
+
err = pm_runtime_resume_and_get(dd->dev);
if (err < 0) {
dev_err(dd->dev, "failed to get sync: %d\n", err);
@@ -1349,10 +1348,6 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
}
- tctx->enginectx.op.do_one_request = omap_sham_hash_one_req;
- tctx->enginectx.op.prepare_request = omap_sham_prepare_request;
- tctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -1423,15 +1418,15 @@ static int omap_sham_import(struct ahash_request *req, const void *in)
return 0;
}
-static struct ahash_alg algs_sha1_md5[] = {
+static struct ahash_engine_alg algs_sha1_md5[] = {
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = SHA1_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = SHA1_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "sha1",
.cra_driver_name = "omap-sha1",
.cra_priority = 400,
@@ -1444,16 +1439,17 @@ static struct ahash_alg algs_sha1_md5[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = MD5_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = MD5_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "md5",
.cra_driver_name = "omap-md5",
.cra_priority = 400,
@@ -1466,17 +1462,18 @@ static struct ahash_alg algs_sha1_md5[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = SHA1_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = SHA1_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(sha1)",
.cra_driver_name = "omap-hmac-sha1",
.cra_priority = 400,
@@ -1490,17 +1487,18 @@ static struct ahash_alg algs_sha1_md5[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha1_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = MD5_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = MD5_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(md5)",
.cra_driver_name = "omap-hmac-md5",
.cra_priority = 400,
@@ -1514,20 +1512,21 @@ static struct ahash_alg algs_sha1_md5[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_md5_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
}
};
/* OMAP4 has some algs in addition to what OMAP2 has */
-static struct ahash_alg algs_sha224_sha256[] = {
-{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = SHA224_DIGEST_SIZE,
- .halg.base = {
+static struct ahash_engine_alg algs_sha224_sha256[] = {
+{
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = SHA224_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "sha224",
.cra_driver_name = "omap-sha224",
.cra_priority = 400,
@@ -1540,16 +1539,17 @@ static struct ahash_alg algs_sha224_sha256[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = SHA256_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = SHA256_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "sha256",
.cra_driver_name = "omap-sha256",
.cra_priority = 400,
@@ -1562,17 +1562,18 @@ static struct ahash_alg algs_sha224_sha256[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = SHA224_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = SHA224_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(sha224)",
.cra_driver_name = "omap-hmac-sha224",
.cra_priority = 400,
@@ -1586,17 +1587,18 @@ static struct ahash_alg algs_sha224_sha256[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha224_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = SHA256_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = SHA256_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(sha256)",
.cra_driver_name = "omap-hmac-sha256",
.cra_priority = 400,
@@ -1610,19 +1612,20 @@ static struct ahash_alg algs_sha224_sha256[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha256_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
};
-static struct ahash_alg algs_sha384_sha512[] = {
+static struct ahash_engine_alg algs_sha384_sha512[] = {
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = SHA384_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = SHA384_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "sha384",
.cra_driver_name = "omap-sha384",
.cra_priority = 400,
@@ -1635,16 +1638,17 @@ static struct ahash_alg algs_sha384_sha512[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .halg.digestsize = SHA512_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.halg.digestsize = SHA512_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "sha512",
.cra_driver_name = "omap-sha512",
.cra_priority = 400,
@@ -1657,17 +1661,18 @@ static struct ahash_alg algs_sha384_sha512[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = SHA384_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = SHA384_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(sha384)",
.cra_driver_name = "omap-hmac-sha384",
.cra_priority = 400,
@@ -1681,17 +1686,18 @@ static struct ahash_alg algs_sha384_sha512[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha384_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
{
- .init = omap_sham_init,
- .update = omap_sham_update,
- .final = omap_sham_final,
- .finup = omap_sham_finup,
- .digest = omap_sham_digest,
- .setkey = omap_sham_setkey,
- .halg.digestsize = SHA512_DIGEST_SIZE,
- .halg.base = {
+ .base.init = omap_sham_init,
+ .base.update = omap_sham_update,
+ .base.final = omap_sham_final,
+ .base.finup = omap_sham_finup,
+ .base.digest = omap_sham_digest,
+ .base.setkey = omap_sham_setkey,
+ .base.halg.digestsize = SHA512_DIGEST_SIZE,
+ .base.halg.base = {
.cra_name = "hmac(sha512)",
.cra_driver_name = "omap-hmac-sha512",
.cra_priority = 400,
@@ -1705,7 +1711,8 @@ static struct ahash_alg algs_sha384_sha512[] = {
.cra_module = THIS_MODULE,
.cra_init = omap_sham_cra_sha512_init,
.cra_exit = omap_sham_cra_exit,
- }
+ },
+ .op.do_one_request = omap_sham_hash_one_req,
},
};
@@ -2146,14 +2153,16 @@ static int omap_sham_probe(struct platform_device *pdev)
break;
for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
+ struct ahash_engine_alg *ealg;
struct ahash_alg *alg;
- alg = &dd->pdata->algs_info[i].algs_list[j];
+ ealg = &dd->pdata->algs_info[i].algs_list[j];
+ alg = &ealg->base;
alg->export = omap_sham_export;
alg->import = omap_sham_import;
alg->halg.statesize = sizeof(struct omap_sham_reqctx) +
BUFLEN;
- err = crypto_register_ahash(alg);
+ err = crypto_engine_register_ahash(ealg);
if (err)
goto err_algs;
@@ -2172,7 +2181,7 @@ static int omap_sham_probe(struct platform_device *pdev)
err_algs:
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
- crypto_unregister_ahash(
+ crypto_engine_unregister_ahash(
&dd->pdata->algs_info[i].algs_list[j]);
err_engine_start:
crypto_engine_exit(dd->engine);
@@ -2203,7 +2212,7 @@ static int omap_sham_remove(struct platform_device *pdev)
spin_unlock_bh(&sham.lock);
for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) {
- crypto_unregister_ahash(
+ crypto_engine_unregister_ahash(
&dd->pdata->algs_info[i].algs_list[j]);
dd->pdata->algs_info[i].registered--;
}
diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c
index 72dd1a4ebac4..825a729f205e 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -173,13 +173,9 @@ static int qcom_rng_probe(struct platform_device *pdev)
if (IS_ERR(rng->base))
return PTR_ERR(rng->base);
- /* ACPI systems have clk already on, so skip clk_get */
- if (!has_acpi_companion(&pdev->dev)) {
- rng->clk = devm_clk_get(&pdev->dev, "core");
- if (IS_ERR(rng->clk))
- return PTR_ERR(rng->clk);
- }
-
+ rng->clk = devm_clk_get_optional(&pdev->dev, "core");
+ if (IS_ERR(rng->clk))
+ return PTR_ERR(rng->clk);
rng->skip_init = (unsigned long)device_get_match_data(&pdev->dev);
diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
index 9f6ba770a90a..77d5705a5d96 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.c
+++ b/drivers/crypto/rockchip/rk3288_crypto.c
@@ -10,14 +10,21 @@
*/
#include "rk3288_crypto.h"
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/reset.h>
+#include <linux/spinlock.h>
static struct rockchip_ip rocklist = {
.dev_list = LIST_HEAD_INIT(rocklist.dev_list),
@@ -184,7 +191,6 @@ static struct rk_crypto_tmp *rk_cipher_algs[] = {
&rk_ahash_md5,
};
-#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
{
struct rk_crypto_info *dd;
@@ -204,8 +210,8 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
switch (rk_cipher_algs[i]->type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name,
- rk_cipher_algs[i]->alg.skcipher.base.cra_name,
+ rk_cipher_algs[i]->alg.skcipher.base.base.cra_driver_name,
+ rk_cipher_algs[i]->alg.skcipher.base.base.cra_name,
rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb);
seq_printf(seq, "\tfallback due to length: %lu\n",
rk_cipher_algs[i]->stat_fb_len);
@@ -216,8 +222,8 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
break;
case CRYPTO_ALG_TYPE_AHASH:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
- rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name,
- rk_cipher_algs[i]->alg.hash.halg.base.cra_name,
+ rk_cipher_algs[i]->alg.hash.base.halg.base.cra_driver_name,
+ rk_cipher_algs[i]->alg.hash.base.halg.base.cra_name,
rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb);
break;
}
@@ -226,17 +232,20 @@ static int rk_crypto_debugfs_show(struct seq_file *seq, void *v)
}
DEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs);
-#endif
static void register_debugfs(struct rk_crypto_info *crypto_info)
{
-#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
+ struct dentry *dbgfs_dir __maybe_unused;
+ struct dentry *dbgfs_stats __maybe_unused;
+
/* Ignore error of debugfs */
- rocklist.dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL);
- rocklist.dbgfs_stats = debugfs_create_file("stats", 0444,
- rocklist.dbgfs_dir,
- &rocklist,
- &rk_crypto_debugfs_fops);
+ dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL);
+ dbgfs_stats = debugfs_create_file("stats", 0444, dbgfs_dir, &rocklist,
+ &rk_crypto_debugfs_fops);
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG
+ rocklist.dbgfs_dir = dbgfs_dir;
+ rocklist.dbgfs_stats = dbgfs_stats;
#endif
}
@@ -250,15 +259,15 @@ static int rk_crypto_register(struct rk_crypto_info *crypto_info)
switch (rk_cipher_algs[i]->type) {
case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(crypto_info->dev, "Register %s as %s\n",
- rk_cipher_algs[i]->alg.skcipher.base.cra_name,
- rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name);
- err = crypto_register_skcipher(&rk_cipher_algs[i]->alg.skcipher);
+ rk_cipher_algs[i]->alg.skcipher.base.base.cra_name,
+ rk_cipher_algs[i]->alg.skcipher.base.base.cra_driver_name);
+ err = crypto_engine_register_skcipher(&rk_cipher_algs[i]->alg.skcipher);
break;
case CRYPTO_ALG_TYPE_AHASH:
dev_info(crypto_info->dev, "Register %s as %s\n",
- rk_cipher_algs[i]->alg.hash.halg.base.cra_name,
- rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name);
- err = crypto_register_ahash(&rk_cipher_algs[i]->alg.hash);
+ rk_cipher_algs[i]->alg.hash.base.halg.base.cra_name,
+ rk_cipher_algs[i]->alg.hash.base.halg.base.cra_driver_name);
+ err = crypto_engine_register_ahash(&rk_cipher_algs[i]->alg.hash);
break;
default:
dev_err(crypto_info->dev, "unknown algorithm\n");
@@ -271,9 +280,9 @@ static int rk_crypto_register(struct rk_crypto_info *crypto_info)
err_cipher_algs:
for (k = 0; k < i; k++) {
if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER)
- crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
+ crypto_engine_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
else
- crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
+ crypto_engine_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
}
return err;
}
@@ -284,9 +293,9 @@ static void rk_crypto_unregister(void)
for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER)
- crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
+ crypto_engine_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
else
- crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
+ crypto_engine_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
}
}
diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
index b2695258cade..3aa03cbfb6be 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.h
+++ b/drivers/crypto/rockchip/rk3288_crypto.h
@@ -3,21 +3,18 @@
#define __RK3288_CRYPTO_H__
#include <crypto/aes.h>
-#include <crypto/internal/des.h>
-#include <crypto/algapi.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/pm_runtime.h>
-#include <linux/scatterlist.h>
#include <crypto/engine.h>
+#include <crypto/internal/des.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
-
#include <crypto/md5.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
#define _SBF(v, f) ((v) << (f))
@@ -231,7 +228,6 @@ struct rk_crypto_info {
/* the private variable of hash */
struct rk_ahash_ctx {
- struct crypto_engine_ctx enginectx;
/* for fallback */
struct crypto_ahash *fallback_tfm;
};
@@ -246,7 +242,6 @@ struct rk_ahash_rctx {
/* the private variable of cipher */
struct rk_cipher_ctx {
- struct crypto_engine_ctx enginectx;
unsigned int keylen;
u8 key[AES_MAX_KEY_SIZE];
u8 iv[AES_BLOCK_SIZE];
@@ -264,8 +259,8 @@ struct rk_crypto_tmp {
u32 type;
struct rk_crypto_info *dev;
union {
- struct skcipher_alg skcipher;
- struct ahash_alg hash;
+ struct skcipher_engine_alg skcipher;
+ struct ahash_engine_alg hash;
} alg;
unsigned long stat_req;
unsigned long stat_fb;
diff --git a/drivers/crypto/rockchip/rk3288_crypto_ahash.c b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
index a78ff3dcd0b1..8c143180645e 100644
--- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c
+++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c
@@ -8,9 +8,15 @@
*
* Some ideas are from marvell/cesa.c and s5p-sss.c driver.
*/
-#include <linux/device.h>
+
#include <asm/unaligned.h>
+#include <crypto/internal/hash.h>
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
#include "rk3288_crypto.h"
/*
@@ -40,8 +46,8 @@ static int rk_ahash_digest_fb(struct ahash_request *areq)
struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct rk_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);
algt->stat_fb++;
@@ -240,14 +246,13 @@ static int rk_hash_prepare(struct crypto_engine *engine, void *breq)
return 0;
}
-static int rk_hash_unprepare(struct crypto_engine *engine, void *breq)
+static void rk_hash_unprepare(struct crypto_engine *engine, void *breq)
{
struct ahash_request *areq = container_of(breq, struct ahash_request, base);
struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);
struct rk_crypto_info *rkc = rctx->dev;
dma_unmap_sg(rkc->dev, areq->src, rctx->nrsg, DMA_TO_DEVICE);
- return 0;
}
static int rk_hash_run(struct crypto_engine *engine, void *breq)
@@ -255,11 +260,11 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
struct ahash_request *areq = container_of(breq, struct ahash_request, base);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct rk_ahash_rctx *rctx = ahash_request_ctx(areq);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);
struct scatterlist *sg = areq->src;
struct rk_crypto_info *rkc = rctx->dev;
- int err = 0;
+ int err;
int i;
u32 v;
@@ -267,6 +272,10 @@ static int rk_hash_run(struct crypto_engine *engine, void *breq)
if (err)
return err;
+ err = rk_hash_prepare(engine, breq);
+ if (err)
+ goto theend;
+
rctx->mode = 0;
algt->stat_req++;
@@ -327,15 +336,17 @@ theend:
crypto_finalize_hash_request(engine, breq, err);
local_bh_enable();
+ rk_hash_unprepare(engine, breq);
+
return 0;
}
-static int rk_cra_hash_init(struct crypto_tfm *tfm)
+static int rk_hash_init_tfm(struct crypto_ahash *tfm)
{
- struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm);
- const char *alg_name = crypto_tfm_alg_name(tfm);
- struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash);
+ struct rk_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
+ const char *alg_name = crypto_ahash_alg_name(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash.base);
/* for fallback */
tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0,
@@ -345,27 +356,23 @@ static int rk_cra_hash_init(struct crypto_tfm *tfm)
return PTR_ERR(tctx->fallback_tfm);
}
- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ crypto_ahash_set_reqsize(tfm,
sizeof(struct rk_ahash_rctx) +
crypto_ahash_reqsize(tctx->fallback_tfm));
- tctx->enginectx.op.do_one_request = rk_hash_run;
- tctx->enginectx.op.prepare_request = rk_hash_prepare;
- tctx->enginectx.op.unprepare_request = rk_hash_unprepare;
-
return 0;
}
-static void rk_cra_hash_exit(struct crypto_tfm *tfm)
+static void rk_hash_exit_tfm(struct crypto_ahash *tfm)
{
- struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm);
+ struct rk_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
crypto_free_ahash(tctx->fallback_tfm);
}
struct rk_crypto_tmp rk_ahash_sha1 = {
.type = CRYPTO_ALG_TYPE_AHASH,
- .alg.hash = {
+ .alg.hash.base = {
.init = rk_ahash_init,
.update = rk_ahash_update,
.final = rk_ahash_final,
@@ -373,6 +380,8 @@ struct rk_crypto_tmp rk_ahash_sha1 = {
.export = rk_ahash_export,
.import = rk_ahash_import,
.digest = rk_ahash_digest,
+ .init_tfm = rk_hash_init_tfm,
+ .exit_tfm = rk_hash_exit_tfm,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.statesize = sizeof(struct sha1_state),
@@ -385,17 +394,18 @@ struct rk_crypto_tmp rk_ahash_sha1 = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct rk_ahash_ctx),
.cra_alignmask = 3,
- .cra_init = rk_cra_hash_init,
- .cra_exit = rk_cra_hash_exit,
.cra_module = THIS_MODULE,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk_hash_run,
+ },
};
struct rk_crypto_tmp rk_ahash_sha256 = {
.type = CRYPTO_ALG_TYPE_AHASH,
- .alg.hash = {
+ .alg.hash.base = {
.init = rk_ahash_init,
.update = rk_ahash_update,
.final = rk_ahash_final,
@@ -403,6 +413,8 @@ struct rk_crypto_tmp rk_ahash_sha256 = {
.export = rk_ahash_export,
.import = rk_ahash_import,
.digest = rk_ahash_digest,
+ .init_tfm = rk_hash_init_tfm,
+ .exit_tfm = rk_hash_exit_tfm,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
@@ -415,17 +427,18 @@ struct rk_crypto_tmp rk_ahash_sha256 = {
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct rk_ahash_ctx),
.cra_alignmask = 3,
- .cra_init = rk_cra_hash_init,
- .cra_exit = rk_cra_hash_exit,
.cra_module = THIS_MODULE,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk_hash_run,
+ },
};
struct rk_crypto_tmp rk_ahash_md5 = {
.type = CRYPTO_ALG_TYPE_AHASH,
- .alg.hash = {
+ .alg.hash.base = {
.init = rk_ahash_init,
.update = rk_ahash_update,
.final = rk_ahash_final,
@@ -433,6 +446,8 @@ struct rk_crypto_tmp rk_ahash_md5 = {
.export = rk_ahash_export,
.import = rk_ahash_import,
.digest = rk_ahash_digest,
+ .init_tfm = rk_hash_init_tfm,
+ .exit_tfm = rk_hash_exit_tfm,
.halg = {
.digestsize = MD5_DIGEST_SIZE,
.statesize = sizeof(struct md5_state),
@@ -445,10 +460,11 @@ struct rk_crypto_tmp rk_ahash_md5 = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct rk_ahash_ctx),
.cra_alignmask = 3,
- .cra_init = rk_cra_hash_init,
- .cra_exit = rk_cra_hash_exit,
.cra_module = THIS_MODULE,
}
}
- }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk_hash_run,
+ },
};
diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
index 59069457582b..da95747d973f 100644
--- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
+++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c
@@ -8,8 +8,14 @@
*
* Some ideas are from marvell-cesa.c and s5p-sss.c driver.
*/
-#include <linux/device.h>
+
+#include <crypto/engine.h>
+#include <crypto/internal/skcipher.h>
#include <crypto/scatterwalk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
#include "rk3288_crypto.h"
#define RK_CRYPTO_DEC BIT(0)
@@ -18,7 +24,7 @@ static int rk_cipher_need_fallback(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher.base);
struct scatterlist *sgs, *sgd;
unsigned int stodo, dtodo, len;
unsigned int bs = crypto_skcipher_blocksize(tfm);
@@ -65,7 +71,7 @@ static int rk_cipher_fallback(struct skcipher_request *areq)
struct rk_cipher_ctx *op = crypto_skcipher_ctx(tfm);
struct rk_cipher_rctx *rctx = skcipher_request_ctx(areq);
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher.base);
int err;
algt->stat_fb++;
@@ -305,7 +311,7 @@ static int rk_cipher_run(struct crypto_engine *engine, void *async_req)
unsigned int len = areq->cryptlen;
unsigned int todo;
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher.base);
struct rk_crypto_info *rkc = rctx->dev;
err = pm_runtime_resume_and_get(rkc->dev);
@@ -430,7 +436,7 @@ static int rk_cipher_tfm_init(struct crypto_skcipher *tfm)
struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
const char *name = crypto_tfm_alg_name(&tfm->base);
struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
- struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher);
+ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher.base);
ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->fallback_tfm)) {
@@ -442,8 +448,6 @@ static int rk_cipher_tfm_init(struct crypto_skcipher *tfm)
tfm->reqsize = sizeof(struct rk_cipher_rctx) +
crypto_skcipher_reqsize(ctx->fallback_tfm);
- ctx->enginectx.op.do_one_request = rk_cipher_run;
-
return 0;
}
@@ -457,7 +461,7 @@ static void rk_cipher_tfm_exit(struct crypto_skcipher *tfm)
struct rk_crypto_tmp rk_ecb_aes_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "ecb(aes)",
.base.cra_driver_name = "ecb-aes-rk",
.base.cra_priority = 300,
@@ -474,12 +478,15 @@ struct rk_crypto_tmp rk_ecb_aes_alg = {
.setkey = rk_aes_setkey,
.encrypt = rk_aes_ecb_encrypt,
.decrypt = rk_aes_ecb_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
struct rk_crypto_tmp rk_cbc_aes_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "cbc(aes)",
.base.cra_driver_name = "cbc-aes-rk",
.base.cra_priority = 300,
@@ -497,12 +504,15 @@ struct rk_crypto_tmp rk_cbc_aes_alg = {
.setkey = rk_aes_setkey,
.encrypt = rk_aes_cbc_encrypt,
.decrypt = rk_aes_cbc_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
struct rk_crypto_tmp rk_ecb_des_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "ecb(des)",
.base.cra_driver_name = "ecb-des-rk",
.base.cra_priority = 300,
@@ -519,12 +529,15 @@ struct rk_crypto_tmp rk_ecb_des_alg = {
.setkey = rk_des_setkey,
.encrypt = rk_des_ecb_encrypt,
.decrypt = rk_des_ecb_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
struct rk_crypto_tmp rk_cbc_des_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "cbc(des)",
.base.cra_driver_name = "cbc-des-rk",
.base.cra_priority = 300,
@@ -542,12 +555,15 @@ struct rk_crypto_tmp rk_cbc_des_alg = {
.setkey = rk_des_setkey,
.encrypt = rk_des_cbc_encrypt,
.decrypt = rk_des_cbc_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
struct rk_crypto_tmp rk_ecb_des3_ede_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "ecb(des3_ede)",
.base.cra_driver_name = "ecb-des3-ede-rk",
.base.cra_priority = 300,
@@ -564,12 +580,15 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg = {
.setkey = rk_tdes_setkey,
.encrypt = rk_des3_ede_ecb_encrypt,
.decrypt = rk_des3_ede_ecb_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
struct rk_crypto_tmp rk_cbc_des3_ede_alg = {
.type = CRYPTO_ALG_TYPE_SKCIPHER,
- .alg.skcipher = {
+ .alg.skcipher.base = {
.base.cra_name = "cbc(des3_ede)",
.base.cra_driver_name = "cbc-des3-ede-rk",
.base.cra_priority = 300,
@@ -587,5 +606,8 @@ struct rk_crypto_tmp rk_cbc_des3_ede_alg = {
.setkey = rk_tdes_setkey,
.encrypt = rk_des3_ede_cbc_encrypt,
.decrypt = rk_des3_ede_cbc_decrypt,
- }
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk_cipher_run,
+ },
};
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index 1c4d5fb05d69..fe8cf9ba8005 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c
index df5f9d675c57..6238d34f8db2 100644
--- a/drivers/crypto/sa2ul.c
+++ b/drivers/crypto/sa2ul.c
@@ -15,7 +15,8 @@
#include <linux/dmapool.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 4c799df3e883..62d93526920f 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -27,7 +27,6 @@
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/crypto/starfive/Kconfig b/drivers/crypto/starfive/Kconfig
index df745fcb09df..2cb192502c1b 100644
--- a/drivers/crypto/starfive/Kconfig
+++ b/drivers/crypto/starfive/Kconfig
@@ -12,6 +12,8 @@ config CRYPTO_DEV_JH7110
select CRYPTO_SHA512
select CRYPTO_SM3_GENERIC
select CRYPTO_RSA
+ select CRYPTO_AES
+ select CRYPTO_CCM
help
Support for StarFive JH7110 crypto hardware acceleration engine.
This module provides acceleration for public key algo,
diff --git a/drivers/crypto/starfive/Makefile b/drivers/crypto/starfive/Makefile
index 98b01d2f1ccf..8c137afe58ad 100644
--- a/drivers/crypto/starfive/Makefile
+++ b/drivers/crypto/starfive/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_JH7110) += jh7110-crypto.o
-jh7110-crypto-objs := jh7110-cryp.o jh7110-hash.o jh7110-rsa.o
+jh7110-crypto-objs := jh7110-cryp.o jh7110-hash.o jh7110-rsa.o jh7110-aes.o
diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c
new file mode 100644
index 000000000000..9378e6682f0e
--- /dev/null
+++ b/drivers/crypto/starfive/jh7110-aes.c
@@ -0,0 +1,1024 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive AES acceleration driver
+ *
+ * Copyright (c) 2022 StarFive Technology
+ */
+
+#include <crypto/engine.h>
+#include <crypto/gcm.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include "jh7110-cryp.h"
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define STARFIVE_AES_REGS_OFFSET 0x100
+#define STARFIVE_AES_AESDIO0R (STARFIVE_AES_REGS_OFFSET + 0x0)
+#define STARFIVE_AES_KEY0 (STARFIVE_AES_REGS_OFFSET + 0x4)
+#define STARFIVE_AES_KEY1 (STARFIVE_AES_REGS_OFFSET + 0x8)
+#define STARFIVE_AES_KEY2 (STARFIVE_AES_REGS_OFFSET + 0xC)
+#define STARFIVE_AES_KEY3 (STARFIVE_AES_REGS_OFFSET + 0x10)
+#define STARFIVE_AES_KEY4 (STARFIVE_AES_REGS_OFFSET + 0x14)
+#define STARFIVE_AES_KEY5 (STARFIVE_AES_REGS_OFFSET + 0x18)
+#define STARFIVE_AES_KEY6 (STARFIVE_AES_REGS_OFFSET + 0x1C)
+#define STARFIVE_AES_KEY7 (STARFIVE_AES_REGS_OFFSET + 0x20)
+#define STARFIVE_AES_CSR (STARFIVE_AES_REGS_OFFSET + 0x24)
+#define STARFIVE_AES_IV0 (STARFIVE_AES_REGS_OFFSET + 0x28)
+#define STARFIVE_AES_IV1 (STARFIVE_AES_REGS_OFFSET + 0x2C)
+#define STARFIVE_AES_IV2 (STARFIVE_AES_REGS_OFFSET + 0x30)
+#define STARFIVE_AES_IV3 (STARFIVE_AES_REGS_OFFSET + 0x34)
+#define STARFIVE_AES_NONCE0 (STARFIVE_AES_REGS_OFFSET + 0x3C)
+#define STARFIVE_AES_NONCE1 (STARFIVE_AES_REGS_OFFSET + 0x40)
+#define STARFIVE_AES_NONCE2 (STARFIVE_AES_REGS_OFFSET + 0x44)
+#define STARFIVE_AES_NONCE3 (STARFIVE_AES_REGS_OFFSET + 0x48)
+#define STARFIVE_AES_ALEN0 (STARFIVE_AES_REGS_OFFSET + 0x4C)
+#define STARFIVE_AES_ALEN1 (STARFIVE_AES_REGS_OFFSET + 0x50)
+#define STARFIVE_AES_MLEN0 (STARFIVE_AES_REGS_OFFSET + 0x54)
+#define STARFIVE_AES_MLEN1 (STARFIVE_AES_REGS_OFFSET + 0x58)
+#define STARFIVE_AES_IVLEN (STARFIVE_AES_REGS_OFFSET + 0x5C)
+
+#define FLG_MODE_MASK GENMASK(2, 0)
+#define FLG_ENCRYPT BIT(4)
+
+/* Misc */
+#define CCM_B0_ADATA 0x40
+#define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32))
+
+static inline int starfive_aes_wait_busy(struct starfive_cryp_dev *cryp)
+{
+ u32 status;
+
+ return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
+ !(status & STARFIVE_AES_BUSY), 10, 100000);
+}
+
+static inline int starfive_aes_wait_keydone(struct starfive_cryp_dev *cryp)
+{
+ u32 status;
+
+ return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
+ (status & STARFIVE_AES_KEY_DONE), 10, 100000);
+}
+
+static inline int starfive_aes_wait_gcmdone(struct starfive_cryp_dev *cryp)
+{
+ u32 status;
+
+ return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
+ (status & STARFIVE_AES_GCM_DONE), 10, 100000);
+}
+
+static inline int is_gcm(struct starfive_cryp_dev *cryp)
+{
+ return (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_GCM;
+}
+
+static inline int is_encrypt(struct starfive_cryp_dev *cryp)
+{
+ return cryp->flags & FLG_ENCRYPT;
+}
+
+static void starfive_aes_aead_hw_start(struct starfive_cryp_ctx *ctx, u32 hw_mode)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ unsigned int value;
+
+ switch (hw_mode) {
+ case STARFIVE_AES_MODE_GCM:
+ value = readl(ctx->cryp->base + STARFIVE_AES_CSR);
+ value |= STARFIVE_AES_GCM_START;
+ writel(value, cryp->base + STARFIVE_AES_CSR);
+ starfive_aes_wait_gcmdone(cryp);
+ break;
+ case STARFIVE_AES_MODE_CCM:
+ value = readl(ctx->cryp->base + STARFIVE_AES_CSR);
+ value |= STARFIVE_AES_CCM_START;
+ writel(value, cryp->base + STARFIVE_AES_CSR);
+ break;
+ }
+}
+
+static inline void starfive_aes_set_ivlen(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ if (is_gcm(cryp))
+ writel(GCM_AES_IV_SIZE, cryp->base + STARFIVE_AES_IVLEN);
+ else
+ writel(AES_BLOCK_SIZE, cryp->base + STARFIVE_AES_IVLEN);
+}
+
+static inline void starfive_aes_set_alen(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ writel(upper_32_bits(cryp->assoclen), cryp->base + STARFIVE_AES_ALEN0);
+ writel(lower_32_bits(cryp->assoclen), cryp->base + STARFIVE_AES_ALEN1);
+}
+
+static inline void starfive_aes_set_mlen(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ writel(upper_32_bits(cryp->total_in), cryp->base + STARFIVE_AES_MLEN0);
+ writel(lower_32_bits(cryp->total_in), cryp->base + STARFIVE_AES_MLEN1);
+}
+
+static inline int starfive_aes_ccm_check_iv(const u8 *iv)
+{
+ /* 2 <= L <= 8, so 1 <= L' <= 7. */
+ if (iv[0] < 1 || iv[0] > 7)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int starfive_aes_write_iv(struct starfive_cryp_ctx *ctx, u32 *iv)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ writel(iv[0], cryp->base + STARFIVE_AES_IV0);
+ writel(iv[1], cryp->base + STARFIVE_AES_IV1);
+ writel(iv[2], cryp->base + STARFIVE_AES_IV2);
+
+ if (is_gcm(cryp)) {
+ if (starfive_aes_wait_gcmdone(cryp))
+ return -ETIMEDOUT;
+
+ return 0;
+ }
+
+ writel(iv[3], cryp->base + STARFIVE_AES_IV3);
+
+ return 0;
+}
+
+static inline void starfive_aes_get_iv(struct starfive_cryp_dev *cryp, u32 *iv)
+{
+ iv[0] = readl(cryp->base + STARFIVE_AES_IV0);
+ iv[1] = readl(cryp->base + STARFIVE_AES_IV1);
+ iv[2] = readl(cryp->base + STARFIVE_AES_IV2);
+ iv[3] = readl(cryp->base + STARFIVE_AES_IV3);
+}
+
+static inline void starfive_aes_write_nonce(struct starfive_cryp_ctx *ctx, u32 *nonce)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ writel(nonce[0], cryp->base + STARFIVE_AES_NONCE0);
+ writel(nonce[1], cryp->base + STARFIVE_AES_NONCE1);
+ writel(nonce[2], cryp->base + STARFIVE_AES_NONCE2);
+ writel(nonce[3], cryp->base + STARFIVE_AES_NONCE3);
+}
+
+static int starfive_aes_write_key(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ u32 *key = (u32 *)ctx->key;
+
+ if (ctx->keylen >= AES_KEYSIZE_128) {
+ writel(key[0], cryp->base + STARFIVE_AES_KEY0);
+ writel(key[1], cryp->base + STARFIVE_AES_KEY1);
+ writel(key[2], cryp->base + STARFIVE_AES_KEY2);
+ writel(key[3], cryp->base + STARFIVE_AES_KEY3);
+ }
+
+ if (ctx->keylen >= AES_KEYSIZE_192) {
+ writel(key[4], cryp->base + STARFIVE_AES_KEY4);
+ writel(key[5], cryp->base + STARFIVE_AES_KEY5);
+ }
+
+ if (ctx->keylen >= AES_KEYSIZE_256) {
+ writel(key[6], cryp->base + STARFIVE_AES_KEY6);
+ writel(key[7], cryp->base + STARFIVE_AES_KEY7);
+ }
+
+ if (starfive_aes_wait_keydone(cryp))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int starfive_aes_ccm_init(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE];
+ unsigned int textlen;
+
+ memcpy(iv, cryp->req.areq->iv, AES_BLOCK_SIZE);
+ memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
+
+ /* Build B0 */
+ memcpy(b0, iv, AES_BLOCK_SIZE);
+
+ b0[0] |= (8 * ((cryp->authsize - 2) / 2));
+
+ if (cryp->assoclen)
+ b0[0] |= CCM_B0_ADATA;
+
+ textlen = cryp->total_in;
+
+ b0[AES_BLOCK_SIZE - 2] = textlen >> 8;
+ b0[AES_BLOCK_SIZE - 1] = textlen & 0xFF;
+
+ starfive_aes_write_nonce(ctx, (u32 *)b0);
+
+ return 0;
+}
+
+static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_request_ctx *rctx = ctx->rctx;
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ u32 hw_mode;
+
+ /* reset */
+ rctx->csr.aes.v = 0;
+ rctx->csr.aes.aesrst = 1;
+ writel(rctx->csr.aes.v, cryp->base + STARFIVE_AES_CSR);
+
+ /* csr setup */
+ hw_mode = cryp->flags & FLG_MODE_MASK;
+
+ rctx->csr.aes.v = 0;
+
+ switch (ctx->keylen) {
+ case AES_KEYSIZE_128:
+ rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_128;
+ break;
+ case AES_KEYSIZE_192:
+ rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_192;
+ break;
+ case AES_KEYSIZE_256:
+ rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_256;
+ break;
+ }
+
+ rctx->csr.aes.mode = hw_mode;
+ rctx->csr.aes.cmode = !is_encrypt(cryp);
+ rctx->csr.aes.ie = 1;
+
+ if (hw_mode == STARFIVE_AES_MODE_CFB ||
+ hw_mode == STARFIVE_AES_MODE_OFB)
+ rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_128;
+ else
+ rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1;
+
+ if (cryp->side_chan) {
+ rctx->csr.aes.delay_aes = 1;
+ rctx->csr.aes.vaes_start = 1;
+ }
+
+ writel(rctx->csr.aes.v, cryp->base + STARFIVE_AES_CSR);
+
+ cryp->err = starfive_aes_write_key(ctx);
+ if (cryp->err)
+ return cryp->err;
+
+ switch (hw_mode) {
+ case STARFIVE_AES_MODE_GCM:
+ starfive_aes_set_alen(ctx);
+ starfive_aes_set_mlen(ctx);
+ starfive_aes_set_ivlen(ctx);
+ starfive_aes_aead_hw_start(ctx, hw_mode);
+ starfive_aes_write_iv(ctx, (void *)cryp->req.areq->iv);
+ break;
+ case STARFIVE_AES_MODE_CCM:
+ starfive_aes_set_alen(ctx);
+ starfive_aes_set_mlen(ctx);
+ starfive_aes_ccm_init(ctx);
+ starfive_aes_aead_hw_start(ctx, hw_mode);
+ break;
+ case STARFIVE_AES_MODE_OFB:
+ case STARFIVE_AES_MODE_CFB:
+ case STARFIVE_AES_MODE_CBC:
+ case STARFIVE_AES_MODE_CTR:
+ starfive_aes_write_iv(ctx, (void *)cryp->req.sreq->iv);
+ break;
+ default:
+ break;
+ }
+
+ return cryp->err;
+}
+
+static int starfive_aes_read_authtag(struct starfive_cryp_dev *cryp)
+{
+ int i, start_addr;
+
+ if (starfive_aes_wait_busy(cryp))
+ return dev_err_probe(cryp->dev, -ETIMEDOUT,
+ "Timeout waiting for tag generation.");
+
+ start_addr = STARFIVE_AES_NONCE0;
+
+ if (is_gcm(cryp))
+ for (i = 0; i < AES_BLOCK_32; i++, start_addr += 4)
+ cryp->tag_out[i] = readl(cryp->base + start_addr);
+ else
+ for (i = 0; i < AES_BLOCK_32; i++)
+ cryp->tag_out[i] = readl(cryp->base + STARFIVE_AES_AESDIO0R);
+
+ if (is_encrypt(cryp)) {
+ scatterwalk_copychunks(cryp->tag_out, &cryp->out_walk, cryp->authsize, 1);
+ } else {
+ scatterwalk_copychunks(cryp->tag_in, &cryp->in_walk, cryp->authsize, 0);
+
+ if (crypto_memneq(cryp->tag_in, cryp->tag_out, cryp->authsize))
+ return dev_err_probe(cryp->dev, -EBADMSG, "Failed tag verification\n");
+ }
+
+ return 0;
+}
+
+static void starfive_aes_finish_req(struct starfive_cryp_dev *cryp)
+{
+ union starfive_aes_csr csr;
+ int err = cryp->err;
+
+ if (!err && cryp->authsize)
+ err = starfive_aes_read_authtag(cryp);
+
+ if (!err && ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CBC ||
+ (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CTR))
+ starfive_aes_get_iv(cryp, (void *)cryp->req.sreq->iv);
+
+ /* reset irq flags*/
+ csr.v = 0;
+ csr.aesrst = 1;
+ writel(csr.v, cryp->base + STARFIVE_AES_CSR);
+
+ if (cryp->authsize)
+ crypto_finalize_aead_request(cryp->engine, cryp->req.areq, err);
+ else
+ crypto_finalize_skcipher_request(cryp->engine, cryp->req.sreq,
+ err);
+}
+
+void starfive_aes_done_task(unsigned long param)
+{
+ struct starfive_cryp_dev *cryp = (struct starfive_cryp_dev *)param;
+ u32 block[AES_BLOCK_32];
+ u32 stat;
+ int i;
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ block[i] = readl(cryp->base + STARFIVE_AES_AESDIO0R);
+
+ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, AES_BLOCK_SIZE,
+ cryp->total_out), 1);
+
+ cryp->total_out -= min_t(size_t, AES_BLOCK_SIZE, cryp->total_out);
+
+ if (!cryp->total_out) {
+ starfive_aes_finish_req(cryp);
+ return;
+ }
+
+ memset(block, 0, AES_BLOCK_SIZE);
+ scatterwalk_copychunks(block, &cryp->in_walk, min_t(size_t, AES_BLOCK_SIZE,
+ cryp->total_in), 0);
+ cryp->total_in -= min_t(size_t, AES_BLOCK_SIZE, cryp->total_in);
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ writel(block[i], cryp->base + STARFIVE_AES_AESDIO0R);
+
+ stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
+ stat &= ~STARFIVE_IE_MASK_AES_DONE;
+ writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET);
+}
+
+static int starfive_aes_gcm_write_adata(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ struct starfive_cryp_request_ctx *rctx = ctx->rctx;
+ u32 *buffer;
+ int total_len, loop;
+
+ total_len = ALIGN(cryp->assoclen, AES_BLOCK_SIZE) / sizeof(unsigned int);
+ buffer = (u32 *)rctx->adata;
+
+ for (loop = 0; loop < total_len; loop += 4) {
+ writel(*buffer, cryp->base + STARFIVE_AES_NONCE0);
+ buffer++;
+ writel(*buffer, cryp->base + STARFIVE_AES_NONCE1);
+ buffer++;
+ writel(*buffer, cryp->base + STARFIVE_AES_NONCE2);
+ buffer++;
+ writel(*buffer, cryp->base + STARFIVE_AES_NONCE3);
+ buffer++;
+ }
+
+ if (starfive_aes_wait_gcmdone(cryp))
+ return dev_err_probe(cryp->dev, -ETIMEDOUT,
+ "Timeout processing gcm aad block");
+
+ return 0;
+}
+
+static int starfive_aes_ccm_write_adata(struct starfive_cryp_ctx *ctx)
+{
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ struct starfive_cryp_request_ctx *rctx = ctx->rctx;
+ u32 *buffer;
+ u8 *ci;
+ int total_len, loop;
+
+ total_len = cryp->assoclen;
+
+ ci = rctx->adata;
+ writeb(*ci, cryp->base + STARFIVE_AES_AESDIO0R);
+ ci++;
+ writeb(*ci, cryp->base + STARFIVE_AES_AESDIO0R);
+ ci++;
+ total_len -= 2;
+ buffer = (u32 *)ci;
+
+ for (loop = 0; loop < 3; loop++, buffer++)
+ writel(*buffer, cryp->base + STARFIVE_AES_AESDIO0R);
+
+ total_len -= 12;
+
+ while (total_len > 0) {
+ for (loop = 0; loop < AES_BLOCK_32; loop++, buffer++)
+ writel(*buffer, cryp->base + STARFIVE_AES_AESDIO0R);
+
+ total_len -= AES_BLOCK_SIZE;
+ }
+
+ if (starfive_aes_wait_busy(cryp))
+ return dev_err_probe(cryp->dev, -ETIMEDOUT,
+ "Timeout processing ccm aad block");
+
+ return 0;
+}
+
+static int starfive_aes_prepare_req(struct skcipher_request *req,
+ struct aead_request *areq)
+{
+ struct starfive_cryp_ctx *ctx;
+ struct starfive_cryp_request_ctx *rctx;
+ struct starfive_cryp_dev *cryp;
+
+ if (!req && !areq)
+ return -EINVAL;
+
+ ctx = req ? crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)) :
+ crypto_aead_ctx(crypto_aead_reqtfm(areq));
+
+ cryp = ctx->cryp;
+ rctx = req ? skcipher_request_ctx(req) : aead_request_ctx(areq);
+
+ if (req) {
+ cryp->req.sreq = req;
+ cryp->total_in = req->cryptlen;
+ cryp->total_out = req->cryptlen;
+ cryp->assoclen = 0;
+ cryp->authsize = 0;
+ } else {
+ cryp->req.areq = areq;
+ cryp->assoclen = areq->assoclen;
+ cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq));
+ if (is_encrypt(cryp)) {
+ cryp->total_in = areq->cryptlen;
+ cryp->total_out = areq->cryptlen;
+ } else {
+ cryp->total_in = areq->cryptlen - cryp->authsize;
+ cryp->total_out = cryp->total_in;
+ }
+ }
+
+ rctx->in_sg = req ? req->src : areq->src;
+ scatterwalk_start(&cryp->in_walk, rctx->in_sg);
+
+ rctx->out_sg = req ? req->dst : areq->dst;
+ scatterwalk_start(&cryp->out_walk, rctx->out_sg);
+
+ if (cryp->assoclen) {
+ rctx->adata = kzalloc(ALIGN(cryp->assoclen, AES_BLOCK_SIZE), GFP_KERNEL);
+ if (!rctx->adata)
+ return dev_err_probe(cryp->dev, -ENOMEM,
+ "Failed to alloc memory for adata");
+
+ scatterwalk_copychunks(rctx->adata, &cryp->in_walk, cryp->assoclen, 0);
+ scatterwalk_copychunks(NULL, &cryp->out_walk, cryp->assoclen, 2);
+ }
+
+ ctx->rctx = rctx;
+
+ return starfive_aes_hw_init(ctx);
+}
+
+static int starfive_aes_do_one_req(struct crypto_engine *engine, void *areq)
+{
+ struct skcipher_request *req =
+ container_of(areq, struct skcipher_request, base);
+ struct starfive_cryp_ctx *ctx =
+ crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ u32 block[AES_BLOCK_32];
+ u32 stat;
+ int err;
+ int i;
+
+ err = starfive_aes_prepare_req(req, NULL);
+ if (err)
+ return err;
+
+ /*
+ * Write first plain/ciphertext block to start the module
+ * then let irq tasklet handle the rest of the data blocks.
+ */
+ scatterwalk_copychunks(block, &cryp->in_walk, min_t(size_t, AES_BLOCK_SIZE,
+ cryp->total_in), 0);
+ cryp->total_in -= min_t(size_t, AES_BLOCK_SIZE, cryp->total_in);
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ writel(block[i], cryp->base + STARFIVE_AES_AESDIO0R);
+
+ stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
+ stat &= ~STARFIVE_IE_MASK_AES_DONE;
+ writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET);
+
+ return 0;
+}
+
+static int starfive_aes_init_tfm(struct crypto_skcipher *tfm)
+{
+ struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ ctx->cryp = starfive_cryp_find_dev(ctx);
+ if (!ctx->cryp)
+ return -ENODEV;
+
+ crypto_skcipher_set_reqsize(tfm, sizeof(struct starfive_cryp_request_ctx) +
+ sizeof(struct skcipher_request));
+
+ return 0;
+}
+
+static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq)
+{
+ struct aead_request *req =
+ container_of(areq, struct aead_request, base);
+ struct starfive_cryp_ctx *ctx =
+ crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ struct starfive_cryp_request_ctx *rctx = ctx->rctx;
+ u32 block[AES_BLOCK_32];
+ u32 stat;
+ int err;
+ int i;
+
+ err = starfive_aes_prepare_req(NULL, req);
+ if (err)
+ return err;
+
+ if (!cryp->assoclen)
+ goto write_text;
+
+ if ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CCM)
+ cryp->err = starfive_aes_ccm_write_adata(ctx);
+ else
+ cryp->err = starfive_aes_gcm_write_adata(ctx);
+
+ kfree(rctx->adata);
+
+ if (cryp->err)
+ return cryp->err;
+
+write_text:
+ if (!cryp->total_in)
+ goto finish_req;
+
+ /*
+ * Write first plain/ciphertext block to start the module
+ * then let irq tasklet handle the rest of the data blocks.
+ */
+ scatterwalk_copychunks(block, &cryp->in_walk, min_t(size_t, AES_BLOCK_SIZE,
+ cryp->total_in), 0);
+ cryp->total_in -= min_t(size_t, AES_BLOCK_SIZE, cryp->total_in);
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ writel(block[i], cryp->base + STARFIVE_AES_AESDIO0R);
+
+ stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
+ stat &= ~STARFIVE_IE_MASK_AES_DONE;
+ writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET);
+
+ return 0;
+
+finish_req:
+ starfive_aes_finish_req(cryp);
+ return 0;
+}
+
+static int starfive_aes_aead_init_tfm(struct crypto_aead *tfm)
+{
+ struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ struct crypto_tfm *aead = crypto_aead_tfm(tfm);
+ struct crypto_alg *alg = aead->__crt_alg;
+
+ ctx->cryp = starfive_cryp_find_dev(ctx);
+ if (!ctx->cryp)
+ return -ENODEV;
+
+ if (alg->cra_flags & CRYPTO_ALG_NEED_FALLBACK) {
+ ctx->aead_fbk = crypto_alloc_aead(alg->cra_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(ctx->aead_fbk))
+ return dev_err_probe(cryp->dev, PTR_ERR(ctx->aead_fbk),
+ "%s() failed to allocate fallback for %s\n",
+ __func__, alg->cra_name);
+ }
+
+ crypto_aead_set_reqsize(tfm, sizeof(struct starfive_cryp_ctx) +
+ sizeof(struct aead_request));
+
+ return 0;
+}
+
+static void starfive_aes_aead_exit_tfm(struct crypto_aead *tfm)
+{
+ struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+ crypto_free_aead(ctx->aead_fbk);
+}
+
+static int starfive_aes_crypt(struct skcipher_request *req, unsigned long flags)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+ unsigned int blocksize_align = crypto_skcipher_blocksize(tfm) - 1;
+
+ cryp->flags = flags;
+
+ if ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_ECB ||
+ (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CBC)
+ if (req->cryptlen & blocksize_align)
+ return -EINVAL;
+
+ return crypto_transfer_skcipher_request_to_engine(cryp->engine, req);
+}
+
+static int starfive_aes_aead_crypt(struct aead_request *req, unsigned long flags)
+{
+ struct starfive_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct starfive_cryp_dev *cryp = ctx->cryp;
+
+ cryp->flags = flags;
+
+ /*
+ * HW engine could not perform CCM tag verification on
+ * non-blocksize aligned text, use fallback algo instead
+ */
+ if (ctx->aead_fbk && !is_encrypt(cryp)) {
+ struct aead_request *subreq = aead_request_ctx(req);
+
+ aead_request_set_tfm(subreq, ctx->aead_fbk);
+ aead_request_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(subreq, req->src,
+ req->dst, req->cryptlen, req->iv);
+ aead_request_set_ad(subreq, req->assoclen);
+
+ return crypto_aead_decrypt(subreq);
+ }
+
+ return crypto_transfer_aead_request_to_engine(cryp->engine, req);
+}
+
+static int starfive_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ if (!key || !keylen)
+ return -EINVAL;
+
+ if (keylen != AES_KEYSIZE_128 &&
+ keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return 0;
+}
+
+static int starfive_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+ if (!key || !keylen)
+ return -EINVAL;
+
+ if (keylen != AES_KEYSIZE_128 &&
+ keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ if (ctx->aead_fbk)
+ return crypto_aead_setkey(ctx->aead_fbk, key, keylen);
+
+ return 0;
+}
+
+static int starfive_aes_gcm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ return crypto_gcm_check_authsize(authsize);
+}
+
+static int starfive_aes_ccm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+ switch (authsize) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return crypto_aead_setauthsize(ctx->aead_fbk, authsize);
+}
+
+static int starfive_aes_ecb_encrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_ECB | FLG_ENCRYPT);
+}
+
+static int starfive_aes_ecb_decrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_ECB);
+}
+
+static int starfive_aes_cbc_encrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC | FLG_ENCRYPT);
+}
+
+static int starfive_aes_cbc_decrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC);
+}
+
+static int starfive_aes_cfb_encrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB | FLG_ENCRYPT);
+}
+
+static int starfive_aes_cfb_decrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB);
+}
+
+static int starfive_aes_ofb_encrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB | FLG_ENCRYPT);
+}
+
+static int starfive_aes_ofb_decrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB);
+}
+
+static int starfive_aes_ctr_encrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR | FLG_ENCRYPT);
+}
+
+static int starfive_aes_ctr_decrypt(struct skcipher_request *req)
+{
+ return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR);
+}
+
+static int starfive_aes_gcm_encrypt(struct aead_request *req)
+{
+ return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_GCM | FLG_ENCRYPT);
+}
+
+static int starfive_aes_gcm_decrypt(struct aead_request *req)
+{
+ return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_GCM);
+}
+
+static int starfive_aes_ccm_encrypt(struct aead_request *req)
+{
+ int ret;
+
+ ret = starfive_aes_ccm_check_iv(req->iv);
+ if (ret)
+ return ret;
+
+ return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_CCM | FLG_ENCRYPT);
+}
+
+static int starfive_aes_ccm_decrypt(struct aead_request *req)
+{
+ int ret;
+
+ ret = starfive_aes_ccm_check_iv(req->iv);
+ if (ret)
+ return ret;
+
+ return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_CCM);
+}
+
+static struct skcipher_engine_alg skcipher_algs[] = {
+{
+ .base.init = starfive_aes_init_tfm,
+ .base.setkey = starfive_aes_setkey,
+ .base.encrypt = starfive_aes_ecb_encrypt,
+ .base.decrypt = starfive_aes_ecb_decrypt,
+ .base.min_keysize = AES_MIN_KEY_SIZE,
+ .base.max_keysize = AES_MAX_KEY_SIZE,
+ .base.base = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "starfive-ecb-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_do_one_req,
+ },
+}, {
+ .base.init = starfive_aes_init_tfm,
+ .base.setkey = starfive_aes_setkey,
+ .base.encrypt = starfive_aes_cbc_encrypt,
+ .base.decrypt = starfive_aes_cbc_decrypt,
+ .base.min_keysize = AES_MIN_KEY_SIZE,
+ .base.max_keysize = AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "starfive-cbc-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_do_one_req,
+ },
+}, {
+ .base.init = starfive_aes_init_tfm,
+ .base.setkey = starfive_aes_setkey,
+ .base.encrypt = starfive_aes_ctr_encrypt,
+ .base.decrypt = starfive_aes_ctr_decrypt,
+ .base.min_keysize = AES_MIN_KEY_SIZE,
+ .base.max_keysize = AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "starfive-ctr-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_do_one_req,
+ },
+}, {
+ .base.init = starfive_aes_init_tfm,
+ .base.setkey = starfive_aes_setkey,
+ .base.encrypt = starfive_aes_cfb_encrypt,
+ .base.decrypt = starfive_aes_cfb_decrypt,
+ .base.min_keysize = AES_MIN_KEY_SIZE,
+ .base.max_keysize = AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "cfb(aes)",
+ .cra_driver_name = "starfive-cfb-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_do_one_req,
+ },
+}, {
+ .base.init = starfive_aes_init_tfm,
+ .base.setkey = starfive_aes_setkey,
+ .base.encrypt = starfive_aes_ofb_encrypt,
+ .base.decrypt = starfive_aes_ofb_decrypt,
+ .base.min_keysize = AES_MIN_KEY_SIZE,
+ .base.max_keysize = AES_MAX_KEY_SIZE,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "ofb(aes)",
+ .cra_driver_name = "starfive-ofb-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_do_one_req,
+ },
+},
+};
+
+static struct aead_engine_alg aead_algs[] = {
+{
+ .base.setkey = starfive_aes_aead_setkey,
+ .base.setauthsize = starfive_aes_gcm_setauthsize,
+ .base.encrypt = starfive_aes_gcm_encrypt,
+ .base.decrypt = starfive_aes_gcm_decrypt,
+ .base.init = starfive_aes_aead_init_tfm,
+ .base.exit = starfive_aes_aead_exit_tfm,
+ .base.ivsize = GCM_AES_IV_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "starfive-gcm-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_aead_do_one_req,
+ },
+}, {
+ .base.setkey = starfive_aes_aead_setkey,
+ .base.setauthsize = starfive_aes_ccm_setauthsize,
+ .base.encrypt = starfive_aes_ccm_encrypt,
+ .base.decrypt = starfive_aes_ccm_decrypt,
+ .base.init = starfive_aes_aead_init_tfm,
+ .base.exit = starfive_aes_aead_exit_tfm,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
+ .base.base = {
+ .cra_name = "ccm(aes)",
+ .cra_driver_name = "starfive-ccm-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+ .op = {
+ .do_one_request = starfive_aes_aead_do_one_req,
+ },
+},
+};
+
+int starfive_aes_register_algs(void)
+{
+ int ret;
+
+ ret = crypto_engine_register_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
+ if (ret)
+ return ret;
+
+ ret = crypto_engine_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ if (ret)
+ crypto_engine_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
+
+ return ret;
+}
+
+void starfive_aes_unregister_algs(void)
+{
+ crypto_engine_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ crypto_engine_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
+}
diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c
index cc43556b6c80..08e974e0dd12 100644
--- a/drivers/crypto/starfive/jh7110-cryp.c
+++ b/drivers/crypto/starfive/jh7110-cryp.c
@@ -7,17 +7,20 @@
*
*/
+#include <crypto/engine.h>
+#include "jh7110-cryp.h"
#include <linux/clk.h>
-#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-
-#include "jh7110-cryp.h"
+#include <linux/spinlock.h>
#define DRIVER_NAME "jh7110-crypto"
@@ -51,6 +54,13 @@ struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx)
return cryp;
}
+static u16 side_chan;
+module_param(side_chan, ushort, 0);
+MODULE_PARM_DESC(side_chan, "Enable side channel mitigation for AES module.\n"
+ "Enabling this feature will reduce speed performance.\n"
+ " 0 - Disabled\n"
+ " other - Enabled");
+
static int starfive_dma_init(struct starfive_cryp_dev *cryp)
{
dma_cap_mask_t mask;
@@ -82,20 +92,26 @@ static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp)
static irqreturn_t starfive_cryp_irq(int irq, void *priv)
{
u32 status;
+ u32 mask;
struct starfive_cryp_dev *cryp = (struct starfive_cryp_dev *)priv;
+ mask = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
status = readl(cryp->base + STARFIVE_IE_FLAG_OFFSET);
+ if (status & STARFIVE_IE_FLAG_AES_DONE) {
+ mask |= STARFIVE_IE_MASK_AES_DONE;
+ writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET);
+ tasklet_schedule(&cryp->aes_done);
+ }
+
if (status & STARFIVE_IE_FLAG_HASH_DONE) {
- status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
- status |= STARFIVE_IE_MASK_HASH_DONE;
- writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET);
+ mask |= STARFIVE_IE_MASK_HASH_DONE;
+ writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET);
tasklet_schedule(&cryp->hash_done);
}
if (status & STARFIVE_IE_FLAG_PKA_DONE) {
- status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
- status |= STARFIVE_IE_MASK_PKA_DONE;
- writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET);
+ mask |= STARFIVE_IE_MASK_PKA_DONE;
+ writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET);
complete(&cryp->pka_done);
}
@@ -121,10 +137,12 @@ static int starfive_cryp_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base),
"Error remapping memory for platform device\n");
+ tasklet_init(&cryp->aes_done, starfive_aes_done_task, (unsigned long)cryp);
tasklet_init(&cryp->hash_done, starfive_hash_done_task, (unsigned long)cryp);
cryp->phys_base = res->start;
cryp->dma_maxburst = 32;
+ cryp->side_chan = side_chan;
cryp->hclk = devm_clk_get(&pdev->dev, "hclk");
if (IS_ERR(cryp->hclk))
@@ -180,6 +198,10 @@ static int starfive_cryp_probe(struct platform_device *pdev)
if (ret)
goto err_engine_start;
+ ret = starfive_aes_register_algs();
+ if (ret)
+ goto err_algs_aes;
+
ret = starfive_hash_register_algs();
if (ret)
goto err_algs_hash;
@@ -193,6 +215,8 @@ static int starfive_cryp_probe(struct platform_device *pdev)
err_algs_rsa:
starfive_hash_unregister_algs();
err_algs_hash:
+ starfive_aes_unregister_algs();
+err_algs_aes:
crypto_engine_stop(cryp->engine);
err_engine_start:
crypto_engine_exit(cryp->engine);
@@ -207,18 +231,21 @@ err_dma_init:
clk_disable_unprepare(cryp->ahb);
reset_control_assert(cryp->rst);
+ tasklet_kill(&cryp->aes_done);
tasklet_kill(&cryp->hash_done);
err_probe_defer:
return ret;
}
-static int starfive_cryp_remove(struct platform_device *pdev)
+static void starfive_cryp_remove(struct platform_device *pdev)
{
struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev);
+ starfive_aes_unregister_algs();
starfive_hash_unregister_algs();
starfive_rsa_unregister_algs();
+ tasklet_kill(&cryp->aes_done);
tasklet_kill(&cryp->hash_done);
crypto_engine_stop(cryp->engine);
@@ -233,8 +260,6 @@ static int starfive_cryp_remove(struct platform_device *pdev)
clk_disable_unprepare(cryp->hclk);
clk_disable_unprepare(cryp->ahb);
reset_control_assert(cryp->rst);
-
- return 0;
}
static const struct of_device_id starfive_dt_ids[] __maybe_unused = {
@@ -245,7 +270,7 @@ MODULE_DEVICE_TABLE(of, starfive_dt_ids);
static struct platform_driver starfive_cryp_driver = {
.probe = starfive_cryp_probe,
- .remove = starfive_cryp_remove,
+ .remove_new = starfive_cryp_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = starfive_dt_ids,
diff --git a/drivers/crypto/starfive/jh7110-cryp.h b/drivers/crypto/starfive/jh7110-cryp.h
index 0cdcffc0d7d4..fe011d50473d 100644
--- a/drivers/crypto/starfive/jh7110-cryp.h
+++ b/drivers/crypto/starfive/jh7110-cryp.h
@@ -2,13 +2,15 @@
#ifndef __STARFIVE_STR_H__
#define __STARFIVE_STR_H__
+#include <crypto/aes.h>
+#include <crypto/hash.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha2.h>
+#include <crypto/sm3.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-
-#include <crypto/engine.h>
-#include <crypto/sha2.h>
-#include <crypto/sm3.h>
+#include <linux/interrupt.h>
#define STARFIVE_ALG_CR_OFFSET 0x0
#define STARFIVE_ALG_FIFO_OFFSET 0x4
@@ -17,13 +19,56 @@
#define STARFIVE_DMA_IN_LEN_OFFSET 0x10
#define STARFIVE_DMA_OUT_LEN_OFFSET 0x14
+#define STARFIVE_IE_MASK_AES_DONE 0x1
#define STARFIVE_IE_MASK_HASH_DONE 0x4
#define STARFIVE_IE_MASK_PKA_DONE 0x8
+#define STARFIVE_IE_FLAG_AES_DONE 0x1
#define STARFIVE_IE_FLAG_HASH_DONE 0x4
#define STARFIVE_IE_FLAG_PKA_DONE 0x8
#define STARFIVE_MSG_BUFFER_SIZE SZ_16K
#define MAX_KEY_SIZE SHA512_BLOCK_SIZE
+#define STARFIVE_AES_IV_LEN AES_BLOCK_SIZE
+#define STARFIVE_AES_CTR_LEN AES_BLOCK_SIZE
+
+union starfive_aes_csr {
+ u32 v;
+ struct {
+ u32 cmode :1;
+#define STARFIVE_AES_KEYMODE_128 0x0
+#define STARFIVE_AES_KEYMODE_192 0x1
+#define STARFIVE_AES_KEYMODE_256 0x2
+ u32 keymode :2;
+#define STARFIVE_AES_BUSY BIT(3)
+ u32 busy :1;
+ u32 done :1;
+#define STARFIVE_AES_KEY_DONE BIT(5)
+ u32 krdy :1;
+ u32 aesrst :1;
+ u32 ie :1;
+#define STARFIVE_AES_CCM_START BIT(8)
+ u32 ccm_start :1;
+#define STARFIVE_AES_MODE_ECB 0x0
+#define STARFIVE_AES_MODE_CBC 0x1
+#define STARFIVE_AES_MODE_CFB 0x2
+#define STARFIVE_AES_MODE_OFB 0x3
+#define STARFIVE_AES_MODE_CTR 0x4
+#define STARFIVE_AES_MODE_CCM 0x5
+#define STARFIVE_AES_MODE_GCM 0x6
+ u32 mode :3;
+#define STARFIVE_AES_GCM_START BIT(12)
+ u32 gcm_start :1;
+#define STARFIVE_AES_GCM_DONE BIT(13)
+ u32 gcm_done :1;
+ u32 delay_aes :1;
+ u32 vaes_start :1;
+ u32 rsvd_0 :8;
+#define STARFIVE_AES_MODE_XFB_1 0x0
+#define STARFIVE_AES_MODE_XFB_128 0x5
+ u32 stmode :3;
+ u32 rsvd_1 :5;
+ };
+};
union starfive_hash_csr {
u32 v;
@@ -105,7 +150,6 @@ union starfive_alg_cr {
};
struct starfive_cryp_ctx {
- struct crypto_engine_ctx enginectx;
struct starfive_cryp_dev *cryp;
struct starfive_cryp_request_ctx *rctx;
@@ -116,6 +160,7 @@ struct starfive_cryp_ctx {
struct starfive_rsa_key rsa_key;
struct crypto_akcipher *akcipher_fbk;
struct crypto_ahash *ahash_fbk;
+ struct crypto_aead *aead_fbk;
};
struct starfive_cryp_dev {
@@ -133,13 +178,26 @@ struct starfive_cryp_dev {
struct dma_chan *rx;
struct dma_slave_config cfg_in;
struct dma_slave_config cfg_out;
+ struct scatter_walk in_walk;
+ struct scatter_walk out_walk;
struct crypto_engine *engine;
+ struct tasklet_struct aes_done;
struct tasklet_struct hash_done;
struct completion pka_done;
+ size_t assoclen;
+ size_t total_in;
+ size_t total_out;
+ u32 tag_in[4];
+ u32 tag_out[4];
+ unsigned int authsize;
+ unsigned long flags;
int err;
+ bool side_chan;
union starfive_alg_cr alg_cr;
union {
struct ahash_request *hreq;
+ struct aead_request *areq;
+ struct skcipher_request *sreq;
} req;
};
@@ -147,6 +205,7 @@ struct starfive_cryp_request_ctx {
union {
union starfive_hash_csr hash;
union starfive_pka_cacr pka;
+ union starfive_aes_csr aes;
} csr;
struct scatterlist *in_sg;
@@ -157,6 +216,7 @@ struct starfive_cryp_request_ctx {
unsigned int blksize;
unsigned int digsize;
unsigned long in_sg_len;
+ unsigned char *adata;
u8 rsa_data[] __aligned(sizeof(u32));
};
@@ -168,5 +228,9 @@ void starfive_hash_unregister_algs(void);
int starfive_rsa_register_algs(void);
void starfive_rsa_unregister_algs(void);
+int starfive_aes_register_algs(void);
+void starfive_aes_unregister_algs(void);
+
void starfive_hash_done_task(unsigned long param);
+void starfive_aes_done_task(unsigned long param);
#endif
diff --git a/drivers/crypto/starfive/jh7110-hash.c b/drivers/crypto/starfive/jh7110-hash.c
index 5064150b8a1c..cc7650198d70 100644
--- a/drivers/crypto/starfive/jh7110-hash.c
+++ b/drivers/crypto/starfive/jh7110-hash.c
@@ -6,25 +6,20 @@
*
*/
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include "jh7110-cryp.h"
+#include <linux/amba/pl080.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/dma-direct.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <linux/amba/pl080.h>
-
-#include <crypto/hash.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/internal/hash.h>
-
-#include "jh7110-cryp.h"
#define STARFIVE_HASH_REGS_OFFSET 0x300
#define STARFIVE_HASH_SHACSR (STARFIVE_HASH_REGS_OFFSET + 0x0)
@@ -433,10 +428,6 @@ static int starfive_hash_init_tfm(struct crypto_ahash *hash,
ctx->keylen = 0;
ctx->hash_mode = mode;
- ctx->enginectx.op.do_one_request = starfive_hash_one_request;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -445,11 +436,6 @@ static void starfive_hash_exit_tfm(struct crypto_ahash *hash)
struct starfive_cryp_ctx *ctx = crypto_ahash_ctx(hash);
crypto_free_ahash(ctx->ahash_fbk);
-
- ctx->ahash_fbk = NULL;
- ctx->enginectx.op.do_one_request = NULL;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
}
static int starfive_hash_long_setkey(struct starfive_cryp_ctx *ctx,
@@ -619,18 +605,18 @@ static int starfive_hmac_sm3_init_tfm(struct crypto_ahash *hash)
STARFIVE_HASH_SM3);
}
-static struct ahash_alg algs_sha2_sm3[] = {
+static struct ahash_engine_alg algs_sha2_sm3[] = {
{
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_sha224_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_sha224_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
.base = {
@@ -645,19 +631,22 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_hmac_sha224_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .setkey = starfive_hash_setkey,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_hmac_sha224_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.setkey = starfive_hash_setkey,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
.base = {
@@ -672,18 +661,21 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_sha256_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_sha256_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
.base = {
@@ -698,19 +690,22 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_hmac_sha256_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .setkey = starfive_hash_setkey,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_hmac_sha256_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.setkey = starfive_hash_setkey,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct sha256_state),
.base = {
@@ -725,18 +720,21 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_sha384_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_sha384_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
.base = {
@@ -751,19 +749,22 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_hmac_sha384_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .setkey = starfive_hash_setkey,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_hmac_sha384_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.setkey = starfive_hash_setkey,
+ .base.halg = {
.digestsize = SHA384_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
.base = {
@@ -778,18 +779,21 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_sha512_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_sha512_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.halg = {
.digestsize = SHA512_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
.base = {
@@ -804,19 +808,22 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_hmac_sha512_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .setkey = starfive_hash_setkey,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_hmac_sha512_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.setkey = starfive_hash_setkey,
+ .base.halg = {
.digestsize = SHA512_DIGEST_SIZE,
.statesize = sizeof(struct sha512_state),
.base = {
@@ -831,18 +838,21 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_sm3_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_sm3_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.halg = {
.digestsize = SM3_DIGEST_SIZE,
.statesize = sizeof(struct sm3_state),
.base = {
@@ -857,19 +867,22 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
}, {
- .init = starfive_hash_init,
- .update = starfive_hash_update,
- .final = starfive_hash_final,
- .finup = starfive_hash_finup,
- .digest = starfive_hash_digest,
- .export = starfive_hash_export,
- .import = starfive_hash_import,
- .init_tfm = starfive_hmac_sm3_init_tfm,
- .exit_tfm = starfive_hash_exit_tfm,
- .setkey = starfive_hash_setkey,
- .halg = {
+ .base.init = starfive_hash_init,
+ .base.update = starfive_hash_update,
+ .base.final = starfive_hash_final,
+ .base.finup = starfive_hash_finup,
+ .base.digest = starfive_hash_digest,
+ .base.export = starfive_hash_export,
+ .base.import = starfive_hash_import,
+ .base.init_tfm = starfive_hmac_sm3_init_tfm,
+ .base.exit_tfm = starfive_hash_exit_tfm,
+ .base.setkey = starfive_hash_setkey,
+ .base.halg = {
.digestsize = SM3_DIGEST_SIZE,
.statesize = sizeof(struct sm3_state),
.base = {
@@ -884,16 +897,19 @@ static struct ahash_alg algs_sha2_sm3[] = {
.cra_alignmask = 3,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = starfive_hash_one_request,
+ },
},
};
int starfive_hash_register_algs(void)
{
- return crypto_register_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3));
+ return crypto_engine_register_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3));
}
void starfive_hash_unregister_algs(void)
{
- crypto_unregister_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3));
+ crypto_engine_unregister_ahashes(algs_sha2_sm3, ARRAY_SIZE(algs_sha2_sm3));
}
diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig
index 4fc581e9e595..49dfd161e9b9 100644
--- a/drivers/crypto/stm32/Kconfig
+++ b/drivers/crypto/stm32/Kconfig
@@ -16,6 +16,8 @@ config CRYPTO_DEV_STM32_HASH
select CRYPTO_MD5
select CRYPTO_SHA1
select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_SHA3
select CRYPTO_ENGINE
help
This enables support for the HASH hw accelerator which can be found
diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c
index 6b8d731092a4..f095f0065428 100644
--- a/drivers/crypto/stm32/stm32-cryp.c
+++ b/drivers/crypto/stm32/stm32-cryp.c
@@ -5,22 +5,24 @@
* Ux500 support taken from snippets in the old Ux500 cryp driver
*/
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/des.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
+#include <linux/err.h>
#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-
-#include <crypto/aes.h>
-#include <crypto/internal/des.h>
-#include <crypto/engine.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/internal/aead.h>
-#include <crypto/internal/skcipher.h>
+#include <linux/string.h>
#define DRIVER_NAME "stm32-cryp"
@@ -156,7 +158,6 @@ struct stm32_cryp_caps {
};
struct stm32_cryp_ctx {
- struct crypto_engine_ctx enginectx;
struct stm32_cryp *cryp;
int keylen;
__be32 key[AES_KEYSIZE_256 / sizeof(u32)];
@@ -825,35 +826,20 @@ static int stm32_cryp_cpu_start(struct stm32_cryp *cryp)
}
static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq);
-static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
- void *areq);
static int stm32_cryp_init_tfm(struct crypto_skcipher *tfm)
{
- struct stm32_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
-
crypto_skcipher_set_reqsize(tfm, sizeof(struct stm32_cryp_reqctx));
- ctx->enginectx.op.do_one_request = stm32_cryp_cipher_one_req;
- ctx->enginectx.op.prepare_request = stm32_cryp_prepare_cipher_req;
- ctx->enginectx.op.unprepare_request = NULL;
return 0;
}
static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq);
-static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine,
- void *areq);
static int stm32_cryp_aes_aead_init(struct crypto_aead *tfm)
{
- struct stm32_cryp_ctx *ctx = crypto_aead_ctx(tfm);
-
tfm->reqsize = sizeof(struct stm32_cryp_reqctx);
- ctx->enginectx.op.do_one_request = stm32_cryp_aead_one_req;
- ctx->enginectx.op.prepare_request = stm32_cryp_prepare_aead_req;
- ctx->enginectx.op.unprepare_request = NULL;
-
return 0;
}
@@ -1180,9 +1166,6 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req,
cryp = ctx->cryp;
- if (!cryp)
- return -ENODEV;
-
rctx = req ? skcipher_request_ctx(req) : aead_request_ctx(areq);
rctx->mode &= FLG_MODE_MASK;
@@ -1248,16 +1231,6 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req,
return ret;
}
-static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
- void *areq)
-{
- struct skcipher_request *req = container_of(areq,
- struct skcipher_request,
- base);
-
- return stm32_cryp_prepare_req(req, NULL);
-}
-
static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq)
{
struct skcipher_request *req = container_of(areq,
@@ -1270,15 +1243,8 @@ static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq)
if (!cryp)
return -ENODEV;
- return stm32_cryp_cpu_start(cryp);
-}
-
-static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine, void *areq)
-{
- struct aead_request *req = container_of(areq, struct aead_request,
- base);
-
- return stm32_cryp_prepare_req(NULL, req);
+ return stm32_cryp_prepare_req(req, NULL) ?:
+ stm32_cryp_cpu_start(cryp);
}
static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq)
@@ -1287,10 +1253,15 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq)
base);
struct stm32_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
struct stm32_cryp *cryp = ctx->cryp;
+ int err;
if (!cryp)
return -ENODEV;
+ err = stm32_cryp_prepare_req(NULL, req);
+ if (err)
+ return err;
+
if (unlikely(!cryp->payload_in && !cryp->header_in)) {
/* No input data to process: get tag and finish */
stm32_cryp_finish_req(cryp, 0);
@@ -1709,143 +1680,178 @@ static irqreturn_t stm32_cryp_irq(int irq, void *arg)
return IRQ_WAKE_THREAD;
}
-static struct skcipher_alg crypto_algs[] = {
+static struct skcipher_engine_alg crypto_algs[] = {
{
- .base.cra_name = "ecb(aes)",
- .base.cra_driver_name = "stm32-ecb-aes",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = stm32_cryp_aes_setkey,
- .encrypt = stm32_cryp_aes_ecb_encrypt,
- .decrypt = stm32_cryp_aes_ecb_decrypt,
+ .base = {
+ .base.cra_name = "ecb(aes)",
+ .base.cra_driver_name = "stm32-ecb-aes",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = stm32_cryp_aes_setkey,
+ .encrypt = stm32_cryp_aes_ecb_encrypt,
+ .decrypt = stm32_cryp_aes_ecb_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "cbc(aes)",
- .base.cra_driver_name = "stm32-cbc-aes",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = AES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = stm32_cryp_aes_setkey,
- .encrypt = stm32_cryp_aes_cbc_encrypt,
- .decrypt = stm32_cryp_aes_cbc_decrypt,
+ .base = {
+ .base.cra_name = "cbc(aes)",
+ .base.cra_driver_name = "stm32-cbc-aes",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = stm32_cryp_aes_setkey,
+ .encrypt = stm32_cryp_aes_cbc_encrypt,
+ .decrypt = stm32_cryp_aes_cbc_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "ctr(aes)",
- .base.cra_driver_name = "stm32-ctr-aes",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = 1,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = stm32_cryp_aes_setkey,
- .encrypt = stm32_cryp_aes_ctr_encrypt,
- .decrypt = stm32_cryp_aes_ctr_decrypt,
+ .base = {
+ .base.cra_name = "ctr(aes)",
+ .base.cra_driver_name = "stm32-ctr-aes",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = stm32_cryp_aes_setkey,
+ .encrypt = stm32_cryp_aes_ctr_encrypt,
+ .decrypt = stm32_cryp_aes_ctr_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "ecb(des)",
- .base.cra_driver_name = "stm32-ecb-des",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = DES_BLOCK_SIZE,
- .max_keysize = DES_BLOCK_SIZE,
- .setkey = stm32_cryp_des_setkey,
- .encrypt = stm32_cryp_des_ecb_encrypt,
- .decrypt = stm32_cryp_des_ecb_decrypt,
+ .base = {
+ .base.cra_name = "ecb(des)",
+ .base.cra_driver_name = "stm32-ecb-des",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = DES_BLOCK_SIZE,
+ .max_keysize = DES_BLOCK_SIZE,
+ .setkey = stm32_cryp_des_setkey,
+ .encrypt = stm32_cryp_des_ecb_encrypt,
+ .decrypt = stm32_cryp_des_ecb_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "cbc(des)",
- .base.cra_driver_name = "stm32-cbc-des",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = DES_BLOCK_SIZE,
- .max_keysize = DES_BLOCK_SIZE,
- .ivsize = DES_BLOCK_SIZE,
- .setkey = stm32_cryp_des_setkey,
- .encrypt = stm32_cryp_des_cbc_encrypt,
- .decrypt = stm32_cryp_des_cbc_decrypt,
+ .base = {
+ .base.cra_name = "cbc(des)",
+ .base.cra_driver_name = "stm32-cbc-des",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = DES_BLOCK_SIZE,
+ .max_keysize = DES_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = stm32_cryp_des_setkey,
+ .encrypt = stm32_cryp_des_cbc_encrypt,
+ .decrypt = stm32_cryp_des_cbc_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "ecb(des3_ede)",
- .base.cra_driver_name = "stm32-ecb-des3",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = 3 * DES_BLOCK_SIZE,
- .max_keysize = 3 * DES_BLOCK_SIZE,
- .setkey = stm32_cryp_tdes_setkey,
- .encrypt = stm32_cryp_tdes_ecb_encrypt,
- .decrypt = stm32_cryp_tdes_ecb_decrypt,
+ .base = {
+ .base.cra_name = "ecb(des3_ede)",
+ .base.cra_driver_name = "stm32-ecb-des3",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = 3 * DES_BLOCK_SIZE,
+ .max_keysize = 3 * DES_BLOCK_SIZE,
+ .setkey = stm32_cryp_tdes_setkey,
+ .encrypt = stm32_cryp_tdes_ecb_encrypt,
+ .decrypt = stm32_cryp_tdes_ecb_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
{
- .base.cra_name = "cbc(des3_ede)",
- .base.cra_driver_name = "stm32-cbc-des3",
- .base.cra_priority = 200,
- .base.cra_flags = CRYPTO_ALG_ASYNC,
- .base.cra_blocksize = DES_BLOCK_SIZE,
- .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
- .base.cra_alignmask = 0,
- .base.cra_module = THIS_MODULE,
-
- .init = stm32_cryp_init_tfm,
- .min_keysize = 3 * DES_BLOCK_SIZE,
- .max_keysize = 3 * DES_BLOCK_SIZE,
- .ivsize = DES_BLOCK_SIZE,
- .setkey = stm32_cryp_tdes_setkey,
- .encrypt = stm32_cryp_tdes_cbc_encrypt,
- .decrypt = stm32_cryp_tdes_cbc_decrypt,
+ .base = {
+ .base.cra_name = "cbc(des3_ede)",
+ .base.cra_driver_name = "stm32-cbc-des3",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_ASYNC,
+ .base.cra_blocksize = DES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+
+ .init = stm32_cryp_init_tfm,
+ .min_keysize = 3 * DES_BLOCK_SIZE,
+ .max_keysize = 3 * DES_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = stm32_cryp_tdes_setkey,
+ .encrypt = stm32_cryp_tdes_cbc_encrypt,
+ .decrypt = stm32_cryp_tdes_cbc_decrypt,
+ },
+ .op = {
+ .do_one_request = stm32_cryp_cipher_one_req,
+ },
},
};
-static struct aead_alg aead_algs[] = {
+static struct aead_engine_alg aead_algs[] = {
{
- .setkey = stm32_cryp_aes_aead_setkey,
- .setauthsize = stm32_cryp_aes_gcm_setauthsize,
- .encrypt = stm32_cryp_aes_gcm_encrypt,
- .decrypt = stm32_cryp_aes_gcm_decrypt,
- .init = stm32_cryp_aes_aead_init,
- .ivsize = 12,
- .maxauthsize = AES_BLOCK_SIZE,
+ .base.setkey = stm32_cryp_aes_aead_setkey,
+ .base.setauthsize = stm32_cryp_aes_gcm_setauthsize,
+ .base.encrypt = stm32_cryp_aes_gcm_encrypt,
+ .base.decrypt = stm32_cryp_aes_gcm_decrypt,
+ .base.init = stm32_cryp_aes_aead_init,
+ .base.ivsize = 12,
+ .base.maxauthsize = AES_BLOCK_SIZE,
- .base = {
+ .base.base = {
.cra_name = "gcm(aes)",
.cra_driver_name = "stm32-gcm-aes",
.cra_priority = 200,
@@ -1855,17 +1861,20 @@ static struct aead_alg aead_algs[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
+ .op = {
+ .do_one_request = stm32_cryp_aead_one_req,
+ },
},
{
- .setkey = stm32_cryp_aes_aead_setkey,
- .setauthsize = stm32_cryp_aes_ccm_setauthsize,
- .encrypt = stm32_cryp_aes_ccm_encrypt,
- .decrypt = stm32_cryp_aes_ccm_decrypt,
- .init = stm32_cryp_aes_aead_init,
- .ivsize = AES_BLOCK_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
+ .base.setkey = stm32_cryp_aes_aead_setkey,
+ .base.setauthsize = stm32_cryp_aes_ccm_setauthsize,
+ .base.encrypt = stm32_cryp_aes_ccm_encrypt,
+ .base.decrypt = stm32_cryp_aes_ccm_decrypt,
+ .base.init = stm32_cryp_aes_aead_init,
+ .base.ivsize = AES_BLOCK_SIZE,
+ .base.maxauthsize = AES_BLOCK_SIZE,
- .base = {
+ .base.base = {
.cra_name = "ccm(aes)",
.cra_driver_name = "stm32-ccm-aes",
.cra_priority = 200,
@@ -1875,6 +1884,9 @@ static struct aead_alg aead_algs[] = {
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
},
+ .op = {
+ .do_one_request = stm32_cryp_aead_one_req,
+ },
},
};
@@ -2036,14 +2048,14 @@ static int stm32_cryp_probe(struct platform_device *pdev)
goto err_engine2;
}
- ret = crypto_register_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
+ ret = crypto_engine_register_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
if (ret) {
dev_err(dev, "Could not register algs\n");
goto err_algs;
}
if (cryp->caps->aeads_support) {
- ret = crypto_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ ret = crypto_engine_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
if (ret)
goto err_aead_algs;
}
@@ -2055,7 +2067,7 @@ static int stm32_cryp_probe(struct platform_device *pdev)
return 0;
err_aead_algs:
- crypto_unregister_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
+ crypto_engine_unregister_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
err_algs:
err_engine2:
crypto_engine_exit(cryp->engine);
@@ -2085,8 +2097,8 @@ static int stm32_cryp_remove(struct platform_device *pdev)
return ret;
if (cryp->caps->aeads_support)
- crypto_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
- crypto_unregister_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
+ crypto_engine_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ crypto_engine_unregister_skciphers(crypto_algs, ARRAY_SIZE(crypto_algs));
crypto_engine_exit(cryp->engine);
diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c
index f0df32382719..2b2382d4332c 100644
--- a/drivers/crypto/stm32/stm32-hash.c
+++ b/drivers/crypto/stm32/stm32-hash.c
@@ -6,27 +6,26 @@
* Author(s): Lionel DEBIEVE <lionel.debieve@st.com> for STMicroelectronics.
*/
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/md5.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sha3.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-
-#include <crypto/engine.h>
-#include <crypto/hash.h>
-#include <crypto/md5.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/sha1.h>
-#include <crypto/sha2.h>
-#include <crypto/internal/hash.h>
+#include <linux/string.h>
#define HASH_CR 0x00
#define HASH_DIN 0x04
@@ -45,19 +44,11 @@
#define HASH_CR_DMAE BIT(3)
#define HASH_CR_DATATYPE_POS 4
#define HASH_CR_MODE BIT(6)
+#define HASH_CR_ALGO_POS 7
#define HASH_CR_MDMAT BIT(13)
#define HASH_CR_DMAA BIT(14)
#define HASH_CR_LKEY BIT(16)
-#define HASH_CR_ALGO_SHA1 0x0
-#define HASH_CR_ALGO_MD5 0x80
-#define HASH_CR_ALGO_SHA224 0x40000
-#define HASH_CR_ALGO_SHA256 0x40080
-
-#define HASH_CR_UX500_EMPTYMSG BIT(20)
-#define HASH_CR_UX500_ALGO_SHA1 BIT(7)
-#define HASH_CR_UX500_ALGO_SHA256 0x0
-
/* Interrupt */
#define HASH_DINIE BIT(0)
#define HASH_DCIE BIT(1)
@@ -66,9 +57,6 @@
#define HASH_MASK_CALC_COMPLETION BIT(0)
#define HASH_MASK_DATA_INPUT BIT(1)
-/* Context swap register */
-#define HASH_CSR_REGISTER_NUMBER 54
-
/* Status Flags */
#define HASH_SR_DATA_INPUT_READY BIT(0)
#define HASH_SR_OUTPUT_READY BIT(1)
@@ -79,28 +67,39 @@
#define HASH_STR_NBLW_MASK GENMASK(4, 0)
#define HASH_STR_DCAL BIT(8)
+/* HWCFGR Register */
+#define HASH_HWCFG_DMA_MASK GENMASK(3, 0)
+
+/* Context swap register */
+#define HASH_CSR_NB_SHA256_HMAC 54
+#define HASH_CSR_NB_SHA256 38
+#define HASH_CSR_NB_SHA512_HMAC 103
+#define HASH_CSR_NB_SHA512 91
+#define HASH_CSR_NB_SHA3_HMAC 88
+#define HASH_CSR_NB_SHA3 72
+#define HASH_CSR_NB_MAX HASH_CSR_NB_SHA512_HMAC
+
#define HASH_FLAGS_INIT BIT(0)
#define HASH_FLAGS_OUTPUT_READY BIT(1)
#define HASH_FLAGS_CPU BIT(2)
-#define HASH_FLAGS_DMA_READY BIT(3)
-#define HASH_FLAGS_DMA_ACTIVE BIT(4)
-#define HASH_FLAGS_HMAC_INIT BIT(5)
-#define HASH_FLAGS_HMAC_FINAL BIT(6)
-#define HASH_FLAGS_HMAC_KEY BIT(7)
-
+#define HASH_FLAGS_DMA_ACTIVE BIT(3)
+#define HASH_FLAGS_HMAC_INIT BIT(4)
+#define HASH_FLAGS_HMAC_FINAL BIT(5)
+#define HASH_FLAGS_HMAC_KEY BIT(6)
+#define HASH_FLAGS_SHA3_MODE BIT(7)
#define HASH_FLAGS_FINAL BIT(15)
#define HASH_FLAGS_FINUP BIT(16)
-#define HASH_FLAGS_ALGO_MASK GENMASK(21, 18)
-#define HASH_FLAGS_MD5 BIT(18)
-#define HASH_FLAGS_SHA1 BIT(19)
-#define HASH_FLAGS_SHA224 BIT(20)
-#define HASH_FLAGS_SHA256 BIT(21)
+#define HASH_FLAGS_ALGO_MASK GENMASK(20, 17)
+#define HASH_FLAGS_ALGO_SHIFT 17
+#define HASH_FLAGS_ERRORS BIT(21)
#define HASH_FLAGS_EMPTY BIT(22)
#define HASH_FLAGS_HMAC BIT(23)
#define HASH_OP_UPDATE 1
#define HASH_OP_FINAL 2
+#define HASH_BURST_LEVEL 4
+
enum stm32_hash_data_format {
HASH_DATA_32_BITS = 0x0,
HASH_DATA_16_BITS = 0x1,
@@ -108,16 +107,30 @@ enum stm32_hash_data_format {
HASH_DATA_1_BIT = 0x3
};
-#define HASH_BUFLEN 256
-#define HASH_LONG_KEY 64
-#define HASH_MAX_KEY_SIZE (SHA256_BLOCK_SIZE * 8)
-#define HASH_QUEUE_LENGTH 16
-#define HASH_DMA_THRESHOLD 50
+#define HASH_BUFLEN (SHA3_224_BLOCK_SIZE + 4)
+#define HASH_MAX_KEY_SIZE (SHA512_BLOCK_SIZE * 8)
+
+enum stm32_hash_algo {
+ HASH_SHA1 = 0,
+ HASH_MD5 = 1,
+ HASH_SHA224 = 2,
+ HASH_SHA256 = 3,
+ HASH_SHA3_224 = 4,
+ HASH_SHA3_256 = 5,
+ HASH_SHA3_384 = 6,
+ HASH_SHA3_512 = 7,
+ HASH_SHA384 = 12,
+ HASH_SHA512 = 15,
+};
+
+enum ux500_hash_algo {
+ HASH_SHA256_UX500 = 0,
+ HASH_SHA1_UX500 = 1,
+};
#define HASH_AUTOSUSPEND_DELAY 50
struct stm32_hash_ctx {
- struct crypto_engine_ctx enginectx;
struct stm32_hash_dev *hdev;
struct crypto_shash *xtfm;
unsigned long flags;
@@ -130,19 +143,19 @@ struct stm32_hash_state {
u32 flags;
u16 bufcnt;
- u16 buflen;
+ u16 blocklen;
u8 buffer[HASH_BUFLEN] __aligned(4);
/* hash state */
- u32 hw_context[3 + HASH_CSR_REGISTER_NUMBER];
+ u32 hw_context[3 + HASH_CSR_NB_MAX];
};
struct stm32_hash_request_ctx {
struct stm32_hash_dev *hdev;
unsigned long op;
- u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
+ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
size_t digcnt;
/* DMA */
@@ -161,17 +174,18 @@ struct stm32_hash_request_ctx {
};
struct stm32_hash_algs_info {
- struct ahash_alg *algs_list;
+ struct ahash_engine_alg *algs_list;
size_t size;
};
struct stm32_hash_pdata {
- struct stm32_hash_algs_info *algs_info;
- size_t algs_info_size;
- bool has_sr;
- bool has_mdmat;
- bool broken_emptymsg;
- bool ux500;
+ const int alg_shift;
+ const struct stm32_hash_algs_info *algs_info;
+ size_t algs_info_size;
+ bool has_sr;
+ bool has_mdmat;
+ bool broken_emptymsg;
+ bool ux500;
};
struct stm32_hash_dev {
@@ -182,7 +196,6 @@ struct stm32_hash_dev {
void __iomem *io_base;
phys_addr_t phys_base;
u32 dma_mode;
- u32 dma_maxburst;
bool polled;
struct ahash_request *req;
@@ -269,37 +282,25 @@ static int stm32_hash_write_key(struct stm32_hash_dev *hdev)
return 0;
}
-static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev, int bufcnt)
+static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev)
{
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(hdev->req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(hdev->req);
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm);
struct stm32_hash_state *state = &rctx->state;
+ u32 alg = (state->flags & HASH_FLAGS_ALGO_MASK) >> HASH_FLAGS_ALGO_SHIFT;
u32 reg = HASH_CR_INIT;
if (!(hdev->flags & HASH_FLAGS_INIT)) {
- switch (state->flags & HASH_FLAGS_ALGO_MASK) {
- case HASH_FLAGS_MD5:
- reg |= HASH_CR_ALGO_MD5;
- break;
- case HASH_FLAGS_SHA1:
- if (hdev->pdata->ux500)
- reg |= HASH_CR_UX500_ALGO_SHA1;
+ if (hdev->pdata->ux500) {
+ reg |= ((alg & BIT(0)) << HASH_CR_ALGO_POS);
+ } else {
+ if (hdev->pdata->alg_shift == HASH_CR_ALGO_POS)
+ reg |= ((alg & BIT(1)) << 17) |
+ ((alg & BIT(0)) << HASH_CR_ALGO_POS);
else
- reg |= HASH_CR_ALGO_SHA1;
- break;
- case HASH_FLAGS_SHA224:
- reg |= HASH_CR_ALGO_SHA224;
- break;
- case HASH_FLAGS_SHA256:
- if (hdev->pdata->ux500)
- reg |= HASH_CR_UX500_ALGO_SHA256;
- else
- reg |= HASH_CR_ALGO_SHA256;
- break;
- default:
- reg |= HASH_CR_ALGO_MD5;
+ reg |= alg << hdev->pdata->alg_shift;
}
reg |= (rctx->data_type << HASH_CR_DATATYPE_POS);
@@ -307,7 +308,7 @@ static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev, int bufcnt)
if (state->flags & HASH_FLAGS_HMAC) {
hdev->flags |= HASH_FLAGS_HMAC;
reg |= HASH_CR_MODE;
- if (ctx->keylen > HASH_LONG_KEY)
+ if (ctx->keylen > crypto_ahash_blocksize(tfm))
reg |= HASH_CR_LKEY;
}
@@ -318,6 +319,12 @@ static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev, int bufcnt)
hdev->flags |= HASH_FLAGS_INIT;
+ /*
+ * After first block + 1 words are fill up,
+ * we only need to fill 1 block to start partial computation
+ */
+ rctx->state.blocklen -= sizeof(u32);
+
dev_dbg(hdev->dev, "Write Control %x\n", reg);
}
}
@@ -327,9 +334,9 @@ static void stm32_hash_append_sg(struct stm32_hash_request_ctx *rctx)
struct stm32_hash_state *state = &rctx->state;
size_t count;
- while ((state->bufcnt < state->buflen) && rctx->total) {
+ while ((state->bufcnt < state->blocklen) && rctx->total) {
count = min(rctx->sg->length - rctx->offset, rctx->total);
- count = min_t(size_t, count, state->buflen - state->bufcnt);
+ count = min_t(size_t, count, state->blocklen - state->bufcnt);
if (count <= 0) {
if ((rctx->sg->length == 0) && !sg_is_last(rctx->sg)) {
@@ -384,7 +391,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
hdev->flags |= HASH_FLAGS_CPU;
- stm32_hash_write_ctrl(hdev, length);
+ stm32_hash_write_ctrl(hdev);
if (stm32_hash_wait_busy(hdev))
return -ETIMEDOUT;
@@ -419,20 +426,59 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
return 0;
}
+static int hash_swap_reg(struct stm32_hash_request_ctx *rctx)
+{
+ struct stm32_hash_state *state = &rctx->state;
+
+ switch ((state->flags & HASH_FLAGS_ALGO_MASK) >>
+ HASH_FLAGS_ALGO_SHIFT) {
+ case HASH_MD5:
+ case HASH_SHA1:
+ case HASH_SHA224:
+ case HASH_SHA256:
+ if (state->flags & HASH_FLAGS_HMAC)
+ return HASH_CSR_NB_SHA256_HMAC;
+ else
+ return HASH_CSR_NB_SHA256;
+ break;
+
+ case HASH_SHA384:
+ case HASH_SHA512:
+ if (state->flags & HASH_FLAGS_HMAC)
+ return HASH_CSR_NB_SHA512_HMAC;
+ else
+ return HASH_CSR_NB_SHA512;
+ break;
+
+ case HASH_SHA3_224:
+ case HASH_SHA3_256:
+ case HASH_SHA3_384:
+ case HASH_SHA3_512:
+ if (state->flags & HASH_FLAGS_HMAC)
+ return HASH_CSR_NB_SHA3_HMAC;
+ else
+ return HASH_CSR_NB_SHA3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int stm32_hash_update_cpu(struct stm32_hash_dev *hdev)
{
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(hdev->req);
struct stm32_hash_state *state = &rctx->state;
u32 *preg = state->hw_context;
int bufcnt, err = 0, final;
- int i;
+ int i, swap_reg;
dev_dbg(hdev->dev, "%s flags %x\n", __func__, state->flags);
final = state->flags & HASH_FLAGS_FINAL;
- while ((rctx->total >= state->buflen) ||
- (state->bufcnt + rctx->total >= state->buflen)) {
+ while ((rctx->total >= state->blocklen) ||
+ (state->bufcnt + rctx->total >= state->blocklen)) {
stm32_hash_append_sg(rctx);
bufcnt = state->bufcnt;
state->bufcnt = 0;
@@ -455,11 +501,13 @@ static int stm32_hash_update_cpu(struct stm32_hash_dev *hdev)
if (stm32_hash_wait_busy(hdev))
return -ETIMEDOUT;
+ swap_reg = hash_swap_reg(rctx);
+
if (!hdev->pdata->ux500)
*preg++ = stm32_hash_read(hdev, HASH_IMR);
*preg++ = stm32_hash_read(hdev, HASH_STR);
*preg++ = stm32_hash_read(hdev, HASH_CR);
- for (i = 0; i < HASH_CSR_REGISTER_NUMBER; i++)
+ for (i = 0; i < swap_reg; i++)
*preg++ = stm32_hash_read(hdev, HASH_CSR(i));
state->flags |= HASH_FLAGS_INIT;
@@ -492,7 +540,7 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev,
reg = stm32_hash_read(hdev, HASH_CR);
- if (!hdev->pdata->has_mdmat) {
+ if (hdev->pdata->has_mdmat) {
if (mdma)
reg |= HASH_CR_MDMAT;
else
@@ -533,8 +581,6 @@ static void stm32_hash_dma_callback(void *param)
struct stm32_hash_dev *hdev = param;
complete(&hdev->dma_completion);
-
- hdev->flags |= HASH_FLAGS_DMA_READY;
}
static int stm32_hash_hmac_dma_send(struct stm32_hash_dev *hdev)
@@ -544,7 +590,7 @@ static int stm32_hash_hmac_dma_send(struct stm32_hash_dev *hdev)
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm);
int err;
- if (ctx->keylen < HASH_DMA_THRESHOLD || (hdev->dma_mode == 1)) {
+ if (ctx->keylen < rctx->state.blocklen || hdev->dma_mode == 1) {
err = stm32_hash_write_key(hdev);
if (stm32_hash_wait_busy(hdev))
return -ETIMEDOUT;
@@ -579,8 +625,8 @@ static int stm32_hash_dma_init(struct stm32_hash_dev *hdev)
dma_conf.direction = DMA_MEM_TO_DEV;
dma_conf.dst_addr = hdev->phys_base + HASH_DIN;
dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dma_conf.src_maxburst = hdev->dma_maxburst;
- dma_conf.dst_maxburst = hdev->dma_maxburst;
+ dma_conf.src_maxburst = HASH_BURST_LEVEL;
+ dma_conf.dst_maxburst = HASH_BURST_LEVEL;
dma_conf.device_fc = false;
chan = dma_request_chan(hdev->dev, "in");
@@ -607,18 +653,18 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(hdev->req);
u32 *buffer = (void *)rctx->state.buffer;
struct scatterlist sg[1], *tsg;
- int err = 0, len = 0, reg, ncp = 0;
- unsigned int i;
+ int err = 0, reg, ncp = 0;
+ unsigned int i, len = 0, bufcnt = 0;
+ bool is_last = false;
rctx->sg = hdev->req->src;
rctx->total = hdev->req->nbytes;
rctx->nents = sg_nents(rctx->sg);
-
if (rctx->nents < 0)
return -EINVAL;
- stm32_hash_write_ctrl(hdev, rctx->total);
+ stm32_hash_write_ctrl(hdev);
if (hdev->flags & HASH_FLAGS_HMAC) {
err = stm32_hash_hmac_dma_send(hdev);
@@ -627,10 +673,12 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
}
for_each_sg(rctx->sg, tsg, rctx->nents, i) {
+ sg[0] = *tsg;
len = sg->length;
- sg[0] = *tsg;
- if (sg_is_last(sg)) {
+ if (sg_is_last(sg) || (bufcnt + sg[0].length) >= rctx->total) {
+ sg->length = rctx->total - bufcnt;
+ is_last = true;
if (hdev->dma_mode == 1) {
len = (ALIGN(sg->length, 16) - 16);
@@ -656,13 +704,15 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
return -ENOMEM;
}
- err = stm32_hash_xmit_dma(hdev, sg, len,
- !sg_is_last(sg));
+ err = stm32_hash_xmit_dma(hdev, sg, len, !is_last);
+ bufcnt += sg[0].length;
dma_unmap_sg(hdev->dev, sg, 1, DMA_TO_DEVICE);
if (err == -ENOMEM)
return err;
+ if (is_last)
+ break;
}
if (hdev->dma_mode == 1) {
@@ -718,11 +768,12 @@ static struct stm32_hash_dev *stm32_hash_find_dev(struct stm32_hash_ctx *ctx)
static bool stm32_hash_dma_aligned_data(struct ahash_request *req)
{
struct scatterlist *sg;
+ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
int i;
- if (req->nbytes <= HASH_DMA_THRESHOLD)
+ if (!hdev->dma_lch || req->nbytes <= rctx->state.blocklen)
return false;
if (sg_nents(req->src) > 1) {
@@ -748,31 +799,64 @@ static int stm32_hash_init(struct ahash_request *req)
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
struct stm32_hash_state *state = &rctx->state;
+ bool sha3_mode = ctx->flags & HASH_FLAGS_SHA3_MODE;
rctx->hdev = hdev;
state->flags = HASH_FLAGS_CPU;
+ if (sha3_mode)
+ state->flags |= HASH_FLAGS_SHA3_MODE;
+
rctx->digcnt = crypto_ahash_digestsize(tfm);
switch (rctx->digcnt) {
case MD5_DIGEST_SIZE:
- state->flags |= HASH_FLAGS_MD5;
+ state->flags |= HASH_MD5 << HASH_FLAGS_ALGO_SHIFT;
break;
case SHA1_DIGEST_SIZE:
- state->flags |= HASH_FLAGS_SHA1;
+ if (hdev->pdata->ux500)
+ state->flags |= HASH_SHA1_UX500 << HASH_FLAGS_ALGO_SHIFT;
+ else
+ state->flags |= HASH_SHA1 << HASH_FLAGS_ALGO_SHIFT;
break;
case SHA224_DIGEST_SIZE:
- state->flags |= HASH_FLAGS_SHA224;
+ if (sha3_mode)
+ state->flags |= HASH_SHA3_224 << HASH_FLAGS_ALGO_SHIFT;
+ else
+ state->flags |= HASH_SHA224 << HASH_FLAGS_ALGO_SHIFT;
break;
case SHA256_DIGEST_SIZE:
- state->flags |= HASH_FLAGS_SHA256;
+ if (sha3_mode) {
+ state->flags |= HASH_SHA3_256 << HASH_FLAGS_ALGO_SHIFT;
+ } else {
+ if (hdev->pdata->ux500)
+ state->flags |= HASH_SHA256_UX500 << HASH_FLAGS_ALGO_SHIFT;
+ else
+ state->flags |= HASH_SHA256 << HASH_FLAGS_ALGO_SHIFT;
+ }
+ break;
+ case SHA384_DIGEST_SIZE:
+ if (sha3_mode)
+ state->flags |= HASH_SHA3_384 << HASH_FLAGS_ALGO_SHIFT;
+ else
+ state->flags |= HASH_SHA384 << HASH_FLAGS_ALGO_SHIFT;
+ break;
+ case SHA512_DIGEST_SIZE:
+ if (sha3_mode)
+ state->flags |= HASH_SHA3_512 << HASH_FLAGS_ALGO_SHIFT;
+ else
+ state->flags |= HASH_SHA512 << HASH_FLAGS_ALGO_SHIFT;
break;
default:
return -EINVAL;
}
rctx->state.bufcnt = 0;
- rctx->state.buflen = HASH_BUFLEN;
+ rctx->state.blocklen = crypto_ahash_blocksize(tfm) + sizeof(u32);
+ if (rctx->state.blocklen > HASH_BUFLEN) {
+ dev_err(hdev->dev, "Error, block too large");
+ return -EINVAL;
+ }
rctx->total = 0;
rctx->offset = 0;
rctx->data_type = HASH_DATA_8_BITS;
@@ -842,6 +926,7 @@ static void stm32_hash_emptymsg_fallback(struct ahash_request *req)
static void stm32_hash_copy_hash(struct ahash_request *req)
{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
struct stm32_hash_state *state = &rctx->state;
struct stm32_hash_dev *hdev = rctx->hdev;
@@ -851,22 +936,7 @@ static void stm32_hash_copy_hash(struct ahash_request *req)
if (hdev->pdata->broken_emptymsg && (state->flags & HASH_FLAGS_EMPTY))
return stm32_hash_emptymsg_fallback(req);
- switch (state->flags & HASH_FLAGS_ALGO_MASK) {
- case HASH_FLAGS_MD5:
- hashsize = MD5_DIGEST_SIZE;
- break;
- case HASH_FLAGS_SHA1:
- hashsize = SHA1_DIGEST_SIZE;
- break;
- case HASH_FLAGS_SHA224:
- hashsize = SHA224_DIGEST_SIZE;
- break;
- case HASH_FLAGS_SHA256:
- hashsize = SHA256_DIGEST_SIZE;
- break;
- default:
- return;
- }
+ hashsize = crypto_ahash_digestsize(tfm);
for (i = 0; i < hashsize / sizeof(u32); i++) {
if (hdev->pdata->ux500)
@@ -881,6 +951,11 @@ static void stm32_hash_copy_hash(struct ahash_request *req)
static int stm32_hash_finish(struct ahash_request *req)
{
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
+ u32 reg;
+
+ reg = stm32_hash_read(rctx->hdev, HASH_SR);
+ reg &= ~HASH_SR_OUTPUT_READY;
+ stm32_hash_write(rctx->hdev, HASH_SR, reg);
if (!req->result)
return -EINVAL;
@@ -920,6 +995,7 @@ static int stm32_hash_one_request(struct crypto_engine *engine, void *areq)
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
struct stm32_hash_state *state = &rctx->state;
+ int swap_reg;
int err = 0;
if (!hdev)
@@ -932,6 +1008,7 @@ static int stm32_hash_one_request(struct crypto_engine *engine, void *areq)
hdev->req = req;
hdev->flags = 0;
+ swap_reg = hash_swap_reg(rctx);
if (state->flags & HASH_FLAGS_INIT) {
u32 *preg = rctx->state.hw_context;
@@ -945,7 +1022,7 @@ static int stm32_hash_one_request(struct crypto_engine *engine, void *areq)
reg = *preg++ | HASH_CR_INIT;
stm32_hash_write(hdev, HASH_CR, reg);
- for (i = 0; i < HASH_CSR_REGISTER_NUMBER; i++)
+ for (i = 0; i < swap_reg; i++)
stm32_hash_write(hdev, HASH_CSR(i), *preg++);
hdev->flags |= HASH_FLAGS_INIT;
@@ -1000,7 +1077,7 @@ static int stm32_hash_update(struct ahash_request *req)
rctx->sg = req->src;
rctx->offset = 0;
- if ((state->bufcnt + rctx->total < state->buflen)) {
+ if ((state->bufcnt + rctx->total < state->blocklen)) {
stm32_hash_append_sg(rctx);
return 0;
}
@@ -1102,8 +1179,7 @@ static int stm32_hash_init_fallback(struct crypto_tfm *tfm)
return 0;
}
-static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm,
- const char *algs_hmac_name)
+static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm, u32 algs_flags)
{
struct stm32_hash_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -1112,38 +1188,33 @@ static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm,
ctx->keylen = 0;
- if (algs_hmac_name)
- ctx->flags |= HASH_FLAGS_HMAC;
-
- ctx->enginectx.op.do_one_request = stm32_hash_one_request;
+ if (algs_flags)
+ ctx->flags |= algs_flags;
return stm32_hash_init_fallback(tfm);
}
static int stm32_hash_cra_init(struct crypto_tfm *tfm)
{
- return stm32_hash_cra_init_algs(tfm, NULL);
+ return stm32_hash_cra_init_algs(tfm, 0);
}
-static int stm32_hash_cra_md5_init(struct crypto_tfm *tfm)
+static int stm32_hash_cra_hmac_init(struct crypto_tfm *tfm)
{
- return stm32_hash_cra_init_algs(tfm, "md5");
+ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_HMAC);
}
-static int stm32_hash_cra_sha1_init(struct crypto_tfm *tfm)
+static int stm32_hash_cra_sha3_init(struct crypto_tfm *tfm)
{
- return stm32_hash_cra_init_algs(tfm, "sha1");
+ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_SHA3_MODE);
}
-static int stm32_hash_cra_sha224_init(struct crypto_tfm *tfm)
+static int stm32_hash_cra_sha3_hmac_init(struct crypto_tfm *tfm)
{
- return stm32_hash_cra_init_algs(tfm, "sha224");
+ return stm32_hash_cra_init_algs(tfm, HASH_FLAGS_SHA3_MODE |
+ HASH_FLAGS_HMAC);
}
-static int stm32_hash_cra_sha256_init(struct crypto_tfm *tfm)
-{
- return stm32_hash_cra_init_algs(tfm, "sha256");
-}
static void stm32_hash_cra_exit(struct crypto_tfm *tfm)
{
@@ -1162,11 +1233,9 @@ static irqreturn_t stm32_hash_irq_thread(int irq, void *dev_id)
hdev->flags &= ~HASH_FLAGS_OUTPUT_READY;
goto finish;
}
- } else if (HASH_FLAGS_DMA_READY & hdev->flags) {
- if (HASH_FLAGS_DMA_ACTIVE & hdev->flags) {
- hdev->flags &= ~HASH_FLAGS_DMA_ACTIVE;
- goto finish;
- }
+ } else if (HASH_FLAGS_DMA_ACTIVE & hdev->flags) {
+ hdev->flags &= ~HASH_FLAGS_DMA_ACTIVE;
+ goto finish;
}
return IRQ_HANDLED;
@@ -1185,8 +1254,6 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id)
reg = stm32_hash_read(hdev, HASH_SR);
if (reg & HASH_SR_OUTPUT_READY) {
- reg &= ~HASH_SR_OUTPUT_READY;
- stm32_hash_write(hdev, HASH_SR, reg);
hdev->flags |= HASH_FLAGS_OUTPUT_READY;
/* Disable IT*/
stm32_hash_write(hdev, HASH_IMR, 0);
@@ -1196,16 +1263,16 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
-static struct ahash_alg algs_md5[] = {
+static struct ahash_engine_alg algs_md5[] = {
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
.digestsize = MD5_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1221,18 +1288,21 @@ static struct ahash_alg algs_md5[] = {
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .setkey = stm32_hash_setkey,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
.digestsize = MD5_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1244,24 +1314,27 @@ static struct ahash_alg algs_md5[] = {
.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct stm32_hash_ctx),
.cra_alignmask = 3,
- .cra_init = stm32_hash_cra_md5_init,
+ .cra_init = stm32_hash_cra_hmac_init,
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
- },
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ }
};
-static struct ahash_alg algs_sha1[] = {
+static struct ahash_engine_alg algs_sha1[] = {
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1277,18 +1350,21 @@ static struct ahash_alg algs_sha1[] = {
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .setkey = stm32_hash_setkey,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1300,24 +1376,27 @@ static struct ahash_alg algs_sha1[] = {
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct stm32_hash_ctx),
.cra_alignmask = 3,
- .cra_init = stm32_hash_cra_sha1_init,
+ .cra_init = stm32_hash_cra_hmac_init,
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
};
-static struct ahash_alg algs_sha224[] = {
+static struct ahash_engine_alg algs_sha224[] = {
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1333,18 +1412,21 @@ static struct ahash_alg algs_sha224[] = {
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .setkey = stm32_hash_setkey,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.setkey = stm32_hash_setkey,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
.digestsize = SHA224_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1356,24 +1438,27 @@ static struct ahash_alg algs_sha224[] = {
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct stm32_hash_ctx),
.cra_alignmask = 3,
- .cra_init = stm32_hash_cra_sha224_init,
+ .cra_init = stm32_hash_cra_hmac_init,
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
};
-static struct ahash_alg algs_sha256[] = {
+static struct ahash_engine_alg algs_sha256[] = {
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1389,18 +1474,21 @@ static struct ahash_alg algs_sha256[] = {
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
{
- .init = stm32_hash_init,
- .update = stm32_hash_update,
- .final = stm32_hash_final,
- .finup = stm32_hash_finup,
- .digest = stm32_hash_digest,
- .export = stm32_hash_export,
- .import = stm32_hash_import,
- .setkey = stm32_hash_setkey,
- .halg = {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.statesize = sizeof(struct stm32_hash_state),
.base = {
@@ -1412,14 +1500,377 @@ static struct ahash_alg algs_sha256[] = {
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct stm32_hash_ctx),
.cra_alignmask = 3,
- .cra_init = stm32_hash_cra_sha256_init,
+ .cra_init = stm32_hash_cra_hmac_init,
.cra_exit = stm32_hash_cra_exit,
.cra_module = THIS_MODULE,
}
- }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
},
};
+static struct ahash_engine_alg algs_sha384_sha512[] = {
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "stm32-sha384",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.setkey = stm32_hash_setkey,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha384)",
+ .cra_driver_name = "stm32-hmac-sha384",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "stm32-sha512",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha512)",
+ .cra_driver_name = "stm32-hmac-sha512",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+};
+
+static struct ahash_engine_alg algs_sha3[] = {
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA3_224_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha3-224",
+ .cra_driver_name = "stm32-sha3-224",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
+ .digestsize = SHA3_224_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha3-224)",
+ .cra_driver_name = "stm32-hmac-sha3-224",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA3_256_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha3-256",
+ .cra_driver_name = "stm32-sha3-256",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
+ .digestsize = SHA3_256_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha3-256)",
+ .cra_driver_name = "stm32-hmac-sha3-256",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA3_384_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha3-384",
+ .cra_driver_name = "stm32-sha3-384",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
+ .digestsize = SHA3_384_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha3-384)",
+ .cra_driver_name = "stm32-hmac-sha3-384",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_384_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.halg = {
+ .digestsize = SHA3_512_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "sha3-512",
+ .cra_driver_name = "stm32-sha3-512",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ },
+ {
+ .base.init = stm32_hash_init,
+ .base.update = stm32_hash_update,
+ .base.final = stm32_hash_final,
+ .base.finup = stm32_hash_finup,
+ .base.digest = stm32_hash_digest,
+ .base.export = stm32_hash_export,
+ .base.import = stm32_hash_import,
+ .base.setkey = stm32_hash_setkey,
+ .base.halg = {
+ .digestsize = SHA3_512_DIGEST_SIZE,
+ .statesize = sizeof(struct stm32_hash_state),
+ .base = {
+ .cra_name = "hmac(sha3-512)",
+ .cra_driver_name = "stm32-hmac-sha3-512",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA3_512_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct stm32_hash_ctx),
+ .cra_alignmask = 3,
+ .cra_init = stm32_hash_cra_sha3_hmac_init,
+ .cra_exit = stm32_hash_cra_exit,
+ .cra_module = THIS_MODULE,
+ }
+ },
+ .op = {
+ .do_one_request = stm32_hash_one_request,
+ },
+ }
+};
+
static int stm32_hash_register_algs(struct stm32_hash_dev *hdev)
{
unsigned int i, j;
@@ -1427,7 +1878,7 @@ static int stm32_hash_register_algs(struct stm32_hash_dev *hdev)
for (i = 0; i < hdev->pdata->algs_info_size; i++) {
for (j = 0; j < hdev->pdata->algs_info[i].size; j++) {
- err = crypto_register_ahash(
+ err = crypto_engine_register_ahash(
&hdev->pdata->algs_info[i].algs_list[j]);
if (err)
goto err_algs;
@@ -1439,7 +1890,7 @@ err_algs:
dev_err(hdev->dev, "Algo %d : %d failed\n", i, j);
for (; i--; ) {
for (; j--;)
- crypto_unregister_ahash(
+ crypto_engine_unregister_ahash(
&hdev->pdata->algs_info[i].algs_list[j]);
}
@@ -1452,7 +1903,7 @@ static int stm32_hash_unregister_algs(struct stm32_hash_dev *hdev)
for (i = 0; i < hdev->pdata->algs_info_size; i++) {
for (j = 0; j < hdev->pdata->algs_info[i].size; j++)
- crypto_unregister_ahash(
+ crypto_engine_unregister_ahash(
&hdev->pdata->algs_info[i].algs_list[j]);
}
@@ -1471,6 +1922,7 @@ static struct stm32_hash_algs_info stm32_hash_algs_info_ux500[] = {
};
static const struct stm32_hash_pdata stm32_hash_pdata_ux500 = {
+ .alg_shift = 7,
.algs_info = stm32_hash_algs_info_ux500,
.algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_ux500),
.broken_emptymsg = true,
@@ -1489,6 +1941,7 @@ static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f4[] = {
};
static const struct stm32_hash_pdata stm32_hash_pdata_stm32f4 = {
+ .alg_shift = 7,
.algs_info = stm32_hash_algs_info_stm32f4,
.algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32f4),
.has_sr = true,
@@ -1515,25 +1968,49 @@ static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f7[] = {
};
static const struct stm32_hash_pdata stm32_hash_pdata_stm32f7 = {
+ .alg_shift = 7,
.algs_info = stm32_hash_algs_info_stm32f7,
.algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32f7),
.has_sr = true,
.has_mdmat = true,
};
-static const struct of_device_id stm32_hash_of_match[] = {
+static struct stm32_hash_algs_info stm32_hash_algs_info_stm32mp13[] = {
{
- .compatible = "stericsson,ux500-hash",
- .data = &stm32_hash_pdata_ux500,
+ .algs_list = algs_sha1,
+ .size = ARRAY_SIZE(algs_sha1),
+ },
+ {
+ .algs_list = algs_sha224,
+ .size = ARRAY_SIZE(algs_sha224),
+ },
+ {
+ .algs_list = algs_sha256,
+ .size = ARRAY_SIZE(algs_sha256),
},
{
- .compatible = "st,stm32f456-hash",
- .data = &stm32_hash_pdata_stm32f4,
+ .algs_list = algs_sha384_sha512,
+ .size = ARRAY_SIZE(algs_sha384_sha512),
},
{
- .compatible = "st,stm32f756-hash",
- .data = &stm32_hash_pdata_stm32f7,
+ .algs_list = algs_sha3,
+ .size = ARRAY_SIZE(algs_sha3),
},
+};
+
+static const struct stm32_hash_pdata stm32_hash_pdata_stm32mp13 = {
+ .alg_shift = 17,
+ .algs_info = stm32_hash_algs_info_stm32mp13,
+ .algs_info_size = ARRAY_SIZE(stm32_hash_algs_info_stm32mp13),
+ .has_sr = true,
+ .has_mdmat = true,
+};
+
+static const struct of_device_id stm32_hash_of_match[] = {
+ { .compatible = "stericsson,ux500-hash", .data = &stm32_hash_pdata_ux500 },
+ { .compatible = "st,stm32f456-hash", .data = &stm32_hash_pdata_stm32f4 },
+ { .compatible = "st,stm32f756-hash", .data = &stm32_hash_pdata_stm32f7 },
+ { .compatible = "st,stm32mp13-hash", .data = &stm32_hash_pdata_stm32mp13 },
{},
};
@@ -1548,12 +2025,6 @@ static int stm32_hash_get_of_match(struct stm32_hash_dev *hdev,
return -EINVAL;
}
- if (of_property_read_u32(dev->of_node, "dma-maxburst",
- &hdev->dma_maxburst)) {
- dev_info(dev, "dma-maxburst not specified, using 0\n");
- hdev->dma_maxburst = 0;
- }
-
return 0;
}
@@ -1663,7 +2134,7 @@ static int stm32_hash_probe(struct platform_device *pdev)
/* FIXME: implement DMA mode for Ux500 */
hdev->dma_mode = 0;
else
- hdev->dma_mode = stm32_hash_read(hdev, HASH_HWCFGR);
+ hdev->dma_mode = stm32_hash_read(hdev, HASH_HWCFGR) & HASH_HWCFG_DMA_MASK;
/* Register algos */
ret = stm32_hash_register_algs(hdev);
@@ -1696,18 +2167,12 @@ err_reset:
return ret;
}
-static int stm32_hash_remove(struct platform_device *pdev)
+static void stm32_hash_remove(struct platform_device *pdev)
{
- struct stm32_hash_dev *hdev;
+ struct stm32_hash_dev *hdev = platform_get_drvdata(pdev);
int ret;
- hdev = platform_get_drvdata(pdev);
- if (!hdev)
- return -ENODEV;
-
- ret = pm_runtime_resume_and_get(hdev->dev);
- if (ret < 0)
- return ret;
+ ret = pm_runtime_get_sync(hdev->dev);
stm32_hash_unregister_algs(hdev);
@@ -1723,9 +2188,8 @@ static int stm32_hash_remove(struct platform_device *pdev)
pm_runtime_disable(hdev->dev);
pm_runtime_put_noidle(hdev->dev);
- clk_disable_unprepare(hdev->clk);
-
- return 0;
+ if (ret >= 0)
+ clk_disable_unprepare(hdev->clk);
}
#ifdef CONFIG_PM
@@ -1762,7 +2226,7 @@ static const struct dev_pm_ops stm32_hash_pm_ops = {
static struct platform_driver stm32_hash_driver = {
.probe = stm32_hash_probe,
- .remove = stm32_hash_remove,
+ .remove_new = stm32_hash_remove,
.driver = {
.name = "stm32-hash",
.pm = &stm32_hash_pm_ops,
@@ -1772,6 +2236,6 @@ static struct platform_driver stm32_hash_driver = {
module_platform_driver(stm32_hash_driver);
-MODULE_DESCRIPTION("STM32 SHA1/224/256 & MD5 (HMAC) hw accelerator driver");
+MODULE_DESCRIPTION("STM32 SHA1/SHA2/SHA3 & MD5 (HMAC) hw accelerator driver");
MODULE_AUTHOR("Lionel Debieve <lionel.debieve@st.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index bb27f011cf31..4ca4fbd227bc 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -19,9 +19,9 @@
#include <linux/interrupt.h>
#include <linux/crypto.h>
#include <linux/hw_random.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/spinlock.h>
diff --git a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c
index 6963344f6a3a..2621ff8a9376 100644
--- a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c
@@ -7,15 +7,16 @@
* Copyright 2022 Bytedance CO., LTD.
*/
-#include <linux/mpi.h>
-#include <linux/scatterlist.h>
-#include <crypto/algapi.h>
+#include <crypto/engine.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/rsa.h>
-#include <linux/err.h>
#include <crypto/scatterwalk.h>
-#include <linux/atomic.h>
-
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mpi.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include <uapi/linux/virtio_crypto.h>
#include "virtio_crypto_common.h"
@@ -24,7 +25,6 @@ struct virtio_crypto_rsa_ctx {
};
struct virtio_crypto_akcipher_ctx {
- struct crypto_engine_ctx enginectx;
struct virtio_crypto *vcrypto;
struct crypto_akcipher *tfm;
bool session_valid;
@@ -47,7 +47,7 @@ struct virtio_crypto_akcipher_algo {
uint32_t algonum;
uint32_t service;
unsigned int active_devs;
- struct akcipher_alg algo;
+ struct akcipher_engine_alg algo;
};
static DEFINE_MUTEX(algs_lock);
@@ -475,9 +475,6 @@ static int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm)
struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
ctx->tfm = tfm;
- ctx->enginectx.op.do_one_request = virtio_crypto_rsa_do_req;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
akcipher_set_reqsize(tfm,
sizeof(struct virtio_crypto_akcipher_request));
@@ -500,7 +497,7 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = {
{
.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
- .algo = {
+ .algo.base = {
.encrypt = virtio_crypto_rsa_encrypt,
.decrypt = virtio_crypto_rsa_decrypt,
.set_pub_key = virtio_crypto_rsa_raw_set_pub_key,
@@ -516,11 +513,14 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = {
.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
},
},
+ .algo.op = {
+ .do_one_request = virtio_crypto_rsa_do_req,
+ },
},
{
.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
- .algo = {
+ .algo.base = {
.encrypt = virtio_crypto_rsa_encrypt,
.decrypt = virtio_crypto_rsa_decrypt,
.sign = virtio_crypto_rsa_sign,
@@ -538,6 +538,9 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = {
.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
},
},
+ .algo.op = {
+ .do_one_request = virtio_crypto_rsa_do_req,
+ },
},
};
@@ -556,14 +559,14 @@ int virtio_crypto_akcipher_algs_register(struct virtio_crypto *vcrypto)
continue;
if (virtio_crypto_akcipher_algs[i].active_devs == 0) {
- ret = crypto_register_akcipher(&virtio_crypto_akcipher_algs[i].algo);
+ ret = crypto_engine_register_akcipher(&virtio_crypto_akcipher_algs[i].algo);
if (ret)
goto unlock;
}
virtio_crypto_akcipher_algs[i].active_devs++;
dev_info(&vcrypto->vdev->dev, "Registered akcipher algo %s\n",
- virtio_crypto_akcipher_algs[i].algo.base.cra_name);
+ virtio_crypto_akcipher_algs[i].algo.base.base.cra_name);
}
unlock:
@@ -586,7 +589,7 @@ void virtio_crypto_akcipher_algs_unregister(struct virtio_crypto *vcrypto)
continue;
if (virtio_crypto_akcipher_algs[i].active_devs == 1)
- crypto_unregister_akcipher(&virtio_crypto_akcipher_algs[i].algo);
+ crypto_engine_unregister_akcipher(&virtio_crypto_akcipher_algs[i].algo);
virtio_crypto_akcipher_algs[i].active_devs--;
}
diff --git a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c
index e5876286828b..23c41d87d835 100644
--- a/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_skcipher_algs.c
@@ -6,19 +6,16 @@
* Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
*/
-#include <linux/scatterlist.h>
-#include <crypto/algapi.h>
+#include <crypto/engine.h>
#include <crypto/internal/skcipher.h>
-#include <linux/err.h>
#include <crypto/scatterwalk.h>
-#include <linux/atomic.h>
-
+#include <linux/err.h>
+#include <linux/scatterlist.h>
#include <uapi/linux/virtio_crypto.h>
#include "virtio_crypto_common.h"
struct virtio_crypto_skcipher_ctx {
- struct crypto_engine_ctx enginectx;
struct virtio_crypto *vcrypto;
struct crypto_skcipher *tfm;
@@ -42,7 +39,7 @@ struct virtio_crypto_algo {
uint32_t algonum;
uint32_t service;
unsigned int active_devs;
- struct skcipher_alg algo;
+ struct skcipher_engine_alg algo;
};
/*
@@ -523,9 +520,6 @@ static int virtio_crypto_skcipher_init(struct crypto_skcipher *tfm)
crypto_skcipher_set_reqsize(tfm, sizeof(struct virtio_crypto_sym_request));
ctx->tfm = tfm;
- ctx->enginectx.op.do_one_request = virtio_crypto_skcipher_crypt_req;
- ctx->enginectx.op.prepare_request = NULL;
- ctx->enginectx.op.unprepare_request = NULL;
return 0;
}
@@ -580,7 +574,7 @@ static void virtio_crypto_skcipher_finalize_req(
static struct virtio_crypto_algo virtio_crypto_algs[] = { {
.algonum = VIRTIO_CRYPTO_CIPHER_AES_CBC,
.service = VIRTIO_CRYPTO_SERVICE_CIPHER,
- .algo = {
+ .algo.base = {
.base.cra_name = "cbc(aes)",
.base.cra_driver_name = "virtio_crypto_aes_cbc",
.base.cra_priority = 150,
@@ -598,6 +592,9 @@ static struct virtio_crypto_algo virtio_crypto_algs[] = { {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
},
+ .algo.op = {
+ .do_one_request = virtio_crypto_skcipher_crypt_req,
+ },
} };
int virtio_crypto_skcipher_algs_register(struct virtio_crypto *vcrypto)
@@ -616,14 +613,14 @@ int virtio_crypto_skcipher_algs_register(struct virtio_crypto *vcrypto)
continue;
if (virtio_crypto_algs[i].active_devs == 0) {
- ret = crypto_register_skcipher(&virtio_crypto_algs[i].algo);
+ ret = crypto_engine_register_skcipher(&virtio_crypto_algs[i].algo);
if (ret)
goto unlock;
}
virtio_crypto_algs[i].active_devs++;
dev_info(&vcrypto->vdev->dev, "Registered algo %s\n",
- virtio_crypto_algs[i].algo.base.cra_name);
+ virtio_crypto_algs[i].algo.base.base.cra_name);
}
unlock:
@@ -647,7 +644,7 @@ void virtio_crypto_skcipher_algs_unregister(struct virtio_crypto *vcrypto)
continue;
if (virtio_crypto_algs[i].active_devs == 1)
- crypto_unregister_skcipher(&virtio_crypto_algs[i].algo);
+ crypto_engine_unregister_skcipher(&virtio_crypto_algs[i].algo);
virtio_crypto_algs[i].active_devs--;
}
diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
index bf1f421e05f2..ce335578b759 100644
--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c
+++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c
@@ -9,13 +9,14 @@
#include <crypto/gcm.h>
#include <crypto/internal/aead.h>
#include <crypto/scatterwalk.h>
-
#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
-
-#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/string.h>
#define ZYNQMP_DMA_BIT_MASK 32U
@@ -43,7 +44,7 @@ enum zynqmp_aead_keysrc {
struct zynqmp_aead_drv_ctx {
union {
- struct aead_alg aead;
+ struct aead_engine_alg aead;
} alg;
struct device *dev;
struct crypto_engine *engine;
@@ -60,7 +61,6 @@ struct zynqmp_aead_hw_req {
};
struct zynqmp_aead_tfm_ctx {
- struct crypto_engine_ctx engine_ctx;
struct device *dev;
u8 key[ZYNQMP_AES_KEY_SIZE];
u8 *iv;
@@ -286,7 +286,7 @@ static int zynqmp_aes_aead_encrypt(struct aead_request *req)
struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
rq_ctx->op = ZYNQMP_AES_ENCRYPT;
- drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
+ drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
}
@@ -299,7 +299,7 @@ static int zynqmp_aes_aead_decrypt(struct aead_request *req)
struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
rq_ctx->op = ZYNQMP_AES_DECRYPT;
- drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
+ drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
}
@@ -312,20 +312,16 @@ static int zynqmp_aes_aead_init(struct crypto_aead *aead)
struct zynqmp_aead_drv_ctx *drv_ctx;
struct aead_alg *alg = crypto_aead_alg(aead);
- drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
+ drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead.base);
tfm_ctx->dev = drv_ctx->dev;
- tfm_ctx->engine_ctx.op.do_one_request = zynqmp_handle_aes_req;
- tfm_ctx->engine_ctx.op.prepare_request = NULL;
- tfm_ctx->engine_ctx.op.unprepare_request = NULL;
-
- tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->alg.aead.base.cra_name,
+ tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->alg.aead.base.base.cra_name,
0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(tfm_ctx->fbk_cipher)) {
pr_err("%s() Error: failed to allocate fallback for %s\n",
- __func__, drv_ctx->alg.aead.base.cra_name);
+ __func__, drv_ctx->alg.aead.base.base.cra_name);
return PTR_ERR(tfm_ctx->fbk_cipher);
}
@@ -350,7 +346,7 @@ static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
}
static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
- .alg.aead = {
+ .alg.aead.base = {
.setkey = zynqmp_aes_aead_setkey,
.setauthsize = zynqmp_aes_aead_setauthsize,
.encrypt = zynqmp_aes_aead_encrypt,
@@ -372,7 +368,10 @@ static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
.cra_ctxsize = sizeof(struct zynqmp_aead_tfm_ctx),
.cra_module = THIS_MODULE,
}
- }
+ },
+ .alg.aead.op = {
+ .do_one_request = zynqmp_handle_aes_req,
+ },
};
static int zynqmp_aes_aead_probe(struct platform_device *pdev)
@@ -405,7 +404,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
goto err_engine;
}
- err = crypto_register_aead(&aes_drv_ctx.alg.aead);
+ err = crypto_engine_register_aead(&aes_drv_ctx.alg.aead);
if (err < 0) {
dev_err(dev, "Failed to register AEAD alg.\n");
goto err_aead;
@@ -413,7 +412,7 @@ static int zynqmp_aes_aead_probe(struct platform_device *pdev)
return 0;
err_aead:
- crypto_unregister_aead(&aes_drv_ctx.alg.aead);
+ crypto_engine_unregister_aead(&aes_drv_ctx.alg.aead);
err_engine:
if (aes_drv_ctx.engine)
@@ -425,7 +424,7 @@ err_engine:
static int zynqmp_aes_aead_remove(struct platform_device *pdev)
{
crypto_engine_exit(aes_drv_ctx.engine);
- crypto_unregister_aead(&aes_drv_ctx.alg.aead);
+ crypto_engine_unregister_aead(&aes_drv_ctx.alg.aead);
return 0;
}
diff --git a/drivers/crypto/xilinx/zynqmp-sha.c b/drivers/crypto/xilinx/zynqmp-sha.c
index 43ff170ff1c2..426bf1a72ba6 100644
--- a/drivers/crypto/xilinx/zynqmp-sha.c
+++ b/drivers/crypto/xilinx/zynqmp-sha.c
@@ -15,7 +15,6 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#define ZYNQMP_DMA_BIT_MASK 32U
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 30665a3ff6ea..93ebedc5ec8c 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -228,32 +228,26 @@ static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
}
#endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
-static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf,
- enum page_entry_size pe_size)
+static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf, unsigned int order)
{
struct file *filp = vmf->vma->vm_file;
vm_fault_t rc = VM_FAULT_SIGBUS;
int id;
struct dev_dax *dev_dax = filp->private_data;
- dev_dbg(&dev_dax->dev, "%s: %s (%#lx - %#lx) size = %d\n", current->comm,
+ dev_dbg(&dev_dax->dev, "%s: %s (%#lx - %#lx) order:%d\n", current->comm,
(vmf->flags & FAULT_FLAG_WRITE) ? "write" : "read",
- vmf->vma->vm_start, vmf->vma->vm_end, pe_size);
+ vmf->vma->vm_start, vmf->vma->vm_end, order);
id = dax_read_lock();
- switch (pe_size) {
- case PE_SIZE_PTE:
+ if (order == 0)
rc = __dev_dax_pte_fault(dev_dax, vmf);
- break;
- case PE_SIZE_PMD:
+ else if (order == PMD_ORDER)
rc = __dev_dax_pmd_fault(dev_dax, vmf);
- break;
- case PE_SIZE_PUD:
+ else if (order == PUD_ORDER)
rc = __dev_dax_pud_fault(dev_dax, vmf);
- break;
- default:
+ else
rc = VM_FAULT_SIGBUS;
- }
dax_read_unlock(id);
@@ -262,7 +256,7 @@ static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf,
static vm_fault_t dev_dax_fault(struct vm_fault *vmf)
{
- return dev_dax_huge_fault(vmf, PE_SIZE_PTE);
+ return dev_dax_huge_fault(vmf, 0);
}
static int dev_dax_may_split(struct vm_area_struct *vma, unsigned long addr)
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index 898ca9505754..c57acb73e3db 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -264,7 +264,7 @@ static int __init dax_kmem_init(void)
return rc;
error_dax_driver:
- destroy_memory_type(dax_slowmem_type);
+ put_memory_type(dax_slowmem_type);
err_dax_slowmem_type:
kfree_const(kmem_name);
return rc;
@@ -275,7 +275,7 @@ static void __exit dax_kmem_exit(void)
dax_driver_unregister(&device_dax_kmem_driver);
if (!any_hotremove_failed)
kfree_const(kmem_name);
- destroy_memory_type(dax_slowmem_type);
+ put_memory_type(dax_slowmem_type);
}
MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index e36cbb920ec8..474d81831ad3 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -472,10 +472,11 @@ static void devfreq_monitor(struct work_struct *work)
* devfreq_monitor_start() - Start load monitoring of devfreq instance
* @devfreq: the devfreq instance.
*
- * Helper function for starting devfreq device load monitoring. By
- * default delayed work based monitoring is supported. Function
- * to be called from governor in response to DEVFREQ_GOV_START
- * event when device is added to devfreq framework.
+ * Helper function for starting devfreq device load monitoring. By default,
+ * deferrable timer is used for load monitoring. But the users can change this
+ * behavior using the "timer" type in devfreq_dev_profile. This function will be
+ * called by devfreq governor in response to the DEVFREQ_GOV_START event
+ * generated while adding a device to the devfreq framework.
*/
void devfreq_monitor_start(struct devfreq *devfreq)
{
@@ -763,6 +764,7 @@ static void devfreq_dev_release(struct device *dev)
dev_pm_opp_put_opp_table(devfreq->opp_table);
mutex_destroy(&devfreq->lock);
+ srcu_cleanup_notifier_head(&devfreq->transition_notifier_list);
kfree(devfreq);
}
diff --git a/drivers/devfreq/imx-bus.c b/drivers/devfreq/imx-bus.c
index a727067980fb..86850b7dea09 100644
--- a/drivers/devfreq/imx-bus.c
+++ b/drivers/devfreq/imx-bus.c
@@ -7,7 +7,7 @@
#include <linux/devfreq.h>
#include <linux/device.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
diff --git a/drivers/devfreq/imx8m-ddrc.c b/drivers/devfreq/imx8m-ddrc.c
index 16636973eb10..e1348490c8aa 100644
--- a/drivers/devfreq/imx8m-ddrc.c
+++ b/drivers/devfreq/imx8m-ddrc.c
@@ -3,9 +3,9 @@
* Copyright 2019 NXP
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/devfreq.h>
#include <linux/pm_opp.h>
diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c
index 6354622eda65..83a73f0ccd80 100644
--- a/drivers/devfreq/mtk-cci-devfreq.c
+++ b/drivers/devfreq/mtk-cci-devfreq.c
@@ -8,7 +8,6 @@
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c
index 503376b894b6..4a4f0106ab9d 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/reset.h>
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 63f0aeb66db6..f0a35277fd84 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -191,6 +191,7 @@ static const struct dma_fence_ops timeline_fence_ops = {
*/
static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
{
+ LIST_HEAD(signalled);
struct sync_pt *pt, *next;
trace_sync_timeline(obj);
@@ -203,21 +204,20 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
if (!timeline_fence_signaled(&pt->base))
break;
- list_del_init(&pt->link);
+ dma_fence_get(&pt->base);
+
+ list_move_tail(&pt->link, &signalled);
rb_erase(&pt->node, &obj->pt_tree);
- /*
- * A signal callback may release the last reference to this
- * fence, causing it to be freed. That operation has to be
- * last to avoid a use after free inside this loop, and must
- * be after we remove the fence from the timeline in order to
- * prevent deadlocking on timeline->lock inside
- * timeline_fence_release().
- */
dma_fence_signal_locked(&pt->base);
}
spin_unlock_irq(&obj->lock);
+
+ list_for_each_entry_safe(pt, next, &signalled, link) {
+ list_del_init(&pt->link);
+ dma_fence_put(&pt->base);
+ }
}
/**
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 597dae7692b1..9b6642d00871 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -4150,6 +4150,20 @@ static int per_family_init(struct amd64_pvt *pvt)
}
break;
+ case 0x1A:
+ switch (pvt->model) {
+ case 0x00 ... 0x1f:
+ pvt->ctl_name = "F1Ah";
+ pvt->max_mcs = 12;
+ pvt->flags.zn_regs_v2 = 1;
+ break;
+ case 0x40 ... 0x4f:
+ pvt->ctl_name = "F1Ah_M40h";
+ pvt->flags.zn_regs_v2 = 1;
+ break;
+ }
+ break;
+
default:
amd64_err("Unsupported family!\n");
return -ENODEV;
@@ -4344,6 +4358,7 @@ static const struct x86_cpu_id amd64_cpuids[] = {
X86_MATCH_VENDOR_FAM(AMD, 0x17, NULL),
X86_MATCH_VENDOR_FAM(HYGON, 0x18, NULL),
X86_MATCH_VENDOR_FAM(AMD, 0x19, NULL),
+ X86_MATCH_VENDOR_FAM(AMD, 0x1A, NULL),
{ }
};
MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index a897b6aff368..5abf997ca7c1 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -906,7 +906,7 @@ static const struct x86_cpu_id i10nm_cpuids[] = {
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SAPPHIRERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(EMERALDRAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg),
X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(GRANITERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
- X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SIERRAFOREST_X, X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
+ X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_CRESTMONT_X, X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
{}
};
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 713582cc27d1..33f0ba11c6ad 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -60,7 +60,7 @@ static void __init eisa_name_device(struct eisa_device *edev)
int i;
for (i = 0; i < EISA_INFOS; i++) {
if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) {
- strlcpy(edev->pretty_name,
+ strscpy(edev->pretty_name,
eisa_table[i].name,
sizeof(edev->pretty_name));
return;
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index f9040bd61081..285fe7ad490d 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -1095,3 +1095,22 @@ int sdei_event_handler(struct pt_regs *regs,
return err;
}
NOKPROBE_SYMBOL(sdei_event_handler);
+
+void sdei_handler_abort(void)
+{
+ /*
+ * If the crash happened in an SDEI event handler then we need to
+ * finish the handler with the firmware so that we can have working
+ * interrupts in the crash kernel.
+ */
+ if (__this_cpu_read(sdei_active_critical_event)) {
+ pr_warn("still in SDEI critical event context, attempting to finish handler.\n");
+ __sdei_handler_abort();
+ __this_cpu_write(sdei_active_critical_event, NULL);
+ }
+ if (__this_cpu_read(sdei_active_normal_event)) {
+ pr_warn("still in SDEI normal event context, attempting to finish handler.\n");
+ __sdei_handler_abort();
+ __this_cpu_write(sdei_active_normal_event, NULL);
+ }
+}
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 16d64a34d1e1..92389a5481ff 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -88,6 +88,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64.o arm64-stub.o smbios.o
lib-$(CONFIG_X86) += x86-stub.o
+lib-$(CONFIG_X86_64) += x86-5lvl.o
lib-$(CONFIG_RISCV) += riscv.o riscv-stub.o
lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
@@ -146,7 +147,7 @@ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS
# For RISC-V, we don't need anything special other than arm64. Keep all the
# symbols in .init section and make sure that no absolute symbols references
-# doesn't exist.
+# exist.
STUBCOPY_FLAGS-$(CONFIG_RISCV) += --prefix-alloc-sections=.init \
--prefix-symbols=__efistub_
STUBCOPY_RELOC-$(CONFIG_RISCV) := R_RISCV_HI20
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 770b8ecb7398..8c40fc89f5f9 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -106,7 +106,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
*/
status = efi_random_alloc(*reserve_size, min_kimg_align,
reserve_addr, phys_seed,
- EFI_LOADER_CODE);
+ EFI_LOADER_CODE, EFI_ALLOC_LIMIT);
if (status != EFI_SUCCESS)
efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
} else {
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 732984295295..bfa30625f5d0 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -73,6 +73,8 @@ efi_status_t efi_parse_options(char const *cmdline)
efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
} else if (!strcmp(param, "noinitrd")) {
efi_noinitrd = true;
+ } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
+ efi_no5lvl = true;
} else if (!strcmp(param, "efi") && val) {
efi_nochunk = parse_option_str(val, "nochunk");
efi_novamap |= parse_option_str(val, "novamap");
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 6aa38a1bf126..9823f6fb3e01 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -33,6 +33,7 @@
#define EFI_ALLOC_LIMIT ULONG_MAX
#endif
+extern bool efi_no5lvl;
extern bool efi_nochunk;
extern bool efi_nokaslr;
extern int efi_loglevel;
@@ -955,7 +956,7 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);
efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long random_seed,
- int memory_type);
+ int memory_type, unsigned long alloc_limit);
efi_status_t efi_random_get_seed(void);
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
index 32c7a54923b4..674a064b8f7a 100644
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -16,7 +16,8 @@
*/
static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
unsigned long size,
- unsigned long align_shift)
+ unsigned long align_shift,
+ u64 alloc_limit)
{
unsigned long align = 1UL << align_shift;
u64 first_slot, last_slot, region_end;
@@ -29,7 +30,7 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
return 0;
region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
- (u64)EFI_ALLOC_LIMIT);
+ alloc_limit);
if (region_end < size)
return 0;
@@ -54,7 +55,8 @@ efi_status_t efi_random_alloc(unsigned long size,
unsigned long align,
unsigned long *addr,
unsigned long random_seed,
- int memory_type)
+ int memory_type,
+ unsigned long alloc_limit)
{
unsigned long total_slots = 0, target_slot;
unsigned long total_mirrored_slots = 0;
@@ -76,7 +78,7 @@ efi_status_t efi_random_alloc(unsigned long size,
efi_memory_desc_t *md = (void *)map->map + map_offset;
unsigned long slots;
- slots = get_entry_num_slots(md, size, ilog2(align));
+ slots = get_entry_num_slots(md, size, ilog2(align), alloc_limit);
MD_NUM_SLOTS(md) = slots;
total_slots += slots;
if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
diff --git a/drivers/firmware/efi/libstub/x86-5lvl.c b/drivers/firmware/efi/libstub/x86-5lvl.c
new file mode 100644
index 000000000000..479dd445acdc
--- /dev/null
+++ b/drivers/firmware/efi/libstub/x86-5lvl.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/efi.h>
+
+#include <asm/boot.h>
+#include <asm/desc.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+#include "x86-stub.h"
+
+bool efi_no5lvl;
+
+static void (*la57_toggle)(void *cr3);
+
+static const struct desc_struct gdt[] = {
+ [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff),
+ [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff),
+};
+
+/*
+ * Enabling (or disabling) 5 level paging is tricky, because it can only be
+ * done from 32-bit mode with paging disabled. This means not only that the
+ * code itself must be running from 32-bit addressable physical memory, but
+ * also that the root page table must be 32-bit addressable, as programming
+ * a 64-bit value into CR3 when running in 32-bit mode is not supported.
+ */
+efi_status_t efi_setup_5level_paging(void)
+{
+ u8 tmpl_size = (u8 *)&trampoline_ljmp_imm_offset - (u8 *)&trampoline_32bit_src;
+ efi_status_t status;
+ u8 *la57_code;
+
+ if (!efi_is_64bit())
+ return EFI_SUCCESS;
+
+ /* check for 5 level paging support */
+ if (native_cpuid_eax(0) < 7 ||
+ !(native_cpuid_ecx(7) & (1 << (X86_FEATURE_LA57 & 31))))
+ return EFI_SUCCESS;
+
+ /* allocate some 32-bit addressable memory for code and a page table */
+ status = efi_allocate_pages(2 * PAGE_SIZE, (unsigned long *)&la57_code,
+ U32_MAX);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ la57_toggle = memcpy(la57_code, trampoline_32bit_src, tmpl_size);
+ memset(la57_code + tmpl_size, 0x90, PAGE_SIZE - tmpl_size);
+
+ /*
+ * To avoid the need to allocate a 32-bit addressable stack, the
+ * trampoline uses a LJMP instruction to switch back to long mode.
+ * LJMP takes an absolute destination address, which needs to be
+ * fixed up at runtime.
+ */
+ *(u32 *)&la57_code[trampoline_ljmp_imm_offset] += (unsigned long)la57_code;
+
+ efi_adjust_memory_range_protection((unsigned long)la57_toggle, PAGE_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+void efi_5level_switch(void)
+{
+ bool want_la57 = IS_ENABLED(CONFIG_X86_5LEVEL) && !efi_no5lvl;
+ bool have_la57 = native_read_cr4() & X86_CR4_LA57;
+ bool need_toggle = want_la57 ^ have_la57;
+ u64 *pgt = (void *)la57_toggle + PAGE_SIZE;
+ u64 *cr3 = (u64 *)__native_read_cr3();
+ u64 *new_cr3;
+
+ if (!la57_toggle || !need_toggle)
+ return;
+
+ if (!have_la57) {
+ /*
+ * 5 level paging will be enabled, so a root level page needs
+ * to be allocated from the 32-bit addressable physical region,
+ * with its first entry referring to the existing hierarchy.
+ */
+ new_cr3 = memset(pgt, 0, PAGE_SIZE);
+ new_cr3[0] = (u64)cr3 | _PAGE_TABLE_NOENC;
+ } else {
+ /* take the new root table pointer from the current entry #0 */
+ new_cr3 = (u64 *)(cr3[0] & PAGE_MASK);
+
+ /* copy the new root table if it is not 32-bit addressable */
+ if ((u64)new_cr3 > U32_MAX)
+ new_cr3 = memcpy(pgt, new_cr3, PAGE_SIZE);
+ }
+
+ native_load_gdt(&(struct desc_ptr){ sizeof(gdt) - 1, (u64)gdt });
+
+ la57_toggle(new_cr3);
+}
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index 220be75a5cdc..2fee52ed335d 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -15,16 +15,16 @@
#include <asm/setup.h>
#include <asm/desc.h>
#include <asm/boot.h>
+#include <asm/kaslr.h>
+#include <asm/sev.h>
#include "efistub.h"
-
-/* Maximum physical address for 64-bit kernel with 4-level paging */
-#define MAXMEM_X86_64_4LEVEL (1ull << 46)
+#include "x86-stub.h"
const efi_system_table_t *efi_system_table;
const efi_dxe_services_table_t *efi_dxe_table;
-u32 image_offset __section(".data");
static efi_loaded_image_t *image = NULL;
+static efi_memory_attribute_protocol_t *memattr;
typedef union sev_memory_acceptance_protocol sev_memory_acceptance_protocol_t;
union sev_memory_acceptance_protocol {
@@ -72,7 +72,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
rom->data.type = SETUP_PCI;
rom->data.len = size - sizeof(struct setup_data);
rom->data.next = 0;
- rom->pcilen = pci->romsize;
+ rom->pcilen = romsize;
*__rom = rom;
status = efi_call_proto(pci, pci.read, EfiPciIoWidthUint16,
@@ -223,8 +223,8 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
}
}
-static void
-adjust_memory_range_protection(unsigned long start, unsigned long size)
+void efi_adjust_memory_range_protection(unsigned long start,
+ unsigned long size)
{
efi_status_t status;
efi_gcd_memory_space_desc_t desc;
@@ -232,12 +232,18 @@ adjust_memory_range_protection(unsigned long start, unsigned long size)
unsigned long rounded_start, rounded_end;
unsigned long unprotect_start, unprotect_size;
- if (efi_dxe_table == NULL)
- return;
-
rounded_start = rounddown(start, EFI_PAGE_SIZE);
rounded_end = roundup(start + size, EFI_PAGE_SIZE);
+ if (memattr != NULL) {
+ efi_call_proto(memattr, clear_memory_attributes, rounded_start,
+ rounded_end - rounded_start, EFI_MEMORY_XP);
+ return;
+ }
+
+ if (efi_dxe_table == NULL)
+ return;
+
/*
* Don't modify memory region attributes, they are
* already suitable, to lower the possibility to
@@ -278,49 +284,6 @@ adjust_memory_range_protection(unsigned long start, unsigned long size)
}
}
-/*
- * Trampoline takes 2 pages and can be loaded in first megabyte of memory
- * with its end placed between 128k and 640k where BIOS might start.
- * (see arch/x86/boot/compressed/pgtable_64.c)
- *
- * We cannot find exact trampoline placement since memory map
- * can be modified by UEFI, and it can alter the computed address.
- */
-
-#define TRAMPOLINE_PLACEMENT_BASE ((128 - 8)*1024)
-#define TRAMPOLINE_PLACEMENT_SIZE (640*1024 - (128 - 8)*1024)
-
-void startup_32(struct boot_params *boot_params);
-
-static void
-setup_memory_protection(unsigned long image_base, unsigned long image_size)
-{
- /*
- * Allow execution of possible trampoline used
- * for switching between 4- and 5-level page tables
- * and relocated kernel image.
- */
-
- adjust_memory_range_protection(TRAMPOLINE_PLACEMENT_BASE,
- TRAMPOLINE_PLACEMENT_SIZE);
-
-#ifdef CONFIG_64BIT
- if (image_base != (unsigned long)startup_32)
- adjust_memory_range_protection(image_base, image_size);
-#else
- /*
- * Clear protection flags on a whole range of possible
- * addresses used for KASLR. We don't need to do that
- * on x86_64, since KASLR/extraction is performed after
- * dedicated identity page tables are built and we only
- * need to remove possible protection on relocated image
- * itself disregarding further relocations.
- */
- adjust_memory_range_protection(LOAD_PHYSICAL_ADDR,
- KERNEL_IMAGE_SIZE - LOAD_PHYSICAL_ADDR);
-#endif
-}
-
static void setup_unaccepted_memory(void)
{
efi_guid_t mem_acceptance_proto = OVMF_SEV_MEMORY_ACCEPTANCE_PROTOCOL_GUID;
@@ -346,9 +309,7 @@ static void setup_unaccepted_memory(void)
static const efi_char16_t apple[] = L"Apple";
-static void setup_quirks(struct boot_params *boot_params,
- unsigned long image_base,
- unsigned long image_size)
+static void setup_quirks(struct boot_params *boot_params)
{
efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
efi_table_attr(efi_system_table, fw_vendor);
@@ -357,9 +318,6 @@ static void setup_quirks(struct boot_params *boot_params,
if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
retrieve_apple_device_properties(boot_params);
}
-
- if (IS_ENABLED(CONFIG_EFI_DXE_MEM_ATTRIBUTES))
- setup_memory_protection(image_base, image_size);
}
/*
@@ -512,7 +470,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
}
image_base = efi_table_attr(image, image_base);
- image_offset = (void *)startup_32 - image_base;
status = efi_allocate_pages(sizeof(struct boot_params),
(unsigned long *)&boot_params, ULONG_MAX);
@@ -803,19 +760,96 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
return EFI_SUCCESS;
}
+static bool have_unsupported_snp_features(void)
+{
+ u64 unsupported;
+
+ unsupported = snp_get_unsupported_features(sev_get_status());
+ if (unsupported) {
+ efi_err("Unsupported SEV-SNP features detected: 0x%llx\n",
+ unsupported);
+ return true;
+ }
+ return false;
+}
+
+static void efi_get_seed(void *seed, int size)
+{
+ efi_get_random_bytes(size, seed);
+
+ /*
+ * This only updates seed[0] when running on 32-bit, but in that case,
+ * seed[1] is not used anyway, as there is no virtual KASLR on 32-bit.
+ */
+ *(unsigned long *)seed ^= kaslr_get_random_long("EFI");
+}
+
+static void error(char *str)
+{
+ efi_warn("Decompression failed: %s\n", str);
+}
+
+static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
+{
+ unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
+ unsigned long addr, alloc_size, entry;
+ efi_status_t status;
+ u32 seed[2] = {};
+
+ /* determine the required size of the allocation */
+ alloc_size = ALIGN(max_t(unsigned long, output_len, kernel_total_size),
+ MIN_KERNEL_ALIGN);
+
+ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && !efi_nokaslr) {
+ u64 range = KERNEL_IMAGE_SIZE - LOAD_PHYSICAL_ADDR - kernel_total_size;
+
+ efi_get_seed(seed, sizeof(seed));
+
+ virt_addr += (range * seed[1]) >> 32;
+ virt_addr &= ~(CONFIG_PHYSICAL_ALIGN - 1);
+ }
+
+ status = efi_random_alloc(alloc_size, CONFIG_PHYSICAL_ALIGN, &addr,
+ seed[0], EFI_LOADER_CODE,
+ EFI_X86_KERNEL_ALLOC_LIMIT);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ entry = decompress_kernel((void *)addr, virt_addr, error);
+ if (entry == ULONG_MAX) {
+ efi_free(alloc_size, addr);
+ return EFI_LOAD_ERROR;
+ }
+
+ *kernel_entry = addr + entry;
+
+ efi_adjust_memory_range_protection(addr, kernel_total_size);
+
+ return EFI_SUCCESS;
+}
+
+static void __noreturn enter_kernel(unsigned long kernel_addr,
+ struct boot_params *boot_params)
+{
+ /* enter decompressed kernel with boot_params pointer in RSI/ESI */
+ asm("jmp *%0"::"r"(kernel_addr), "S"(boot_params));
+
+ unreachable();
+}
+
/*
- * On success, we return the address of startup_32, which has potentially been
- * relocated by efi_relocate_kernel.
- * On failure, we exit to the firmware via efi_exit instead of returning.
+ * On success, this routine will jump to the relocated image directly and never
+ * return. On failure, it will exit to the firmware via efi_exit() instead of
+ * returning.
*/
-asmlinkage unsigned long efi_main(efi_handle_t handle,
- efi_system_table_t *sys_table_arg,
- struct boot_params *boot_params)
+void __noreturn efi_stub_entry(efi_handle_t handle,
+ efi_system_table_t *sys_table_arg,
+ struct boot_params *boot_params)
{
- unsigned long bzimage_addr = (unsigned long)startup_32;
- unsigned long buffer_start, buffer_end;
+ efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
struct setup_header *hdr = &boot_params->hdr;
const struct linux_efi_initrd *initrd = NULL;
+ unsigned long kernel_entry;
efi_status_t status;
efi_system_table = sys_table_arg;
@@ -823,65 +857,25 @@ asmlinkage unsigned long efi_main(efi_handle_t handle,
if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
efi_exit(handle, EFI_INVALID_PARAMETER);
- efi_dxe_table = get_efi_config_table(EFI_DXE_SERVICES_TABLE_GUID);
- if (efi_dxe_table &&
- efi_dxe_table->hdr.signature != EFI_DXE_SERVICES_TABLE_SIGNATURE) {
- efi_warn("Ignoring DXE services table: invalid signature\n");
- efi_dxe_table = NULL;
+ if (have_unsupported_snp_features())
+ efi_exit(handle, EFI_UNSUPPORTED);
+
+ if (IS_ENABLED(CONFIG_EFI_DXE_MEM_ATTRIBUTES)) {
+ efi_dxe_table = get_efi_config_table(EFI_DXE_SERVICES_TABLE_GUID);
+ if (efi_dxe_table &&
+ efi_dxe_table->hdr.signature != EFI_DXE_SERVICES_TABLE_SIGNATURE) {
+ efi_warn("Ignoring DXE services table: invalid signature\n");
+ efi_dxe_table = NULL;
+ }
}
- /*
- * If the kernel isn't already loaded at a suitable address,
- * relocate it.
- *
- * It must be loaded above LOAD_PHYSICAL_ADDR.
- *
- * The maximum address for 64-bit is 1 << 46 for 4-level paging. This
- * is defined as the macro MAXMEM, but unfortunately that is not a
- * compile-time constant if 5-level paging is configured, so we instead
- * define our own macro for use here.
- *
- * For 32-bit, the maximum address is complicated to figure out, for
- * now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
- * KASLR uses.
- *
- * Also relocate it if image_offset is zero, i.e. the kernel wasn't
- * loaded by LoadImage, but rather by a bootloader that called the
- * handover entry. The reason we must always relocate in this case is
- * to handle the case of systemd-boot booting a unified kernel image,
- * which is a PE executable that contains the bzImage and an initrd as
- * COFF sections. The initrd section is placed after the bzImage
- * without ensuring that there are at least init_size bytes available
- * for the bzImage, and thus the compressed kernel's startup code may
- * overwrite the initrd unless it is moved out of the way.
- */
+ /* grab the memory attributes protocol if it exists */
+ efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr);
- buffer_start = ALIGN(bzimage_addr - image_offset,
- hdr->kernel_alignment);
- buffer_end = buffer_start + hdr->init_size;
-
- if ((buffer_start < LOAD_PHYSICAL_ADDR) ||
- (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE) ||
- (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
- (image_offset == 0)) {
- extern char _bss[];
-
- status = efi_relocate_kernel(&bzimage_addr,
- (unsigned long)_bss - bzimage_addr,
- hdr->init_size,
- hdr->pref_address,
- hdr->kernel_alignment,
- LOAD_PHYSICAL_ADDR);
- if (status != EFI_SUCCESS) {
- efi_err("efi_relocate_kernel() failed!\n");
- goto fail;
- }
- /*
- * Now that we've copied the kernel elsewhere, we no longer
- * have a set up block before startup_32(), so reset image_offset
- * to zero in case it was set earlier.
- */
- image_offset = 0;
+ status = efi_setup_5level_paging();
+ if (status != EFI_SUCCESS) {
+ efi_err("efi_setup_5level_paging() failed!\n");
+ goto fail;
}
#ifdef CONFIG_CMDLINE_BOOL
@@ -901,6 +895,12 @@ asmlinkage unsigned long efi_main(efi_handle_t handle,
}
}
+ status = efi_decompress_kernel(&kernel_entry);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to decompress kernel\n");
+ goto fail;
+ }
+
/*
* At this point, an initrd may already have been loaded by the
* bootloader and passed via bootparams. We permit an initrd loaded
@@ -940,7 +940,7 @@ asmlinkage unsigned long efi_main(efi_handle_t handle,
setup_efi_pci(boot_params);
- setup_quirks(boot_params, bzimage_addr, buffer_end - buffer_start);
+ setup_quirks(boot_params);
setup_unaccepted_memory();
@@ -950,9 +950,38 @@ asmlinkage unsigned long efi_main(efi_handle_t handle,
goto fail;
}
- return bzimage_addr;
+ /*
+ * Call the SEV init code while still running with the firmware's
+ * GDT/IDT, so #VC exceptions will be handled by EFI.
+ */
+ sev_enable(boot_params);
+
+ efi_5level_switch();
+
+ enter_kernel(kernel_entry, boot_params);
fail:
- efi_err("efi_main() failed!\n");
+ efi_err("efi_stub_entry() failed!\n");
efi_exit(handle, status);
}
+
+#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
+void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
+ struct boot_params *boot_params)
+{
+ extern char _bss[], _ebss[];
+
+ memset(_bss, 0, _ebss - _bss);
+ efi_stub_entry(handle, sys_table_arg, boot_params);
+}
+
+#ifndef CONFIG_EFI_MIXED
+extern __alias(efi_handover_entry)
+void efi32_stub_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
+ struct boot_params *boot_params);
+
+extern __alias(efi_handover_entry)
+void efi64_stub_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
+ struct boot_params *boot_params);
+#endif
+#endif
diff --git a/drivers/firmware/efi/libstub/x86-stub.h b/drivers/firmware/efi/libstub/x86-stub.h
new file mode 100644
index 000000000000..37c5a36b9d8c
--- /dev/null
+++ b/drivers/firmware/efi/libstub/x86-stub.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/efi.h>
+
+extern void trampoline_32bit_src(void *, bool);
+extern const u16 trampoline_ljmp_imm_offset;
+
+void efi_adjust_memory_range_protection(unsigned long start,
+ unsigned long size);
+
+#ifdef CONFIG_X86_64
+efi_status_t efi_setup_5level_paging(void);
+void efi_5level_switch(void);
+#else
+static inline efi_status_t efi_setup_5level_paging(void) { return EFI_SUCCESS; }
+static inline void efi_5level_switch(void) {}
+#endif
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index e5d7fa1f1d8f..bdb17eac0cb4 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -119,7 +119,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
}
status = efi_random_alloc(alloc_size, min_kimg_align, &image_base,
- seed, EFI_LOADER_CODE);
+ seed, EFI_LOADER_CODE, EFI_ALLOC_LIMIT);
if (status != EFI_SUCCESS) {
efi_err("Failed to allocate memory\n");
goto free_cmdline;
diff --git a/drivers/firmware/efi/riscv-runtime.c b/drivers/firmware/efi/riscv-runtime.c
index d0daacd2c903..09525fb5c240 100644
--- a/drivers/firmware/efi/riscv-runtime.c
+++ b/drivers/firmware/efi/riscv-runtime.c
@@ -130,14 +130,25 @@ static int __init riscv_enable_runtime_services(void)
}
early_initcall(riscv_enable_runtime_services);
-void efi_virtmap_load(void)
+static void efi_virtmap_load(void)
{
preempt_disable();
switch_mm(current->active_mm, &efi_mm, NULL);
}
-void efi_virtmap_unload(void)
+static void efi_virtmap_unload(void)
{
switch_mm(&efi_mm, current->active_mm, NULL);
preempt_enable();
}
+
+void arch_efi_call_virt_setup(void)
+{
+ sync_kernel_mappings(efi_mm.pgd);
+ efi_virtmap_load();
+}
+
+void arch_efi_call_virt_teardown(void)
+{
+ efi_virtmap_unload();
+}
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index a400c4312c82..5d56bc40a79d 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -40,55 +40,97 @@
* code doesn't get too cluttered:
*/
#define efi_call_virt(f, args...) \
- efi_call_virt_pointer(efi.runtime, f, args)
-#define __efi_call_virt(f, args...) \
- __efi_call_virt_pointer(efi.runtime, f, args)
+ arch_efi_call_virt(efi.runtime, f, args)
+
+union efi_rts_args {
+ struct {
+ efi_time_t *time;
+ efi_time_cap_t *capabilities;
+ } GET_TIME;
+
+ struct {
+ efi_time_t *time;
+ } SET_TIME;
+
+ struct {
+ efi_bool_t *enabled;
+ efi_bool_t *pending;
+ efi_time_t *time;
+ } GET_WAKEUP_TIME;
+
+ struct {
+ efi_bool_t enable;
+ efi_time_t *time;
+ } SET_WAKEUP_TIME;
+
+ struct {
+ efi_char16_t *name;
+ efi_guid_t *vendor;
+ u32 *attr;
+ unsigned long *data_size;
+ void *data;
+ } GET_VARIABLE;
+
+ struct {
+ unsigned long *name_size;
+ efi_char16_t *name;
+ efi_guid_t *vendor;
+ } GET_NEXT_VARIABLE;
+
+ struct {
+ efi_char16_t *name;
+ efi_guid_t *vendor;
+ u32 attr;
+ unsigned long data_size;
+ void *data;
+ } SET_VARIABLE;
+
+ struct {
+ u32 attr;
+ u64 *storage_space;
+ u64 *remaining_space;
+ u64 *max_variable_size;
+ } QUERY_VARIABLE_INFO;
+
+ struct {
+ u32 *high_count;
+ } GET_NEXT_HIGH_MONO_COUNT;
+
+ struct {
+ efi_capsule_header_t **capsules;
+ unsigned long count;
+ unsigned long sg_list;
+ } UPDATE_CAPSULE;
+
+ struct {
+ efi_capsule_header_t **capsules;
+ unsigned long count;
+ u64 *max_size;
+ int *reset_type;
+ } QUERY_CAPSULE_CAPS;
+
+ struct {
+ efi_status_t (__efiapi *acpi_prm_handler)(u64, void *);
+ u64 param_buffer_addr;
+ void *context;
+ } ACPI_PRM_HANDLER;
+};
struct efi_runtime_work efi_rts_work;
/*
- * efi_queue_work: Queue efi_runtime_service() and wait until it's done
- * @rts: efi_runtime_service() function identifier
- * @rts_arg<1-5>: efi_runtime_service() function arguments
+ * efi_queue_work: Queue EFI runtime service call and wait for completion
+ * @_rts: EFI runtime service function identifier
+ * @_args: Arguments to pass to the EFI runtime service
*
* Accesses to efi_runtime_services() are serialized by a binary
* semaphore (efi_runtime_lock) and caller waits until the work is
* finished, hence _only_ one work is queued at a time and the caller
* thread waits for completion.
*/
-#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \
-({ \
- efi_rts_work.status = EFI_ABORTED; \
- \
- if (!efi_enabled(EFI_RUNTIME_SERVICES)) { \
- pr_warn_once("EFI Runtime Services are disabled!\n"); \
- efi_rts_work.status = EFI_DEVICE_ERROR; \
- goto exit; \
- } \
- \
- init_completion(&efi_rts_work.efi_rts_comp); \
- INIT_WORK(&efi_rts_work.work, efi_call_rts); \
- efi_rts_work.arg1 = _arg1; \
- efi_rts_work.arg2 = _arg2; \
- efi_rts_work.arg3 = _arg3; \
- efi_rts_work.arg4 = _arg4; \
- efi_rts_work.arg5 = _arg5; \
- efi_rts_work.efi_rts_id = _rts; \
- \
- /* \
- * queue_work() returns 0 if work was already on queue, \
- * _ideally_ this should never happen. \
- */ \
- if (queue_work(efi_rts_wq, &efi_rts_work.work)) \
- wait_for_completion(&efi_rts_work.efi_rts_comp); \
- else \
- pr_err("Failed to queue work to efi_rts_wq.\n"); \
- \
- WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED); \
-exit: \
- efi_rts_work.efi_rts_id = EFI_NONE; \
- efi_rts_work.status; \
-})
+#define efi_queue_work(_rts, _args...) \
+ __efi_queue_work(EFI_ ## _rts, \
+ &(union efi_rts_args){ ._rts = { _args }})
#ifndef arch_efi_save_flags
#define arch_efi_save_flags(state_flags) local_save_flags(state_flags)
@@ -103,7 +145,7 @@ unsigned long efi_call_virt_save_flags(void)
return flags;
}
-void efi_call_virt_check_flags(unsigned long flags, const char *call)
+void efi_call_virt_check_flags(unsigned long flags, const void *caller)
{
unsigned long cur_flags, mismatch;
@@ -114,8 +156,8 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
return;
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
- pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
- flags, cur_flags, call);
+ pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI call from %pS\n",
+ flags, cur_flags, caller ?: __builtin_return_address(0));
arch_efi_restore_flags(flags);
}
@@ -170,74 +212,90 @@ extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
/*
* Calls the appropriate efi_runtime_service() with the appropriate
* arguments.
- *
- * Semantics followed by efi_call_rts() to understand efi_runtime_work:
- * 1. If argument was a pointer, recast it from void pointer to original
- * pointer type.
- * 2. If argument was a value, recast it from void pointer to original
- * pointer type and dereference it.
*/
static void efi_call_rts(struct work_struct *work)
{
- void *arg1, *arg2, *arg3, *arg4, *arg5;
+ const union efi_rts_args *args = efi_rts_work.args;
efi_status_t status = EFI_NOT_FOUND;
+ unsigned long flags;
- arg1 = efi_rts_work.arg1;
- arg2 = efi_rts_work.arg2;
- arg3 = efi_rts_work.arg3;
- arg4 = efi_rts_work.arg4;
- arg5 = efi_rts_work.arg5;
+ arch_efi_call_virt_setup();
+ flags = efi_call_virt_save_flags();
switch (efi_rts_work.efi_rts_id) {
case EFI_GET_TIME:
- status = efi_call_virt(get_time, (efi_time_t *)arg1,
- (efi_time_cap_t *)arg2);
+ status = efi_call_virt(get_time,
+ args->GET_TIME.time,
+ args->GET_TIME.capabilities);
break;
case EFI_SET_TIME:
- status = efi_call_virt(set_time, (efi_time_t *)arg1);
+ status = efi_call_virt(set_time,
+ args->SET_TIME.time);
break;
case EFI_GET_WAKEUP_TIME:
- status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
- (efi_bool_t *)arg2, (efi_time_t *)arg3);
+ status = efi_call_virt(get_wakeup_time,
+ args->GET_WAKEUP_TIME.enabled,
+ args->GET_WAKEUP_TIME.pending,
+ args->GET_WAKEUP_TIME.time);
break;
case EFI_SET_WAKEUP_TIME:
- status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
- (efi_time_t *)arg2);
+ status = efi_call_virt(set_wakeup_time,
+ args->SET_WAKEUP_TIME.enable,
+ args->SET_WAKEUP_TIME.time);
break;
case EFI_GET_VARIABLE:
- status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
- (efi_guid_t *)arg2, (u32 *)arg3,
- (unsigned long *)arg4, (void *)arg5);
+ status = efi_call_virt(get_variable,
+ args->GET_VARIABLE.name,
+ args->GET_VARIABLE.vendor,
+ args->GET_VARIABLE.attr,
+ args->GET_VARIABLE.data_size,
+ args->GET_VARIABLE.data);
break;
case EFI_GET_NEXT_VARIABLE:
- status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
- (efi_char16_t *)arg2,
- (efi_guid_t *)arg3);
+ status = efi_call_virt(get_next_variable,
+ args->GET_NEXT_VARIABLE.name_size,
+ args->GET_NEXT_VARIABLE.name,
+ args->GET_NEXT_VARIABLE.vendor);
break;
case EFI_SET_VARIABLE:
- status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
- (efi_guid_t *)arg2, *(u32 *)arg3,
- *(unsigned long *)arg4, (void *)arg5);
+ status = efi_call_virt(set_variable,
+ args->SET_VARIABLE.name,
+ args->SET_VARIABLE.vendor,
+ args->SET_VARIABLE.attr,
+ args->SET_VARIABLE.data_size,
+ args->SET_VARIABLE.data);
break;
case EFI_QUERY_VARIABLE_INFO:
- status = efi_call_virt(query_variable_info, *(u32 *)arg1,
- (u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
+ status = efi_call_virt(query_variable_info,
+ args->QUERY_VARIABLE_INFO.attr,
+ args->QUERY_VARIABLE_INFO.storage_space,
+ args->QUERY_VARIABLE_INFO.remaining_space,
+ args->QUERY_VARIABLE_INFO.max_variable_size);
break;
case EFI_GET_NEXT_HIGH_MONO_COUNT:
- status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
+ status = efi_call_virt(get_next_high_mono_count,
+ args->GET_NEXT_HIGH_MONO_COUNT.high_count);
break;
case EFI_UPDATE_CAPSULE:
status = efi_call_virt(update_capsule,
- (efi_capsule_header_t **)arg1,
- *(unsigned long *)arg2,
- *(unsigned long *)arg3);
+ args->UPDATE_CAPSULE.capsules,
+ args->UPDATE_CAPSULE.count,
+ args->UPDATE_CAPSULE.sg_list);
break;
case EFI_QUERY_CAPSULE_CAPS:
status = efi_call_virt(query_capsule_caps,
- (efi_capsule_header_t **)arg1,
- *(unsigned long *)arg2, (u64 *)arg3,
- (int *)arg4);
+ args->QUERY_CAPSULE_CAPS.capsules,
+ args->QUERY_CAPSULE_CAPS.count,
+ args->QUERY_CAPSULE_CAPS.max_size,
+ args->QUERY_CAPSULE_CAPS.reset_type);
break;
+ case EFI_ACPI_PRM_HANDLER:
+#ifdef CONFIG_ACPI_PRMT
+ status = arch_efi_call_virt(args, ACPI_PRM_HANDLER.acpi_prm_handler,
+ args->ACPI_PRM_HANDLER.param_buffer_addr,
+ args->ACPI_PRM_HANDLER.context);
+ break;
+#endif
default:
/*
* Ideally, we should never reach here because a caller of this
@@ -246,17 +304,53 @@ static void efi_call_rts(struct work_struct *work)
*/
pr_err("Requested executing invalid EFI Runtime Service.\n");
}
+
+ efi_call_virt_check_flags(flags, efi_rts_work.caller);
+ arch_efi_call_virt_teardown();
+
efi_rts_work.status = status;
complete(&efi_rts_work.efi_rts_comp);
}
+static efi_status_t __efi_queue_work(enum efi_rts_ids id,
+ union efi_rts_args *args)
+{
+ efi_rts_work.efi_rts_id = id;
+ efi_rts_work.args = args;
+ efi_rts_work.caller = __builtin_return_address(0);
+ efi_rts_work.status = EFI_ABORTED;
+
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_warn_once("EFI Runtime Services are disabled!\n");
+ efi_rts_work.status = EFI_DEVICE_ERROR;
+ goto exit;
+ }
+
+ init_completion(&efi_rts_work.efi_rts_comp);
+ INIT_WORK(&efi_rts_work.work, efi_call_rts);
+
+ /*
+ * queue_work() returns 0 if work was already on queue,
+ * _ideally_ this should never happen.
+ */
+ if (queue_work(efi_rts_wq, &efi_rts_work.work))
+ wait_for_completion(&efi_rts_work.efi_rts_comp);
+ else
+ pr_err("Failed to queue work to efi_rts_wq.\n");
+
+ WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED);
+exit:
+ efi_rts_work.efi_rts_id = EFI_NONE;
+ return efi_rts_work.status;
+}
+
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{
efi_status_t status;
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_GET_TIME, tm, tc, NULL, NULL, NULL);
+ status = efi_queue_work(GET_TIME, tm, tc);
up(&efi_runtime_lock);
return status;
}
@@ -267,7 +361,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_SET_TIME, tm, NULL, NULL, NULL, NULL);
+ status = efi_queue_work(SET_TIME, tm);
up(&efi_runtime_lock);
return status;
}
@@ -280,8 +374,7 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_GET_WAKEUP_TIME, enabled, pending, tm, NULL,
- NULL);
+ status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm);
up(&efi_runtime_lock);
return status;
}
@@ -292,8 +385,7 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
- NULL);
+ status = efi_queue_work(SET_WAKEUP_TIME, enabled, tm);
up(&efi_runtime_lock);
return status;
}
@@ -308,7 +400,7 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_GET_VARIABLE, name, vendor, attr, data_size,
+ status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
data);
up(&efi_runtime_lock);
return status;
@@ -322,8 +414,7 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_GET_NEXT_VARIABLE, name_size, name, vendor,
- NULL, NULL);
+ status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor);
up(&efi_runtime_lock);
return status;
}
@@ -338,24 +429,23 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_SET_VARIABLE, name, vendor, &attr, &data_size,
+ status = efi_queue_work(SET_VARIABLE, name, vendor, attr, data_size,
data);
up(&efi_runtime_lock);
return status;
}
static efi_status_t
-virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
- u32 attr, unsigned long data_size,
- void *data)
+virt_efi_set_variable_nb(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
+ unsigned long data_size, void *data)
{
efi_status_t status;
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
- status = efi_call_virt(set_variable, name, vendor, attr, data_size,
- data);
+ status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor,
+ attr, data_size, data);
up(&efi_runtime_lock);
return status;
}
@@ -373,17 +463,15 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_QUERY_VARIABLE_INFO, &attr, storage_space,
- remaining_space, max_variable_size, NULL);
+ status = efi_queue_work(QUERY_VARIABLE_INFO, attr, storage_space,
+ remaining_space, max_variable_size);
up(&efi_runtime_lock);
return status;
}
static efi_status_t
-virt_efi_query_variable_info_nonblocking(u32 attr,
- u64 *storage_space,
- u64 *remaining_space,
- u64 *max_variable_size)
+virt_efi_query_variable_info_nb(u32 attr, u64 *storage_space,
+ u64 *remaining_space, u64 *max_variable_size)
{
efi_status_t status;
@@ -393,8 +481,9 @@ virt_efi_query_variable_info_nonblocking(u32 attr,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
- status = efi_call_virt(query_variable_info, attr, storage_space,
- remaining_space, max_variable_size);
+ status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr,
+ storage_space, remaining_space,
+ max_variable_size);
up(&efi_runtime_lock);
return status;
}
@@ -405,8 +494,7 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
- NULL, NULL);
+ status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count);
up(&efi_runtime_lock);
return status;
}
@@ -421,8 +509,13 @@ static void virt_efi_reset_system(int reset_type,
"could not get exclusive access to the firmware\n");
return;
}
+
+ arch_efi_call_virt_setup();
efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM;
- __efi_call_virt(reset_system, reset_type, status, data_size, data);
+ arch_efi_call_virt(efi.runtime, reset_system, reset_type, status,
+ data_size, data);
+ arch_efi_call_virt_teardown();
+
up(&efi_runtime_lock);
}
@@ -437,8 +530,7 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_UPDATE_CAPSULE, capsules, &count, &sg_list,
- NULL, NULL);
+ status = efi_queue_work(UPDATE_CAPSULE, capsules, count, sg_list);
up(&efi_runtime_lock);
return status;
}
@@ -455,26 +547,44 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
if (down_interruptible(&efi_runtime_lock))
return EFI_ABORTED;
- status = efi_queue_work(EFI_QUERY_CAPSULE_CAPS, capsules, &count,
- max_size, reset_type, NULL);
+ status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, count,
+ max_size, reset_type);
up(&efi_runtime_lock);
return status;
}
-void efi_native_runtime_setup(void)
+void __init efi_native_runtime_setup(void)
{
- efi.get_time = virt_efi_get_time;
- efi.set_time = virt_efi_set_time;
- efi.get_wakeup_time = virt_efi_get_wakeup_time;
- efi.set_wakeup_time = virt_efi_set_wakeup_time;
- efi.get_variable = virt_efi_get_variable;
- efi.get_next_variable = virt_efi_get_next_variable;
- efi.set_variable = virt_efi_set_variable;
- efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
- efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
- efi.reset_system = virt_efi_reset_system;
- efi.query_variable_info = virt_efi_query_variable_info;
- efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
- efi.update_capsule = virt_efi_update_capsule;
- efi.query_capsule_caps = virt_efi_query_capsule_caps;
+ efi.get_time = virt_efi_get_time;
+ efi.set_time = virt_efi_set_time;
+ efi.get_wakeup_time = virt_efi_get_wakeup_time;
+ efi.set_wakeup_time = virt_efi_set_wakeup_time;
+ efi.get_variable = virt_efi_get_variable;
+ efi.get_next_variable = virt_efi_get_next_variable;
+ efi.set_variable = virt_efi_set_variable;
+ efi.set_variable_nonblocking = virt_efi_set_variable_nb;
+ efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+ efi.reset_system = virt_efi_reset_system;
+ efi.query_variable_info = virt_efi_query_variable_info;
+ efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nb;
+ efi.update_capsule = virt_efi_update_capsule;
+ efi.query_capsule_caps = virt_efi_query_capsule_caps;
}
+
+#ifdef CONFIG_ACPI_PRMT
+
+efi_status_t
+efi_call_acpi_prm_handler(efi_status_t (__efiapi *handler_addr)(u64, void *),
+ u64 param_buffer_addr, void *context)
+{
+ efi_status_t status;
+
+ if (down_interruptible(&efi_runtime_lock))
+ return EFI_ABORTED;
+ status = efi_queue_work(ACPI_PRM_HANDLER, handler_addr,
+ param_buffer_addr, context);
+ up(&efi_runtime_lock);
+ return status;
+}
+
+#endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e382dfebad7c..673bafb8be58 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -111,6 +111,9 @@ config GPIO_MAX730X
config GPIO_IDIO_16
tristate
+ select REGMAP_IRQ
+ select GPIOLIB_IRQCHIP
+ select GPIO_REGMAP
help
Enables support for the idio-16 library functions. The idio-16 library
provides functions to facilitate communication with devices within the
@@ -191,7 +194,7 @@ config GPIO_RASPBERRYPI_EXP
config GPIO_BCM_KONA
bool "Broadcom Kona GPIO"
- depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
+ depends on ARCH_BCM_MOBILE || COMPILE_TEST
help
Turn on GPIO support for Broadcom "Kona" chips.
@@ -283,7 +286,7 @@ config GPIO_EXAR
config GPIO_GE_FPGA
bool "GE FPGA based GPIO"
- depends on GE_FPGA
+ depends on GE_FPGA || COMPILE_TEST
select GPIO_GENERIC
help
Support for common GPIO functionality provided on some GE Single Board
@@ -564,7 +567,7 @@ config GPIO_SAMA5D2_PIOBU
maintain their value during backup/self-refresh.
config GPIO_SIFIVE
- bool "SiFive GPIO support"
+ tristate "SiFive GPIO support"
depends on OF_GPIO
select IRQ_DOMAIN_HIERARCHY
select GPIO_GENERIC
@@ -858,6 +861,7 @@ config GPIO_104_DIO_48E
select REGMAP_IRQ
select GPIOLIB_IRQCHIP
select GPIO_I8255
+ select I8254
help
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
104-DIO-24E). The base port addresses for the devices may be
@@ -868,7 +872,7 @@ config GPIO_104_IDIO_16
tristate "ACCES 104-IDIO-16 GPIO support"
depends on PC104
select ISA_BUS_API
- select GPIOLIB_IRQCHIP
+ select REGMAP_MMIO
select GPIO_IDIO_16
help
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
@@ -994,7 +998,10 @@ config GPIO_WINBOND
config GPIO_WS16C48
tristate "WinSystems WS16C48 GPIO support"
select ISA_BUS_API
+ select REGMAP_IRQ
+ select REGMAP_MMIO
select GPIOLIB_IRQCHIP
+ select GPIO_REGMAP
help
Enables GPIO support for the WinSystems WS16C48. The base port
addresses for the devices may be configured via the base module
@@ -1028,6 +1035,17 @@ config GPIO_FXL6408
To compile this driver as a module, choose M here: the module will
be called gpio-fxl6408.
+config GPIO_DS4520
+ tristate "DS4520 I2C GPIO expander"
+ select REGMAP_I2C
+ select GPIO_REGMAP
+ help
+ GPIO driver for ADI DS4520 I2C-based GPIO expander.
+ Say yes here to enable the GPIO driver for the ADI DS4520 chip.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-ds4520.
+
config GPIO_GW_PLD
tristate "Gateworks PLD GPIO Expander"
depends on OF_GPIO
@@ -1640,7 +1658,7 @@ config GPIO_PCH
config GPIO_PCI_IDIO_16
tristate "ACCES PCI-IDIO-16 GPIO support"
- select GPIOLIB_IRQCHIP
+ select REGMAP_MMIO
select GPIO_IDIO_16
help
Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
@@ -1650,7 +1668,10 @@ config GPIO_PCI_IDIO_16
config GPIO_PCIE_IDIO_24
tristate "ACCES PCIe-IDIO-24 GPIO support"
+ select REGMAP_IRQ
+ select REGMAP_MMIO
select GPIOLIB_IRQCHIP
+ select GPIO_REGMAP
help
Enables GPIO support for the ACCES PCIe-IDIO-24 family (PCIe-IDIO-24,
PCIe-IDI-24, PCIe-IDO-24, PCIe-IDIO-12). An interrupt is generated
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c3ac51d47aa9..eb73b5d633eb 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
+obj-$(CONFIG_GPIO_DS4520) += gpio-ds4520.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
obj-$(CONFIG_GPIO_ELKHARTLAKE) += gpio-elkhartlake.o
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 8ff5f4ff5958..4df9becaf349 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -9,6 +9,7 @@
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/i8254.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/isa.h>
@@ -16,6 +17,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/regmap.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-i8255.h"
@@ -37,6 +39,8 @@ MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
#define DIO48E_ENABLE_INTERRUPT 0xB
#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT
+#define DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING 0xD
+#define DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING
#define DIO48E_CLEAR_INTERRUPT 0xF
#define DIO48E_NUM_PPI 2
@@ -75,18 +79,20 @@ static const struct regmap_access_table dio48e_precious_table = {
.yes_ranges = dio48e_precious_ranges,
.n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges),
};
-static const struct regmap_config dio48e_regmap_config = {
- .reg_bits = 8,
- .reg_stride = 1,
- .val_bits = 8,
- .io_port = true,
- .max_register = 0xF,
- .wr_table = &dio48e_wr_table,
- .rd_table = &dio48e_rd_table,
- .volatile_table = &dio48e_volatile_table,
- .precious_table = &dio48e_precious_table,
- .cache_type = REGCACHE_FLAT,
- .use_raw_spinlock = true,
+
+static const struct regmap_range pit_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x3),
+};
+static const struct regmap_range pit_rd_ranges[] = {
+ regmap_reg_range(0x0, 0x2),
+};
+static const struct regmap_access_table pit_wr_table = {
+ .yes_ranges = pit_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges),
+};
+static const struct regmap_access_table pit_rd_table = {
+ .yes_ranges = pit_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges),
};
/* only bit 3 on each respective Port C supports interrupts */
@@ -102,14 +108,56 @@ static const struct regmap_irq dio48e_regmap_irqs[] = {
/**
* struct dio48e_gpio - GPIO device private data structure
+ * @lock: synchronization lock to prevent I/O race conditions
* @map: Regmap for the device
+ * @regs: virtual mapping for device registers
+ * @flags: IRQ flags saved during locking
* @irq_mask: Current IRQ mask state on the device
*/
struct dio48e_gpio {
+ raw_spinlock_t lock;
struct regmap *map;
+ void __iomem *regs;
+ unsigned long flags;
unsigned int irq_mask;
};
+static void dio48e_regmap_lock(void *lock_arg) __acquires(&dio48egpio->lock)
+{
+ struct dio48e_gpio *const dio48egpio = lock_arg;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&dio48egpio->lock, flags);
+ dio48egpio->flags = flags;
+}
+
+static void dio48e_regmap_unlock(void *lock_arg) __releases(&dio48egpio->lock)
+{
+ struct dio48e_gpio *const dio48egpio = lock_arg;
+
+ raw_spin_unlock_irqrestore(&dio48egpio->lock, dio48egpio->flags);
+}
+
+static void pit_regmap_lock(void *lock_arg) __acquires(&dio48egpio->lock)
+{
+ struct dio48e_gpio *const dio48egpio = lock_arg;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&dio48egpio->lock, flags);
+ dio48egpio->flags = flags;
+
+ iowrite8(0x00, dio48egpio->regs + DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING);
+}
+
+static void pit_regmap_unlock(void *lock_arg) __releases(&dio48egpio->lock)
+{
+ struct dio48e_gpio *const dio48egpio = lock_arg;
+
+ ioread8(dio48egpio->regs + DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING);
+
+ raw_spin_unlock_irqrestore(&dio48egpio->lock, dio48egpio->flags);
+}
+
static int dio48e_handle_mask_sync(const int index,
const unsigned int mask_buf_def,
const unsigned int mask_buf,
@@ -176,6 +224,9 @@ static int dio48e_probe(struct device *dev, unsigned int id)
struct i8255_regmap_config config = {};
void __iomem *regs;
struct regmap *map;
+ struct regmap_config dio48e_regmap_config;
+ struct regmap_config pit_regmap_config;
+ struct i8254_regmap_config pit_config;
int err;
struct regmap_irq_chip *chip;
struct dio48e_gpio *dio48egpio;
@@ -187,21 +238,58 @@ static int dio48e_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
+ dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
+ if (!dio48egpio)
+ return -ENOMEM;
+
regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
if (!regs)
return -ENOMEM;
+ dio48egpio->regs = regs;
+
+ raw_spin_lock_init(&dio48egpio->lock);
+
+ dio48e_regmap_config = (struct regmap_config) {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .lock = dio48e_regmap_lock,
+ .unlock = dio48e_regmap_unlock,
+ .lock_arg = dio48egpio,
+ .io_port = true,
+ .wr_table = &dio48e_wr_table,
+ .rd_table = &dio48e_rd_table,
+ .volatile_table = &dio48e_volatile_table,
+ .precious_table = &dio48e_precious_table,
+ .cache_type = REGCACHE_FLAT,
+ };
+
map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config);
if (IS_ERR(map))
return dev_err_probe(dev, PTR_ERR(map),
"Unable to initialize register map\n");
- dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
- if (!dio48egpio)
- return -ENOMEM;
-
dio48egpio->map = map;
+ pit_regmap_config = (struct regmap_config) {
+ .name = "i8254",
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .lock = pit_regmap_lock,
+ .unlock = pit_regmap_unlock,
+ .lock_arg = dio48egpio,
+ .io_port = true,
+ .wr_table = &pit_wr_table,
+ .rd_table = &pit_rd_table,
+ };
+
+ pit_config.map = devm_regmap_init_mmio(dev, regs, &pit_regmap_config);
+ if (IS_ERR(pit_config.map))
+ return dev_err_probe(dev, PTR_ERR(pit_config.map),
+ "Unable to initialize i8254 register map\n");
+
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -225,6 +313,12 @@ static int dio48e_probe(struct device *dev, unsigned int id)
if (err)
return dev_err_probe(dev, err, "IRQ registration failed\n");
+ pit_config.parent = dev;
+
+ err = devm_i8254_regmap_register(dev, &pit_config);
+ if (err)
+ return err;
+
config.parent = dev;
config.map = map;
config.num_ppi = DIO48E_NUM_PPI;
@@ -245,3 +339,4 @@ module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(I8254);
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 098fbefdbe22..f03ccd0f534c 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -6,19 +6,16 @@
* This driver supports the following ACCES devices: 104-IDIO-16,
* 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
*/
-#include <linux/bitmap.h>
+#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
+#include <linux/err.h>
#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/irq.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
#include "gpio-idio-16.h"
@@ -36,187 +33,62 @@ static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
-/**
- * struct idio_16_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @lock: synchronization lock to prevent I/O race conditions
- * @irq_mask: I/O bits affected by interrupts
- * @reg: I/O address offset for the device registers
- * @state: ACCES IDIO-16 device state
- */
-struct idio_16_gpio {
- struct gpio_chip chip;
- raw_spinlock_t lock;
- unsigned long irq_mask;
- struct idio_16 __iomem *reg;
- struct idio_16_state state;
+static const struct regmap_range idio_16_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x4),
};
-
-static int idio_16_gpio_get_direction(struct gpio_chip *chip,
- unsigned int offset)
-{
- if (idio_16_get_direction(offset))
- return GPIO_LINE_DIRECTION_IN;
-
- return GPIO_LINE_DIRECTION_OUT;
-}
-
-static int idio_16_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- return 0;
-}
-
-static int idio_16_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- chip->set(chip, offset, value);
- return 0;
-}
-
-static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
-}
-
-static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
-
- return 0;
-}
-
-static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
-}
-
-static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
-}
-
-static void idio_16_irq_ack(struct irq_data *data)
-{
-}
-
-static void idio_16_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- unsigned long flags;
-
- idio16gpio->irq_mask &= ~BIT(offset);
- gpiochip_disable_irq(chip, offset);
-
- if (!idio16gpio->irq_mask) {
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- iowrite8(0, &idio16gpio->reg->irq_ctl);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
- }
-}
-
-static void idio_16_irq_unmask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- const unsigned long prev_irq_mask = idio16gpio->irq_mask;
- unsigned long flags;
-
- gpiochip_enable_irq(chip, offset);
- idio16gpio->irq_mask |= BIT(offset);
-
- if (!prev_irq_mask) {
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- ioread8(&idio16gpio->reg->irq_ctl);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
- }
-}
-
-static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
- /* The only valid irq types are none and both-edges */
- if (flow_type != IRQ_TYPE_NONE &&
- (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct irq_chip idio_16_irqchip = {
- .name = "104-idio-16",
- .irq_ack = idio_16_irq_ack,
- .irq_mask = idio_16_irq_mask,
- .irq_unmask = idio_16_irq_unmask,
- .irq_set_type = idio_16_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+static const struct regmap_range idio_16_rd_ranges[] = {
+ regmap_reg_range(0x1, 0x2), regmap_reg_range(0x5, 0x5),
};
-
-static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
-{
- struct idio_16_gpio *const idio16gpio = dev_id;
- struct gpio_chip *const chip = &idio16gpio->chip;
- int gpio;
-
- for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
- generic_handle_domain_irq(chip->irq.domain, gpio);
-
- raw_spin_lock(&idio16gpio->lock);
-
- iowrite8(0, &idio16gpio->reg->in0_7);
-
- raw_spin_unlock(&idio16gpio->lock);
-
- return IRQ_HANDLED;
-}
-
-#define IDIO_16_NGPIO 32
-static const char *idio_16_names[IDIO_16_NGPIO] = {
- "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
- "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
- "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
- "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
+static const struct regmap_range idio_16_precious_ranges[] = {
+ regmap_reg_range(0x2, 0x2),
+};
+static const struct regmap_access_table idio_16_wr_table = {
+ .yes_ranges = idio_16_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_wr_ranges),
+};
+static const struct regmap_access_table idio_16_rd_table = {
+ .yes_ranges = idio_16_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_rd_ranges),
+};
+static const struct regmap_access_table idio_16_precious_table = {
+ .yes_ranges = idio_16_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_precious_ranges),
+};
+static const struct regmap_config idio_16_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &idio_16_wr_table,
+ .rd_table = &idio_16_rd_table,
+ .volatile_table = &idio_16_rd_table,
+ .precious_table = &idio_16_precious_table,
+ .cache_type = REGCACHE_FLAT,
+ .use_raw_spinlock = true,
};
-static int idio_16_irq_init_hw(struct gpio_chip *gc)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
-
- /* Disable IRQ by default */
- iowrite8(0, &idio16gpio->reg->irq_ctl);
- iowrite8(0, &idio16gpio->reg->in0_7);
+/* Only input lines (GPIO 16-31) support interrupts */
+#define IDIO_16_REGMAP_IRQ(_id) \
+ [16 + _id] = { \
+ .mask = BIT(_id), \
+ .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
+ }
- return 0;
-}
+static const struct regmap_irq idio_16_regmap_irqs[] = {
+ IDIO_16_REGMAP_IRQ(0), IDIO_16_REGMAP_IRQ(1), IDIO_16_REGMAP_IRQ(2), /* 0-2 */
+ IDIO_16_REGMAP_IRQ(3), IDIO_16_REGMAP_IRQ(4), IDIO_16_REGMAP_IRQ(5), /* 3-5 */
+ IDIO_16_REGMAP_IRQ(6), IDIO_16_REGMAP_IRQ(7), IDIO_16_REGMAP_IRQ(8), /* 6-8 */
+ IDIO_16_REGMAP_IRQ(9), IDIO_16_REGMAP_IRQ(10), IDIO_16_REGMAP_IRQ(11), /* 9-11 */
+ IDIO_16_REGMAP_IRQ(12), IDIO_16_REGMAP_IRQ(13), IDIO_16_REGMAP_IRQ(14), /* 12-14 */
+ IDIO_16_REGMAP_IRQ(15), /* 15 */
+};
static int idio_16_probe(struct device *dev, unsigned int id)
{
- struct idio_16_gpio *idio16gpio;
const char *const name = dev_name(dev);
- struct gpio_irq_chip *girq;
- int err;
-
- idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
- if (!idio16gpio)
- return -ENOMEM;
+ struct idio_16_regmap_config config = {};
+ void __iomem *regs;
+ struct regmap *map;
if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -224,54 +96,22 @@ static int idio_16_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
- idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
- if (!idio16gpio->reg)
+ regs = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
+ if (!regs)
return -ENOMEM;
- idio16gpio->chip.label = name;
- idio16gpio->chip.parent = dev;
- idio16gpio->chip.owner = THIS_MODULE;
- idio16gpio->chip.base = -1;
- idio16gpio->chip.ngpio = IDIO_16_NGPIO;
- idio16gpio->chip.names = idio_16_names;
- idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
- idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
- idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
- idio16gpio->chip.get = idio_16_gpio_get;
- idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
- idio16gpio->chip.set = idio_16_gpio_set;
- idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
-
- idio_16_state_init(&idio16gpio->state);
- /* FET off states are represented by bit values of "1" */
- bitmap_fill(idio16gpio->state.out_state, IDIO_16_NOUT);
-
- girq = &idio16gpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
- girq->init_hw = idio_16_irq_init_hw;
+ map = devm_regmap_init_mmio(dev, regs, &idio_16_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map), "Unable to initialize register map\n");
- raw_spin_lock_init(&idio16gpio->lock);
-
- err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
-
- err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
- idio16gpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- return err;
- }
+ config.parent = dev;
+ config.map = map;
+ config.regmap_irqs = idio_16_regmap_irqs;
+ config.num_regmap_irqs = ARRAY_SIZE(idio_16_regmap_irqs);
+ config.irq = irq[id];
+ config.no_status = true;
- return 0;
+ return devm_idio_16_regmap_register(dev, &config);
}
static struct isa_driver idio_16_driver = {
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 0464f1ecd20d..c7ac5a9ffb1f 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -135,8 +135,6 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev)
priv->gc.ngpio = MMIO_74XX_BIT_CNT(priv->flags);
priv->gc.owner = THIS_MODULE;
- platform_set_drvdata(pdev, priv);
-
return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
}
diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c
index be1ed7ee5225..11edf1fe6c90 100644
--- a/drivers/gpio/gpio-altera-a10sr.c
+++ b/drivers/gpio/gpio-altera-a10sr.c
@@ -9,6 +9,7 @@
#include <linux/gpio/driver.h>
#include <linux/mfd/altera-a10sr.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -104,7 +105,7 @@ static struct platform_driver altr_a10sr_gpio_driver = {
.probe = altr_a10sr_gpio_probe,
.driver = {
.name = "altr_a10sr_gpio",
- .of_match_table = of_match_ptr(altr_a10sr_gpio_of_match),
+ .of_match_table = altr_a10sr_gpio_of_match,
},
};
module_platform_driver(altr_a10sr_gpio_driver);
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index aa0a954b8392..f0c0c0f77eb0 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -9,8 +9,9 @@
*/
#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
#include <linux/platform_data/gpio-ath79.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/irq.h>
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 70770429ba48..5321ef98f442 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -8,12 +8,14 @@
#include <linux/bitops.h>
#include <linux/err.h>
-#include <linux/io.h>
#include <linux/gpio/driver.h>
-#include <linux/of_device.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#define BCM_GPIO_PASSWD 0x00a5a501
#define GPIO_PER_BANK 32
@@ -62,7 +64,6 @@ struct bcm_kona_gpio {
struct gpio_chip gpio_chip;
struct irq_domain *irq_domain;
struct bcm_kona_gpio_bank *banks;
- struct platform_device *pdev;
};
struct bcm_kona_gpio_bank {
@@ -556,19 +557,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio)
static int bcm_kona_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct of_device_id *match;
struct bcm_kona_gpio_bank *bank;
struct bcm_kona_gpio *kona_gpio;
struct gpio_chip *chip;
int ret;
int i;
- match = of_match_device(bcm_kona_gpio_of_match, dev);
- if (!match) {
- dev_err(dev, "Failed to find gpio controller\n");
- return -ENODEV;
- }
-
kona_gpio = devm_kzalloc(dev, sizeof(*kona_gpio), GFP_KERNEL);
if (!kona_gpio)
return -ENOMEM;
@@ -596,15 +590,13 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev)
if (!kona_gpio->banks)
return -ENOMEM;
- kona_gpio->pdev = pdev;
- platform_set_drvdata(pdev, kona_gpio);
chip->parent = dev;
chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK;
- kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node,
- chip->ngpio,
- &bcm_kona_irq_ops,
- kona_gpio);
+ kona_gpio->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ chip->ngpio,
+ &bcm_kona_irq_ops,
+ kona_gpio);
if (!kona_gpio->irq_domain) {
dev_err(dev, "Couldn't allocate IRQ domain\n");
return -ENXIO;
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 6566517fe0d8..bccdbfd5ec80 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -3,12 +3,12 @@
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
enum gio_reg_index {
GIO_REG_ODEN = 0,
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
index 75f6f8d4323e..d69a24dd4828 100644
--- a/drivers/gpio/gpio-clps711x.c
+++ b/drivers/gpio/gpio-clps711x.c
@@ -67,7 +67,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
}
-static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
+static const struct of_device_id clps711x_gpio_ids[] = {
{ .compatible = "cirrus,ep7209-gpio" },
{ }
};
@@ -76,7 +76,7 @@ MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
static struct platform_driver clps711x_gpio_driver = {
.driver = {
.name = "clps711x-gpio",
- .of_match_table = of_match_ptr(clps711x_gpio_ids),
+ .of_match_table = clps711x_gpio_ids,
},
.probe = clps711x_gpio_probe,
};
diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
index 789384c6e178..4968232f70f2 100644
--- a/drivers/gpio/gpio-creg-snps.c
+++ b/drivers/gpio/gpio-creg-snps.c
@@ -8,7 +8,7 @@
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#define MAX_GPIO 32
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index fff510d86e31..8db5717bdabe 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -236,7 +236,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
for (i = 0; i < nirq; i++) {
chips->irqs[i] = platform_get_irq(pdev, i);
if (chips->irqs[i] < 0)
- return dev_err_probe(dev, chips->irqs[i], "IRQ not populated\n");
+ return chips->irqs[i];
}
chips->chip.label = dev_name(dev);
diff --git a/drivers/gpio/gpio-ds4520.c b/drivers/gpio/gpio-ds4520.c
new file mode 100644
index 000000000000..1903deaef3e9
--- /dev/null
+++ b/drivers/gpio/gpio-ds4520.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Analog Devices, Inc.
+ * Driver for the DS4520 I/O Expander
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
+#include <linux/i2c.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define DS4520_PULLUP0 0xF0
+#define DS4520_IO_CONTROL0 0xF2
+#define DS4520_IO_STATUS0 0xF8
+
+static const struct regmap_config ds4520_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ds4520_gpio_probe(struct i2c_client *client)
+{
+ struct gpio_regmap_config config = { };
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+ u32 ngpio;
+ u32 base;
+ int ret;
+
+ ret = device_property_read_u32(dev, "reg", &base);
+ if (ret)
+ return dev_err_probe(dev, ret, "Missing 'reg' property.\n");
+
+ ret = device_property_read_u32(dev, "ngpios", &ngpio);
+ if (ret)
+ return dev_err_probe(dev, ret, "Missing 'ngpios' property.\n");
+
+ regmap = devm_regmap_init_i2c(client, &ds4520_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to allocate register map\n");
+
+ config.regmap = regmap;
+ config.parent = dev;
+ config.ngpio = ngpio;
+
+ config.reg_dat_base = base + DS4520_IO_STATUS0;
+ config.reg_set_base = base + DS4520_PULLUP0;
+ config.reg_dir_out_base = base + DS4520_IO_CONTROL0;
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config));
+}
+
+static const struct of_device_id ds4520_gpio_of_match_table[] = {
+ { .compatible = "adi,ds4520-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds4520_gpio_of_match_table);
+
+static const struct i2c_device_id ds4520_gpio_id_table[] = {
+ { "ds4520-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds4520_gpio_id_table);
+
+static struct i2c_driver ds4520_gpio_driver = {
+ .driver = {
+ .name = "ds4520-gpio",
+ .of_match_table = ds4520_gpio_of_match_table,
+ },
+ .probe = ds4520_gpio_probe,
+ .id_table = ds4520_gpio_id_table,
+};
+module_i2c_driver(ds4520_gpio_driver);
+
+MODULE_DESCRIPTION("DS4520 I/O Expander");
+MODULE_AUTHOR("Okan Sahin <okan.sahin@analog.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
index 84352a6f4973..5320cf1de89c 100644
--- a/drivers/gpio/gpio-eic-sprd.c
+++ b/drivers/gpio/gpio-eic-sprd.c
@@ -9,7 +9,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -653,7 +653,6 @@ static int sprd_eic_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, sprd_eic);
return 0;
}
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index df1bdaae441c..5170fe7599cd 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -217,8 +217,6 @@ static int gpio_exar_probe(struct platform_device *pdev)
if (ret)
return ret;
- platform_set_drvdata(pdev, exar_gpio);
-
return 0;
}
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index 31e26072f6ae..5ce59dcf02e3 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -250,8 +250,8 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
return PTR_ERR(g->base);
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return irq ? irq : -EINVAL;
+ if (irq < 0)
+ return irq;
g->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(g->clk)) {
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index 7bd4c2a4cc11..5dc49648d8e3 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -1,29 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for GE FPGA based GPIO
*
* Author: Martyn Welch <martyn.welch@ge.com>
*
* 2008 (c) GE Intelligent Platforms Embedded Systems, 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.
*/
-/* TODO
+/*
+ * TODO:
*
- * Configuration of output modes (totem-pole/open-drain)
- * Interrupt configuration - interrupts are always generated the FPGA relies on
- * the I/O interrupt controllers mask to stop them propergating
+ * Configuration of output modes (totem-pole/open-drain).
+ * Interrupt configuration - interrupts are always generated, the FPGA relies
+ * on the I/O interrupt controllers mask to stop them from being propagated.
*/
-#include <linux/kernel.h>
+#include <linux/gpio/driver.h>
#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
#define GEF_GPIO_DIRECT 0x00
#define GEF_GPIO_IN 0x04
@@ -52,46 +51,39 @@ MODULE_DEVICE_TABLE(of, gef_gpio_ids);
static int __init gef_gpio_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct gpio_chip *gc;
void __iomem *regs;
int ret;
- gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
- regs = of_iomap(pdev->dev.of_node, 0);
- if (!regs)
- return -ENOMEM;
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
- ret = bgpio_init(gc, &pdev->dev, 4, regs + GEF_GPIO_IN,
- regs + GEF_GPIO_OUT, NULL, NULL,
- regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER);
- if (ret) {
- dev_err(&pdev->dev, "bgpio_init failed\n");
- goto err0;
- }
+ ret = bgpio_init(gc, dev, 4, regs + GEF_GPIO_IN, regs + GEF_GPIO_OUT,
+ NULL, NULL, regs + GEF_GPIO_DIRECT,
+ BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ if (ret)
+ return dev_err_probe(dev, ret, "bgpio_init failed\n");
/* Setup pointers to chip functions */
- gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
- if (!gc->label) {
- ret = -ENOMEM;
- goto err0;
- }
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
+ if (!gc->label)
+ return -ENOMEM;
gc->base = -1;
- gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev);
+ gc->ngpio = (uintptr_t)device_get_match_data(dev);
/* This function adds a memory mapped GPIO chip */
- ret = devm_gpiochip_add_data(&pdev->dev, gc, NULL);
+ ret = devm_gpiochip_add_data(dev, gc, NULL);
if (ret)
- goto err0;
+ return dev_err_probe(dev, ret, "GPIO chip registration failed\n");
return 0;
-err0:
- iounmap(regs);
- pr_err("%pOF: GPIO chip registration failed\n", pdev->dev.of_node);
- return ret;
};
static struct platform_driver gef_gpio_driver = {
@@ -103,5 +95,5 @@ static struct platform_driver gef_gpio_driver = {
module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe);
MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
-MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index bea0e32c195d..0163c95f6dd7 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -19,10 +19,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/err.h>
diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c
index c208ac1c54a6..1bcfc1835dae 100644
--- a/drivers/gpio/gpio-hlwd.c
+++ b/drivers/gpio/gpio-hlwd.c
@@ -10,7 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
diff --git a/drivers/gpio/gpio-idio-16.c b/drivers/gpio/gpio-idio-16.c
index 13315242d220..53b1eb876a12 100644
--- a/drivers/gpio/gpio-idio-16.c
+++ b/drivers/gpio/gpio-idio-16.c
@@ -3,143 +3,169 @@
* GPIO library for the ACCES IDIO-16 family
* Copyright (C) 2022 William Breathitt Gray
*/
-#include <linux/bitmap.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/export.h>
-#include <linux/io.h>
+#include <linux/gpio/regmap.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
#include "gpio-idio-16.h"
#define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16
-/**
- * idio_16_get - get signal value at signal offset
- * @reg: ACCES IDIO-16 device registers
- * @state: ACCES IDIO-16 device state
- * @offset: offset of signal to get
- *
- * Returns the signal value (0=low, 1=high) for the signal at @offset.
- */
-int idio_16_get(struct idio_16 __iomem *const reg,
- struct idio_16_state *const state, const unsigned long offset)
-{
- const unsigned long mask = BIT(offset);
-
- if (offset < IDIO_16_NOUT)
- return test_bit(offset, state->out_state);
-
- if (offset < 24)
- return !!(ioread8(&reg->in0_7) & (mask >> IDIO_16_NOUT));
-
- if (offset < 32)
- return !!(ioread8(&reg->in8_15) & (mask >> 24));
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(idio_16_get);
-
-/**
- * idio_16_get_multiple - get multiple signal values at multiple signal offsets
- * @reg: ACCES IDIO-16 device registers
- * @state: ACCES IDIO-16 device state
- * @mask: mask of signals to get
- * @bits: bitmap to store signal values
- *
- * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask.
- */
-void idio_16_get_multiple(struct idio_16 __iomem *const reg,
- struct idio_16_state *const state,
- const unsigned long *const mask,
- unsigned long *const bits)
+#define IDIO_16_DAT_BASE 0x0
+#define IDIO_16_OUT_BASE IDIO_16_DAT_BASE
+#define IDIO_16_IN_BASE (IDIO_16_DAT_BASE + 1)
+#define IDIO_16_CLEAR_INTERRUPT 0x1
+#define IDIO_16_ENABLE_IRQ 0x2
+#define IDIO_16_DEACTIVATE_INPUT_FILTERS 0x3
+#define IDIO_16_DISABLE_IRQ IDIO_16_ENABLE_IRQ
+#define IDIO_16_INTERRUPT_STATUS 0x6
+
+#define IDIO_16_NGPIO 32
+#define IDIO_16_NGPIO_PER_REG 8
+#define IDIO_16_REG_STRIDE 4
+
+struct idio_16_data {
+ struct regmap *map;
+ unsigned int irq_mask;
+};
+
+static int idio_16_handle_mask_sync(const int index, const unsigned int mask_buf_def,
+ const unsigned int mask_buf, void *const irq_drv_data)
{
- unsigned long flags;
- const unsigned long out_mask = GENMASK(IDIO_16_NOUT - 1, 0);
-
- spin_lock_irqsave(&state->lock, flags);
-
- bitmap_replace(bits, bits, state->out_state, &out_mask, IDIO_16_NOUT);
- if (*mask & GENMASK(23, 16))
- bitmap_set_value8(bits, ioread8(&reg->in0_7), 16);
- if (*mask & GENMASK(31, 24))
- bitmap_set_value8(bits, ioread8(&reg->in8_15), 24);
-
- spin_unlock_irqrestore(&state->lock, flags);
+ struct idio_16_data *const data = irq_drv_data;
+ const unsigned int prev_mask = data->irq_mask;
+ int err;
+ unsigned int val;
+
+ /* exit early if no change since the previous mask */
+ if (mask_buf == prev_mask)
+ return 0;
+
+ /* remember the current mask for the next mask sync */
+ data->irq_mask = mask_buf;
+
+ /* if all previously masked, enable interrupts when unmasking */
+ if (prev_mask == mask_buf_def) {
+ err = regmap_write(data->map, IDIO_16_CLEAR_INTERRUPT, 0x00);
+ if (err)
+ return err;
+ return regmap_read(data->map, IDIO_16_ENABLE_IRQ, &val);
+ }
+
+ /* if all are currently masked, disable interrupts */
+ if (mask_buf == mask_buf_def)
+ return regmap_write(data->map, IDIO_16_DISABLE_IRQ, 0x00);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(idio_16_get_multiple);
-/**
- * idio_16_set - set signal value at signal offset
- * @reg: ACCES IDIO-16 device registers
- * @state: ACCES IDIO-16 device state
- * @offset: offset of signal to set
- * @value: value of signal to set
- *
- * Assigns output @value for the signal at @offset.
- */
-void idio_16_set(struct idio_16 __iomem *const reg,
- struct idio_16_state *const state, const unsigned long offset,
- const unsigned long value)
+static int idio_16_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
+ const unsigned int offset, unsigned int *const reg,
+ unsigned int *const mask)
{
- unsigned long flags;
-
- if (offset >= IDIO_16_NOUT)
- return;
+ unsigned int stride;
- spin_lock_irqsave(&state->lock, flags);
+ /* Input lines start at GPIO 16 */
+ if (offset < 16) {
+ stride = offset / IDIO_16_NGPIO_PER_REG;
+ *reg = IDIO_16_OUT_BASE + stride * IDIO_16_REG_STRIDE;
+ } else {
+ stride = (offset - 16) / IDIO_16_NGPIO_PER_REG;
+ *reg = IDIO_16_IN_BASE + stride * IDIO_16_REG_STRIDE;
+ }
- __assign_bit(offset, state->out_state, value);
- if (offset < 8)
- iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
- else
- iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
+ *mask = BIT(offset % IDIO_16_NGPIO_PER_REG);
- spin_unlock_irqrestore(&state->lock, flags);
+ return 0;
}
-EXPORT_SYMBOL_GPL(idio_16_set);
-
-/**
- * idio_16_set_multiple - set signal values at multiple signal offsets
- * @reg: ACCES IDIO-16 device registers
- * @state: ACCES IDIO-16 device state
- * @mask: mask of signals to set
- * @bits: bitmap of signal output values
- *
- * Assigns output values defined by @bits for the signals defined by @mask.
- */
-void idio_16_set_multiple(struct idio_16 __iomem *const reg,
- struct idio_16_state *const state,
- const unsigned long *const mask,
- const unsigned long *const bits)
-{
- unsigned long flags;
- spin_lock_irqsave(&state->lock, flags);
-
- bitmap_replace(state->out_state, state->out_state, bits, mask,
- IDIO_16_NOUT);
- if (*mask & GENMASK(7, 0))
- iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
- if (*mask & GENMASK(15, 8))
- iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
-
- spin_unlock_irqrestore(&state->lock, flags);
-}
-EXPORT_SYMBOL_GPL(idio_16_set_multiple);
+static const char *idio_16_names[IDIO_16_NGPIO] = {
+ "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
+ "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
+ "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
+ "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
+};
/**
- * idio_16_state_init - initialize idio_16_state structure
- * @state: ACCES IDIO-16 device state
+ * devm_idio_16_regmap_register - Register an IDIO-16 GPIO device
+ * @dev: device that is registering this IDIO-16 GPIO device
+ * @config: configuration for idio_16_regmap_config
*
- * Initializes the ACCES IDIO-16 device @state for use in idio-16 library
- * functions.
+ * Registers an IDIO-16 GPIO device. Returns 0 on success and negative error number on failure.
*/
-void idio_16_state_init(struct idio_16_state *const state)
+int devm_idio_16_regmap_register(struct device *const dev,
+ const struct idio_16_regmap_config *const config)
{
- spin_lock_init(&state->lock);
+ struct gpio_regmap_config gpio_config = {};
+ int err;
+ struct idio_16_data *data;
+ struct regmap_irq_chip *chip;
+ struct regmap_irq_chip_data *chip_data;
+
+ if (!config->parent)
+ return -EINVAL;
+
+ if (!config->map)
+ return -EINVAL;
+
+ if (!config->regmap_irqs)
+ return -EINVAL;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ data->map = config->map;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->name = dev_name(dev);
+ chip->status_base = IDIO_16_INTERRUPT_STATUS;
+ chip->mask_base = IDIO_16_ENABLE_IRQ;
+ chip->ack_base = IDIO_16_CLEAR_INTERRUPT;
+ chip->no_status = config->no_status;
+ chip->num_regs = 1;
+ chip->irqs = config->regmap_irqs;
+ chip->num_irqs = config->num_regmap_irqs;
+ chip->handle_mask_sync = idio_16_handle_mask_sync;
+ chip->irq_drv_data = data;
+
+ /* Disable IRQ to prevent spurious interrupts before we're ready */
+ err = regmap_write(data->map, IDIO_16_DISABLE_IRQ, 0x00);
+ if (err)
+ return err;
+
+ err = devm_regmap_add_irq_chip(dev, data->map, config->irq, 0, 0, chip, &chip_data);
+ if (err)
+ return dev_err_probe(dev, err, "IRQ registration failed\n");
+
+ if (config->filters) {
+ /* Deactivate input filters */
+ err = regmap_write(data->map, IDIO_16_DEACTIVATE_INPUT_FILTERS, 0x00);
+ if (err)
+ return err;
+ }
+
+ gpio_config.parent = config->parent;
+ gpio_config.regmap = data->map;
+ gpio_config.ngpio = IDIO_16_NGPIO;
+ gpio_config.names = idio_16_names;
+ gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_16_DAT_BASE);
+ gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_16_DAT_BASE);
+ gpio_config.ngpio_per_reg = IDIO_16_NGPIO_PER_REG;
+ gpio_config.reg_stride = IDIO_16_REG_STRIDE;
+ gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
+ gpio_config.reg_mask_xlate = idio_16_reg_mask_xlate;
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
}
-EXPORT_SYMBOL_GPL(idio_16_state_init);
+EXPORT_SYMBOL_GPL(devm_idio_16_regmap_register);
MODULE_AUTHOR("William Breathitt Gray");
MODULE_DESCRIPTION("ACCES IDIO-16 GPIO Library");
diff --git a/drivers/gpio/gpio-idio-16.h b/drivers/gpio/gpio-idio-16.h
index 928f8251a2bd..93b08ad73065 100644
--- a/drivers/gpio/gpio-idio-16.h
+++ b/drivers/gpio/gpio-idio-16.h
@@ -3,69 +3,30 @@
#ifndef _IDIO_16_H_
#define _IDIO_16_H_
-#include <linux/spinlock.h>
-#include <linux/types.h>
+struct device;
+struct regmap;
+struct regmap_irq;
/**
- * struct idio_16 - IDIO-16 registers structure
- * @out0_7: Read: FET Drive Outputs 0-7
- * Write: FET Drive Outputs 0-7
- * @in0_7: Read: Isolated Inputs 0-7
- * Write: Clear Interrupt
- * @irq_ctl: Read: Enable IRQ
- * Write: Disable IRQ
- * @filter_ctl: Read: Activate Input Filters 0-15
- * Write: Deactivate Input Filters 0-15
- * @out8_15: Read: FET Drive Outputs 8-15
- * Write: FET Drive Outputs 8-15
- * @in8_15: Read: Isolated Inputs 8-15
- * Write: Unused
- * @irq_status: Read: Interrupt status
- * Write: Unused
+ * struct idio_16_regmap_config - Configuration for the IDIO-16 register map
+ * @parent: parent device
+ * @map: regmap for the IDIO-16 device
+ * @regmap_irqs: descriptors for individual IRQs
+ * @num_regmap_irqs: number of IRQ descriptors
+ * @irq: IRQ number for the IDIO-16 device
+ * @no_status: device has no status register
+ * @filters: device has input filters
*/
-struct idio_16 {
- u8 out0_7;
- u8 in0_7;
- u8 irq_ctl;
- u8 filter_ctl;
- u8 out8_15;
- u8 in8_15;
- u8 irq_status;
+struct idio_16_regmap_config {
+ struct device *parent;
+ struct regmap *map;
+ const struct regmap_irq *regmap_irqs;
+ int num_regmap_irqs;
+ unsigned int irq;
+ bool no_status;
+ bool filters;
};
-#define IDIO_16_NOUT 16
-
-/**
- * struct idio_16_state - IDIO-16 state structure
- * @lock: synchronization lock for accessing device state
- * @out_state: output signals state
- */
-struct idio_16_state {
- spinlock_t lock;
- DECLARE_BITMAP(out_state, IDIO_16_NOUT);
-};
-
-/**
- * idio_16_get_direction - get the I/O direction for a signal offset
- * @offset: offset of signal to get direction
- *
- * Returns the signal direction (0=output, 1=input) for the signal at @offset.
- */
-static inline int idio_16_get_direction(const unsigned long offset)
-{
- return (offset >= IDIO_16_NOUT) ? 1 : 0;
-}
-
-int idio_16_get(struct idio_16 __iomem *reg, struct idio_16_state *state,
- unsigned long offset);
-void idio_16_get_multiple(struct idio_16 __iomem *reg,
- struct idio_16_state *state,
- const unsigned long *mask, unsigned long *bits);
-void idio_16_set(struct idio_16 __iomem *reg, struct idio_16_state *state,
- unsigned long offset, unsigned long value);
-void idio_16_set_multiple(struct idio_16 __iomem *reg,
- struct idio_16_state *state,
- const unsigned long *mask, const unsigned long *bits);
-void idio_16_state_init(struct idio_16_state *state);
+int devm_idio_16_regmap_register(struct device *dev, const struct idio_16_regmap_config *config);
#endif /* _IDIO_16_H_ */
diff --git a/drivers/gpio/gpio-imx-scu.c b/drivers/gpio/gpio-imx-scu.c
index e190bde5397d..13baf465aedf 100644
--- a/drivers/gpio/gpio-imx-scu.c
+++ b/drivers/gpio/gpio-imx-scu.c
@@ -6,6 +6,7 @@
* to control the PIN resources on SCU domain.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
@@ -103,7 +104,7 @@ static int imx_scu_gpio_probe(struct platform_device *pdev)
gc = &priv->chip;
gc->base = -1;
gc->parent = dev;
- gc->ngpio = sizeof(scu_rsrc_arr)/sizeof(unsigned int);
+ gc->ngpio = ARRAY_SIZE(scu_rsrc_arr);
gc->label = dev_name(dev);
gc->get = imx_scu_gpio_get;
gc->set = imx_scu_gpio_set;
diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c
index 1e29de1671d4..dde6cf3a5779 100644
--- a/drivers/gpio/gpio-ixp4xx.c
+++ b/drivers/gpio/gpio-ixp4xx.c
@@ -302,7 +302,7 @@ static const struct of_device_id ixp4xx_gpio_of_match[] = {
static struct platform_driver ixp4xx_gpio_driver = {
.driver = {
.name = "ixp4xx-gpio",
- .of_match_table = of_match_ptr(ixp4xx_gpio_of_match),
+ .of_match_table = ixp4xx_gpio_of_match,
},
.probe = ixp4xx_gpio_probe,
};
diff --git a/drivers/gpio/gpio-logicvc.c b/drivers/gpio/gpio-logicvc.c
index 992cc958a43f..05d62011f335 100644
--- a/drivers/gpio/gpio-logicvc.c
+++ b/drivers/gpio/gpio-logicvc.c
@@ -8,7 +8,6 @@
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -139,8 +138,6 @@ static int logicvc_gpio_probe(struct platform_device *pdev)
logicvc->chip.set = logicvc_gpio_set;
logicvc->chip.direction_output = logicvc_gpio_direction_output;
- platform_set_drvdata(pdev, logicvc);
-
return devm_gpiochip_add_data(dev, &logicvc->chip, logicvc);
}
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
index 79edd5db49d2..8e58242f5123 100644
--- a/drivers/gpio/gpio-lp3943.c
+++ b/drivers/gpio/gpio-lp3943.c
@@ -199,8 +199,6 @@ static int lp3943_gpio_probe(struct platform_device *pdev)
lp3943_gpio->chip = lp3943_gpio_chip;
lp3943_gpio->chip.parent = &pdev->dev;
- platform_set_drvdata(pdev, lp3943_gpio);
-
return devm_gpiochip_add_data(&pdev->dev, &lp3943_gpio->chip,
lp3943_gpio);
}
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index d2b65cfb336e..5ef8af824980 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -525,17 +525,15 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id lpc32xx_gpio_of_match[] = {
{ .compatible = "nxp,lpc3220-gpio", },
{ },
};
-#endif
static struct platform_driver lpc32xx_gpio_driver = {
.driver = {
.name = "lpc32xx-gpio",
- .of_match_table = of_match_ptr(lpc32xx_gpio_of_match),
+ .of_match_table = lpc32xx_gpio_of_match,
},
.probe = lpc32xx_gpio_probe,
};
diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c
index 161c4751c5f7..bbacc714632b 100644
--- a/drivers/gpio/gpio-max3191x.c
+++ b/drivers/gpio/gpio-max3191x.c
@@ -457,7 +457,6 @@ static int __init max3191x_register_driver(struct spi_driver *sdrv)
return spi_register_driver(sdrv);
}
-#ifdef CONFIG_OF
static const struct of_device_id max3191x_of_id[] = {
{ .compatible = "maxim,max31910" },
{ .compatible = "maxim,max31911" },
@@ -468,7 +467,6 @@ static const struct of_device_id max3191x_of_id[] = {
{ }
};
MODULE_DEVICE_TABLE(of, max3191x_of_id);
-#endif
static const struct spi_device_id max3191x_spi_id[] = {
{ "max31910" },
@@ -484,7 +482,7 @@ MODULE_DEVICE_TABLE(spi, max3191x_spi_id);
static struct spi_driver max3191x_driver = {
.driver = {
.name = "max3191x",
- .of_match_table = of_match_ptr(max3191x_of_id),
+ .of_match_table = max3191x_of_id,
},
.probe = max3191x_probe,
.remove = max3191x_remove,
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index fca9ca68e387..49d362907bc7 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -18,8 +18,6 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/platform_data/max732x.h>
-#include <linux/of.h>
-
/*
* Each port of MAX732x (including MAX7319) falls into one of the
@@ -114,7 +112,6 @@ static const struct i2c_device_id max732x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max732x_id);
-#ifdef CONFIG_OF
static const struct of_device_id max732x_of_table[] = {
{ .compatible = "maxim,max7319" },
{ .compatible = "maxim,max7320" },
@@ -128,7 +125,6 @@ static const struct of_device_id max732x_of_table[] = {
{ }
};
MODULE_DEVICE_TABLE(of, max732x_of_table);
-#endif
struct max732x_chip {
struct gpio_chip gpio_chip;
@@ -709,7 +705,7 @@ static int max732x_probe(struct i2c_client *client)
static struct i2c_driver max732x_driver = {
.driver = {
.name = "max732x",
- .of_match_table = of_match_ptr(max732x_of_table),
+ .of_match_table = max732x_of_table,
},
.probe = max732x_probe,
.id_table = max732x_id,
diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c
index c18b60e39a94..8c2a5609161f 100644
--- a/drivers/gpio/gpio-max77620.c
+++ b/drivers/gpio/gpio-max77620.c
@@ -331,8 +331,6 @@ static int max77620_gpio_probe(struct platform_device *pdev)
girq->init_hw = max77620_gpio_irq_init_hw;
girq->threaded = true;
- platform_set_drvdata(pdev, mgpio);
-
ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio);
if (ret < 0) {
dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n");
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index 37c5363e391e..ca7eb5e8bfaa 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -10,11 +10,11 @@
#include <linux/io.h>
#include <linux/init.h>
#include <linux/clk.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/of_device.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c
index e30cee108986..7a3e1760fc5b 100644
--- a/drivers/gpio/gpio-mlxbf3.c
+++ b/drivers/gpio/gpio-mlxbf3.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
/* Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES */
#include <linux/bitfield.h>
@@ -19,6 +19,8 @@
* gpio[1]: HOST_GPIO32->HOST_GPIO55
*/
#define MLXBF3_GPIO_MAX_PINS_PER_BLOCK 32
+#define MLXBF3_GPIO_MAX_PINS_BLOCK0 32
+#define MLXBF3_GPIO_MAX_PINS_BLOCK1 24
/*
* fw_gpio[x] block registers and their offset
@@ -158,6 +160,26 @@ static const struct irq_chip gpio_mlxbf3_irqchip = {
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
+static int mlxbf3_gpio_add_pin_ranges(struct gpio_chip *chip)
+{
+ unsigned int id;
+
+ switch(chip->ngpio) {
+ case MLXBF3_GPIO_MAX_PINS_BLOCK0:
+ id = 0;
+ break;
+ case MLXBF3_GPIO_MAX_PINS_BLOCK1:
+ id = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return gpiochip_add_pin_range(chip, "MLNXBF34:00",
+ chip->base, id * MLXBF3_GPIO_MAX_PINS_PER_BLOCK,
+ chip->ngpio);
+}
+
static int mlxbf3_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -197,6 +219,7 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev)
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
gc->owner = THIS_MODULE;
+ gc->add_pin_ranges = mlxbf3_gpio_add_pin_ranges;
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
@@ -243,6 +266,7 @@ static struct platform_driver mlxbf3_gpio_driver = {
};
module_platform_driver(mlxbf3_gpio_driver);
+MODULE_SOFTDEP("pre: pinctrl-mlxbf3");
MODULE_DESCRIPTION("NVIDIA BlueField-3 GPIO Driver");
MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index d9dff3dc92ae..74fdf0d87b2c 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -60,6 +60,8 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/of.h>
#include <linux/of_device.h>
+#include "gpiolib.h"
+
static void bgpio_write8(void __iomem *reg, unsigned long data)
{
writeb(data, reg);
@@ -614,10 +616,15 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
gc->parent = dev;
gc->label = dev_name(dev);
gc->base = -1;
- gc->ngpio = gc->bgpio_bits;
gc->request = bgpio_request;
gc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN);
+ ret = gpiochip_get_ngpios(gc, dev);
+ if (ret)
+ gc->ngpio = gc->bgpio_bits;
+ else
+ gc->bgpio_bits = roundup_pow_of_two(round_up(gc->ngpio, 8));
+
ret = bgpio_setup_io(gc, dat, set, clr, flags);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 3b0bfff8c778..b49e3ca64015 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -10,7 +10,7 @@
#include <linux/slab.h>
#include <linux/gpio/legacy-of-mm-gpiochip.h>
#include <linux/io.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <asm/mpc52xx.h>
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 5979a36bf754..ebf2f511df59 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -9,12 +9,10 @@
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/property.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c
index 036ad2324892..2f448eb23abb 100644
--- a/drivers/gpio/gpio-msc313.c
+++ b/drivers/gpio/gpio-msc313.c
@@ -6,7 +6,6 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 9d0cec4b82a3..4cb455b2bdee 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -17,12 +17,12 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/syscore_ops.h>
#include <linux/gpio/driver.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/bug.h>
#define IMX_SCU_WAKEUP_OFF 0
@@ -62,6 +62,7 @@ struct mxc_gpio_port {
struct clk *clk;
int irq;
int irq_high;
+ void (*mx_irq_handler)(struct irq_desc *desc);
struct irq_domain *domain;
struct gpio_chip gc;
struct device *dev;
@@ -382,6 +383,41 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return irq_find_mapping(port->domain, offset);
}
+static int mxc_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ int ret;
+
+ ret = gpiochip_generic_request(chip, offset);
+ if (ret)
+ return ret;
+
+ return pm_runtime_resume_and_get(chip->parent);
+}
+
+static void mxc_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ gpiochip_generic_free(chip, offset);
+ pm_runtime_put(chip->parent);
+}
+
+static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enable)
+{
+ if (enable)
+ irq_set_chained_handler_and_data(port->irq, port->mx_irq_handler, port);
+ else
+ irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+ /* setup handler for GPIO 16 to 31 */
+ if (port->irq_high > 0) {
+ if (enable)
+ irq_set_chained_handler_and_data(port->irq_high,
+ port->mx_irq_handler,
+ port);
+ else
+ irq_set_chained_handler_and_data(port->irq_high, NULL, NULL);
+ }
+}
+
static int mxc_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -416,19 +452,17 @@ static int mxc_gpio_probe(struct platform_device *pdev)
return port->irq;
/* the controller clock is optional */
- port->clk = devm_clk_get_optional(&pdev->dev, NULL);
+ port->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(port->clk))
return PTR_ERR(port->clk);
- err = clk_prepare_enable(port->clk);
- if (err) {
- dev_err(&pdev->dev, "Unable to enable clock.\n");
- return err;
- }
-
if (of_device_is_compatible(np, "fsl,imx7d-gpio"))
port->power_off = true;
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
/* disable the interrupt and clear the status */
writel(0, port->base + GPIO_IMR);
writel(~0, port->base + GPIO_ISR);
@@ -439,18 +473,12 @@ static int mxc_gpio_probe(struct platform_device *pdev)
* the handler is needed only once, but doing it for every port
* is more robust and easier.
*/
- irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
- } else {
- /* setup one handler for each entry */
- irq_set_chained_handler_and_data(port->irq,
- mx3_gpio_irq_handler, port);
- if (port->irq_high > 0)
- /* setup handler for GPIO 16 to 31 */
- irq_set_chained_handler_and_data(port->irq_high,
- mx3_gpio_irq_handler,
- port);
- }
+ port->irq_high = -1;
+ port->mx_irq_handler = mx2_gpio_irq_handler;
+ } else
+ port->mx_irq_handler = mx3_gpio_irq_handler;
+ mxc_update_irq_chained_handler(port, true);
err = bgpio_init(&port->gc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
@@ -459,8 +487,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (err)
goto out_bgio;
- port->gc.request = gpiochip_generic_request;
- port->gc.free = gpiochip_generic_free;
+ port->gc.request = mxc_gpio_request;
+ port->gc.free = mxc_gpio_free;
port->gc.to_irq = mxc_gpio_to_irq;
port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
pdev->id * 32;
@@ -482,6 +510,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
goto out_bgio;
}
+ irq_domain_set_pm_device(port->domain, &pdev->dev);
+
/* gpio-mxc can be a generic irq chip */
err = mxc_gpio_init_gc(port, irq_base);
if (err < 0)
@@ -490,13 +520,15 @@ static int mxc_gpio_probe(struct platform_device *pdev)
list_add_tail(&port->node, &mxc_gpio_ports);
platform_set_drvdata(pdev, port);
+ pm_runtime_put_autosuspend(&pdev->dev);
return 0;
out_irqdomain_remove:
irq_domain_remove(port->domain);
out_bgio:
- clk_disable_unprepare(port->clk);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
return err;
}
@@ -572,7 +604,35 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
return ret;
}
-static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
+static int mxc_gpio_runtime_suspend(struct device *dev)
+{
+ struct mxc_gpio_port *port = dev_get_drvdata(dev);
+
+ mxc_gpio_save_regs(port);
+ clk_disable_unprepare(port->clk);
+ mxc_update_irq_chained_handler(port, false);
+
+ return 0;
+}
+
+static int mxc_gpio_runtime_resume(struct device *dev)
+{
+ struct mxc_gpio_port *port = dev_get_drvdata(dev);
+ int ret;
+
+ mxc_update_irq_chained_handler(port, true);
+ ret = clk_prepare_enable(port->clk);
+ if (ret) {
+ mxc_update_irq_chained_handler(port, false);
+ return ret;
+ }
+
+ mxc_gpio_restore_regs(port);
+
+ return 0;
+}
+
+static int mxc_gpio_noirq_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
@@ -583,7 +643,7 @@ static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
+static int mxc_gpio_noirq_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mxc_gpio_port *port = platform_get_drvdata(pdev);
@@ -596,15 +656,20 @@ static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
}
static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
+ RUNTIME_PM_OPS(mxc_gpio_runtime_suspend, mxc_gpio_runtime_resume, NULL)
};
static int mxc_gpio_syscore_suspend(void)
{
struct mxc_gpio_port *port;
+ int ret;
/* walk through all ports */
list_for_each_entry(port, &mxc_gpio_ports, node) {
+ ret = clk_prepare_enable(port->clk);
+ if (ret)
+ return ret;
mxc_gpio_save_regs(port);
clk_disable_unprepare(port->clk);
}
@@ -625,6 +690,7 @@ static void mxc_gpio_syscore_resume(void)
return;
}
mxc_gpio_restore_regs(port);
+ clk_disable_unprepare(port->clk);
}
}
@@ -638,7 +704,7 @@ static struct platform_driver mxc_gpio_driver = {
.name = "gpio-mxc",
.of_match_table = mxc_gpio_dt_ids,
.suppress_bind_attrs = true,
- .pm = &mxc_gpio_dev_pm_ops,
+ .pm = pm_ptr(&mxc_gpio_dev_pm_ops),
},
.probe = mxc_gpio_probe,
};
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 390e619a2831..024ad077e98d 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -14,7 +14,6 @@
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
@@ -272,7 +271,7 @@ static int mxs_gpio_probe(struct platform_device *pdev)
port->id = of_alias_get_id(np, "gpio");
if (port->id < 0)
return port->id;
- port->devid = (enum mxs_gpio_id)of_device_get_match_data(&pdev->dev);
+ port->devid = (uintptr_t)of_device_get_match_data(&pdev->dev);
port->dev = &pdev->dev;
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index a08be5bf6808..a927680c66f8 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -22,7 +22,6 @@
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/gpio/driver.h>
#include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h>
@@ -1413,11 +1412,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->dev = dev;
bank->irq = platform_get_irq(pdev, 0);
- if (bank->irq <= 0) {
- if (!bank->irq)
- bank->irq = -ENXIO;
- return dev_err_probe(dev, bank->irq, "can't get irq resource\n");
- }
+ if (bank->irq < 0)
+ return bank->irq;
bank->chip.parent = dev;
bank->chip.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index bac10c2faf56..28dba7048509 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/mfd/palmas.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
struct palmas_gpio {
@@ -184,7 +183,6 @@ static int palmas_gpio_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, palmas_gpio);
return ret;
}
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index a806a3c1b801..bdd50a78e414 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -108,6 +108,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
+ { "tca9538", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
{ "xra1202", 8 | PCA953X_TYPE },
@@ -1051,7 +1052,6 @@ out:
static int pca953x_probe(struct i2c_client *client)
{
- const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client);
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
int irq_base = 0;
@@ -1090,6 +1090,9 @@ static int pca953x_probe(struct i2c_client *client)
}
chip->client = client;
+ chip->driver_data = (uintptr_t)i2c_get_match_data(client);
+ if (!chip->driver_data)
+ return -ENODEV;
reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(reg))
@@ -1102,20 +1105,6 @@ static int pca953x_probe(struct i2c_client *client)
}
chip->regulator = reg;
- if (i2c_id) {
- chip->driver_data = i2c_id->driver_data;
- } else {
- const void *match;
-
- match = device_get_match_data(&client->dev);
- if (!match) {
- ret = -ENODEV;
- goto err_exit;
- }
-
- chip->driver_data = (uintptr_t)match;
- }
-
i2c_set_clientdata(client, chip);
pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
@@ -1354,6 +1343,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+ { .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), },
{ .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index d8db80ef1293..d37ba4049368 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -30,7 +30,7 @@ struct pca9570_chip_data {
/**
* struct pca9570 - GPIO driver data
* @chip: GPIO controller chip
- * @p_data: GPIO controller platform data
+ * @chip_data: GPIO controller platform data
* @lock: Protects write sequences
* @out: Buffer for device register
*/
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index c4c785548408..53b69abe6787 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -36,19 +36,19 @@ static const struct i2c_device_id pcf857x_id[] = {
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
static const struct of_device_id pcf857x_of_table[] = {
- { .compatible = "nxp,pcf8574" },
- { .compatible = "nxp,pcf8574a" },
- { .compatible = "nxp,pca8574" },
- { .compatible = "nxp,pca9670" },
- { .compatible = "nxp,pca9672" },
- { .compatible = "nxp,pca9674" },
- { .compatible = "nxp,pcf8575" },
- { .compatible = "nxp,pca8575" },
- { .compatible = "nxp,pca9671" },
- { .compatible = "nxp,pca9673" },
- { .compatible = "nxp,pca9675" },
- { .compatible = "maxim,max7328" },
- { .compatible = "maxim,max7329" },
+ { .compatible = "nxp,pcf8574", (void *)8 },
+ { .compatible = "nxp,pcf8574a", (void *)8 },
+ { .compatible = "nxp,pca8574", (void *)8 },
+ { .compatible = "nxp,pca9670", (void *)8 },
+ { .compatible = "nxp,pca9672", (void *)8 },
+ { .compatible = "nxp,pca9674", (void *)8 },
+ { .compatible = "nxp,pcf8575", (void *)16 },
+ { .compatible = "nxp,pca8575", (void *)16 },
+ { .compatible = "nxp,pca9671", (void *)16 },
+ { .compatible = "nxp,pca9673", (void *)16 },
+ { .compatible = "nxp,pca9675", (void *)16 },
+ { .compatible = "maxim,max7328", (void *)8 },
+ { .compatible = "maxim,max7329", (void *)8 },
{ }
};
MODULE_DEVICE_TABLE(of, pcf857x_of_table);
@@ -272,7 +272,6 @@ static const struct irq_chip pcf857x_irq_chip = {
static int pcf857x_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct pcf857x *gpio;
unsigned int n_latch = 0;
int status;
@@ -296,7 +295,7 @@ static int pcf857x_probe(struct i2c_client *client)
gpio->chip.set_multiple = pcf857x_set_multiple;
gpio->chip.direction_input = pcf857x_input;
gpio->chip.direction_output = pcf857x_output;
- gpio->chip.ngpio = id->driver_data;
+ gpio->chip.ngpio = (uintptr_t)i2c_get_match_data(client);
/* NOTE: the OnSemi jlc1562b is also largely compatible with
* these parts, notably for output. It has a low-resolution
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 6726c32e31e6..44c0a21b1d1d 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -5,214 +5,75 @@
*/
#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/err.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
#include "gpio-idio-16.h"
-/**
- * struct idio_16_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @lock: synchronization lock to prevent I/O race conditions
- * @reg: I/O address offset for the GPIO device registers
- * @state: ACCES IDIO-16 device state
- * @irq_mask: I/O bits affected by interrupts
- */
-struct idio_16_gpio {
- struct gpio_chip chip;
- raw_spinlock_t lock;
- struct idio_16 __iomem *reg;
- struct idio_16_state state;
- unsigned long irq_mask;
+static const struct regmap_range idio_16_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x2), regmap_reg_range(0x3, 0x4),
};
-
-static int idio_16_gpio_get_direction(struct gpio_chip *chip,
- unsigned int offset)
-{
- if (idio_16_get_direction(offset))
- return GPIO_LINE_DIRECTION_IN;
-
- return GPIO_LINE_DIRECTION_OUT;
-}
-
-static int idio_16_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- return 0;
-}
-
-static int idio_16_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- chip->set(chip, offset, value);
- return 0;
-}
-
-static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
-}
-
-static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
- return 0;
-}
-
-static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
-}
-
-static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
-
- idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
-}
-
-static void idio_16_irq_ack(struct irq_data *data)
-{
-}
-
-static void idio_16_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned long mask = BIT(irqd_to_hwirq(data));
- unsigned long flags;
-
- idio16gpio->irq_mask &= ~mask;
-
- if (!idio16gpio->irq_mask) {
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- iowrite8(0, &idio16gpio->reg->irq_ctl);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
- }
-
- gpiochip_disable_irq(chip, irqd_to_hwirq(data));
-}
-
-static void idio_16_irq_unmask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned long mask = BIT(irqd_to_hwirq(data));
- const unsigned long prev_irq_mask = idio16gpio->irq_mask;
- unsigned long flags;
-
- gpiochip_enable_irq(chip, irqd_to_hwirq(data));
-
- idio16gpio->irq_mask |= mask;
-
- if (!prev_irq_mask) {
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- ioread8(&idio16gpio->reg->irq_ctl);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
- }
-}
-
-static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
- /* The only valid irq types are none and both-edges */
- if (flow_type != IRQ_TYPE_NONE &&
- (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct irq_chip idio_16_irqchip = {
- .name = "pci-idio-16",
- .irq_ack = idio_16_irq_ack,
- .irq_mask = idio_16_irq_mask,
- .irq_unmask = idio_16_irq_unmask,
- .irq_set_type = idio_16_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+static const struct regmap_range idio_16_rd_ranges[] = {
+ regmap_reg_range(0x1, 0x2), regmap_reg_range(0x5, 0x6),
};
-
-static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
-{
- struct idio_16_gpio *const idio16gpio = dev_id;
- unsigned int irq_status;
- struct gpio_chip *const chip = &idio16gpio->chip;
- int gpio;
-
- raw_spin_lock(&idio16gpio->lock);
-
- irq_status = ioread8(&idio16gpio->reg->irq_status);
-
- raw_spin_unlock(&idio16gpio->lock);
-
- /* Make sure our device generated IRQ */
- if (!(irq_status & 0x3) || !(irq_status & 0x4))
- return IRQ_NONE;
-
- for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
- generic_handle_domain_irq(chip->irq.domain, gpio);
-
- raw_spin_lock(&idio16gpio->lock);
-
- /* Clear interrupt */
- iowrite8(0, &idio16gpio->reg->in0_7);
-
- raw_spin_unlock(&idio16gpio->lock);
-
- return IRQ_HANDLED;
-}
-
-#define IDIO_16_NGPIO 32
-static const char *idio_16_names[IDIO_16_NGPIO] = {
- "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
- "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
- "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
- "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
+static const struct regmap_range idio_16_precious_ranges[] = {
+ regmap_reg_range(0x2, 0x2),
+};
+static const struct regmap_access_table idio_16_wr_table = {
+ .yes_ranges = idio_16_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_wr_ranges),
+};
+static const struct regmap_access_table idio_16_rd_table = {
+ .yes_ranges = idio_16_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_rd_ranges),
+};
+static const struct regmap_access_table idio_16_precious_table = {
+ .yes_ranges = idio_16_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_16_precious_ranges),
+};
+static const struct regmap_config idio_16_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &idio_16_wr_table,
+ .rd_table = &idio_16_rd_table,
+ .volatile_table = &idio_16_rd_table,
+ .precious_table = &idio_16_precious_table,
+ .cache_type = REGCACHE_FLAT,
+ .use_raw_spinlock = true,
};
-static int idio_16_irq_init_hw(struct gpio_chip *gc)
-{
- struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
-
- /* Disable IRQ by default and clear any pending interrupt */
- iowrite8(0, &idio16gpio->reg->irq_ctl);
- iowrite8(0, &idio16gpio->reg->in0_7);
+/* Only input lines (GPIO 16-31) support interrupts */
+#define IDIO_16_REGMAP_IRQ(_id) \
+ [16 + _id] = { \
+ .mask = BIT(2), \
+ .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
+ }
- return 0;
-}
+static const struct regmap_irq idio_16_regmap_irqs[] = {
+ IDIO_16_REGMAP_IRQ(0), IDIO_16_REGMAP_IRQ(1), IDIO_16_REGMAP_IRQ(2), /* 0-2 */
+ IDIO_16_REGMAP_IRQ(3), IDIO_16_REGMAP_IRQ(4), IDIO_16_REGMAP_IRQ(5), /* 3-5 */
+ IDIO_16_REGMAP_IRQ(6), IDIO_16_REGMAP_IRQ(7), IDIO_16_REGMAP_IRQ(8), /* 6-8 */
+ IDIO_16_REGMAP_IRQ(9), IDIO_16_REGMAP_IRQ(10), IDIO_16_REGMAP_IRQ(11), /* 9-11 */
+ IDIO_16_REGMAP_IRQ(12), IDIO_16_REGMAP_IRQ(13), IDIO_16_REGMAP_IRQ(14), /* 12-14 */
+ IDIO_16_REGMAP_IRQ(15), /* 15 */
+};
static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *const dev = &pdev->dev;
- struct idio_16_gpio *idio16gpio;
int err;
const size_t pci_bar_index = 2;
const char *const name = pci_name(pdev);
- struct gpio_irq_chip *girq;
-
- idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
- if (!idio16gpio)
- return -ENOMEM;
+ struct idio_16_regmap_config config = {};
+ void __iomem *regs;
+ struct regmap *map;
err = pcim_enable_device(pdev);
if (err) {
@@ -226,53 +87,20 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return err;
}
- idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
+ regs = pcim_iomap_table(pdev)[pci_bar_index];
- /* Deactivate input filters */
- iowrite8(0, &idio16gpio->reg->filter_ctl);
+ map = devm_regmap_init_mmio(dev, regs, &idio_16_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map), "Unable to initialize register map\n");
- idio16gpio->chip.label = name;
- idio16gpio->chip.parent = dev;
- idio16gpio->chip.owner = THIS_MODULE;
- idio16gpio->chip.base = -1;
- idio16gpio->chip.ngpio = IDIO_16_NGPIO;
- idio16gpio->chip.names = idio_16_names;
- idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
- idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
- idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
- idio16gpio->chip.get = idio_16_gpio_get;
- idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
- idio16gpio->chip.set = idio_16_gpio_set;
- idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
-
- idio_16_state_init(&idio16gpio->state);
-
- girq = &idio16gpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
- girq->init_hw = idio_16_irq_init_hw;
-
- raw_spin_lock_init(&idio16gpio->lock);
-
- err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
-
- err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
- name, idio16gpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- return err;
- }
+ config.parent = dev;
+ config.map = map;
+ config.regmap_irqs = idio_16_regmap_irqs;
+ config.num_regmap_irqs = ARRAY_SIZE(idio_16_regmap_irqs);
+ config.irq = pdev->irq;
+ config.filters = true;
- return 0;
+ return devm_idio_16_regmap_register(dev, &config);
}
static const struct pci_device_id idio_16_pci_dev_id[] = {
diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c
index 463c0613abb9..2efd1b1a0805 100644
--- a/drivers/gpio/gpio-pcie-idio-24.c
+++ b/drivers/gpio/gpio-pcie-idio-24.c
@@ -6,16 +6,15 @@
* This driver supports the following ACCES devices: PCIe-IDIO-24,
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
*/
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/err.h>
+#include <linux/gpio/regmap.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -59,422 +58,224 @@
#define PLX_PEX8311_PCI_LCS_INTCSR 0x68
#define INTCSR_INTERNAL_PCI_WIRE BIT(8)
#define INTCSR_LOCAL_INPUT BIT(11)
+#define IDIO_24_ENABLE_IRQ (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT)
+
+#define IDIO_24_OUT_BASE 0x0
+#define IDIO_24_TTLCMOS_OUT_REG 0x3
+#define IDIO_24_IN_BASE 0x4
+#define IDIO_24_TTLCMOS_IN_REG 0x7
+#define IDIO_24_COS_STATUS_BASE 0x8
+#define IDIO_24_CONTROL_REG 0xC
+#define IDIO_24_COS_ENABLE 0xE
+#define IDIO_24_SOFT_RESET 0xF
+
+#define CONTROL_REG_OUT_MODE BIT(1)
+
+#define COS_ENABLE_RISING BIT(1)
+#define COS_ENABLE_FALLING BIT(4)
+#define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING)
+
+static const struct regmap_config pex8311_intcsr_regmap_config = {
+ .name = "pex8311_intcsr",
+ .reg_bits = 32,
+ .reg_stride = 1,
+ .reg_base = PLX_PEX8311_PCI_LCS_INTCSR,
+ .val_bits = 32,
+ .io_port = true,
+};
-/**
- * struct idio_24_gpio_reg - GPIO device registers structure
- * @out0_7: Read: FET Outputs 0-7
- * Write: FET Outputs 0-7
- * @out8_15: Read: FET Outputs 8-15
- * Write: FET Outputs 8-15
- * @out16_23: Read: FET Outputs 16-23
- * Write: FET Outputs 16-23
- * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7
- * Write: TTL/CMOS Outputs 0-7
- * @in0_7: Read: Isolated Inputs 0-7
- * Write: Reserved
- * @in8_15: Read: Isolated Inputs 8-15
- * Write: Reserved
- * @in16_23: Read: Isolated Inputs 16-23
- * Write: Reserved
- * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7
- * Write: Reserved
- * @cos0_7: Read: COS Status Inputs 0-7
- * Write: COS Clear Inputs 0-7
- * @cos8_15: Read: COS Status Inputs 8-15
- * Write: COS Clear Inputs 8-15
- * @cos16_23: Read: COS Status Inputs 16-23
- * Write: COS Clear Inputs 16-23
- * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7
- * Write: COS Clear TTL/CMOS 0-7
- * @ctl: Read: Control Register
- * Write: Control Register
- * @reserved: Read: Reserved
- * Write: Reserved
- * @cos_enable: Read: COS Enable
- * Write: COS Enable
- * @soft_reset: Read: IRQ Output Pin Status
- * Write: Software Board Reset
- */
-struct idio_24_gpio_reg {
- u8 out0_7;
- u8 out8_15;
- u8 out16_23;
- u8 ttl_out0_7;
- u8 in0_7;
- u8 in8_15;
- u8 in16_23;
- u8 ttl_in0_7;
- u8 cos0_7;
- u8 cos8_15;
- u8 cos16_23;
- u8 cos_ttl0_7;
- u8 ctl;
- u8 reserved;
- u8 cos_enable;
- u8 soft_reset;
+static const struct regmap_range idio_24_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC),
+ regmap_reg_range(0xE, 0xF),
+};
+static const struct regmap_range idio_24_rd_ranges[] = {
+ regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF),
+};
+static const struct regmap_range idio_24_volatile_ranges[] = {
+ regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF),
+};
+static const struct regmap_access_table idio_24_wr_table = {
+ .yes_ranges = idio_24_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges),
+};
+static const struct regmap_access_table idio_24_rd_table = {
+ .yes_ranges = idio_24_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges),
+};
+static const struct regmap_access_table idio_24_volatile_table = {
+ .yes_ranges = idio_24_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges),
+};
+
+static const struct regmap_config idio_24_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &idio_24_wr_table,
+ .rd_table = &idio_24_rd_table,
+ .volatile_table = &idio_24_volatile_table,
+ .cache_type = REGCACHE_FLAT,
+ .use_raw_spinlock = true,
+};
+
+#define IDIO_24_NGPIO_PER_REG 8
+#define IDIO_24_REGMAP_IRQ(_id) \
+ [24 + _id] = { \
+ .reg_offset = (_id) / IDIO_24_NGPIO_PER_REG, \
+ .mask = BIT((_id) % IDIO_24_NGPIO_PER_REG), \
+ .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
+ }
+#define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id)
+#define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id)
+
+static const struct regmap_irq idio_24_regmap_irqs[] = {
+ IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */
+ IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */
+ IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */
+ IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */
+ IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */
+ IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */
+ IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */
+ IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */
+ IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */
+ IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */
+ IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */
};
/**
* struct idio_24_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
+ * @map: regmap for the device
* @lock: synchronization lock to prevent I/O race conditions
- * @reg: I/O address offset for the GPIO device registers
- * @irq_mask: I/O bits affected by interrupts
+ * @irq_type: type configuration for IRQs
*/
struct idio_24_gpio {
- struct gpio_chip chip;
+ struct regmap *map;
raw_spinlock_t lock;
- __u8 __iomem *plx;
- struct idio_24_gpio_reg __iomem *reg;
- unsigned long irq_mask;
+ u8 irq_type;
};
-static int idio_24_gpio_get_direction(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- const unsigned long out_mode_mask = BIT(1);
-
- /* FET Outputs */
- if (offset < 24)
- return GPIO_LINE_DIRECTION_OUT;
-
- /* Isolated Inputs */
- if (offset < 48)
- return GPIO_LINE_DIRECTION_IN;
-
- /* TTL/CMOS I/O */
- /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
- if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
- return GPIO_LINE_DIRECTION_OUT;
-
- return GPIO_LINE_DIRECTION_IN;
-}
-
-static int idio_24_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long flags;
- unsigned int ctl_state;
- const unsigned long out_mode_mask = BIT(1);
-
- /* TTL/CMOS I/O */
- if (offset > 47) {
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
-
- /* Clear TTL/CMOS Output Mode */
- ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
- iowrite8(ctl_state, &idio24gpio->reg->ctl);
-
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
- }
-
- return 0;
-}
-
-static int idio_24_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long flags;
- unsigned int ctl_state;
- const unsigned long out_mode_mask = BIT(1);
-
- /* TTL/CMOS I/O */
- if (offset > 47) {
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
-
- /* Set TTL/CMOS Output Mode */
- ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
- iowrite8(ctl_state, &idio24gpio->reg->ctl);
-
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
- }
-
- chip->set(chip, offset, value);
- return 0;
-}
-
-static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
+static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def,
+ const unsigned int mask_buf, void *const irq_drv_data)
{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- const unsigned long offset_mask = BIT(offset % 8);
- const unsigned long out_mode_mask = BIT(1);
-
- /* FET Outputs */
- if (offset < 8)
- return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
+ const unsigned int type_mask = COS_ENABLE_BOTH << index;
+ struct idio_24_gpio *const idio24gpio = irq_drv_data;
+ u8 type;
+ int ret;
- if (offset < 16)
- return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
-
- if (offset < 24)
- return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
-
- /* Isolated Inputs */
- if (offset < 32)
- return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
-
- if (offset < 40)
- return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
-
- if (offset < 48)
- return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
+ raw_spin_lock(&idio24gpio->lock);
- /* TTL/CMOS Outputs */
- if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
- return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
+ /* if all are masked, then disable interrupts, else set to type */
+ type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type;
- /* TTL/CMOS Inputs */
- return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
-}
+ ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type);
-static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- void __iomem *ports[] = {
- &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
- &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7,
- &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23,
- };
- size_t index;
- unsigned long port_state;
- const unsigned long out_mode_mask = BIT(1);
-
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- index = offset / 8;
-
- /* read bits from current gpio port (port 6 is TTL GPIO) */
- if (index < 6)
- port_state = ioread8(ports[index]);
- else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
- port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
- else
- port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
-
- port_state &= gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
+ raw_spin_unlock(&idio24gpio->lock);
- return 0;
+ return ret;
}
-static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type,
+ const struct regmap_irq *const irq_data, const int idx,
+ void *const irq_drv_data)
{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- const unsigned long out_mode_mask = BIT(1);
- void __iomem *base;
- const unsigned int mask = BIT(offset % 8);
- unsigned long flags;
- unsigned int out_state;
-
- /* Isolated Inputs */
- if (offset > 23 && offset < 48)
- return;
-
- /* TTL/CMOS Inputs */
- if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
- return;
-
- /* TTL/CMOS Outputs */
- if (offset > 47)
- base = &idio24gpio->reg->ttl_out0_7;
- /* FET Outputs */
- else if (offset > 15)
- base = &idio24gpio->reg->out16_23;
- else if (offset > 7)
- base = &idio24gpio->reg->out8_15;
- else
- base = &idio24gpio->reg->out0_7;
-
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
-
- if (value)
- out_state = ioread8(base) | mask;
- else
- out_state = ioread8(base) & ~mask;
-
- iowrite8(out_state, base);
-
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
-}
-
-static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- void __iomem *ports[] = {
- &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
- &idio24gpio->reg->out16_23
- };
- size_t index;
- unsigned long bitmask;
- unsigned long flags;
- unsigned long out_state;
- const unsigned long out_mode_mask = BIT(1);
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- index = offset / 8;
-
- bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
-
- /* read bits from current gpio port (port 6 is TTL GPIO) */
- if (index < 6) {
- out_state = ioread8(ports[index]);
- } else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) {
- out_state = ioread8(&idio24gpio->reg->ttl_out0_7);
- } else {
- /* skip TTL GPIO if set for input */
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
- continue;
- }
-
- /* set requested bit states */
- out_state &= ~gpio_mask;
- out_state |= bitmask;
-
- /* write bits for current gpio port (port 6 is TTL GPIO) */
- if (index < 6)
- iowrite8(out_state, ports[index]);
- else
- iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
-
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+ const unsigned int offset = irq_data->reg_offset;
+ const unsigned int rising = COS_ENABLE_RISING << offset;
+ const unsigned int falling = COS_ENABLE_FALLING << offset;
+ const unsigned int mask = COS_ENABLE_BOTH << offset;
+ struct idio_24_gpio *const idio24gpio = irq_drv_data;
+ unsigned int new;
+ unsigned int cos_enable;
+ int ret;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ new = rising;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ new = falling;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ new = mask;
+ break;
+ default:
+ return -EINVAL;
}
-}
-
-static void idio_24_irq_ack(struct irq_data *data)
-{
-}
-static void idio_24_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long flags;
- const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
- unsigned char new_irq_mask;
- const unsigned long bank_offset = bit_offset / 8;
- unsigned char cos_enable_state;
-
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
-
- idio24gpio->irq_mask &= ~BIT(bit_offset);
- new_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
+ raw_spin_lock(&idio24gpio->lock);
- if (!new_irq_mask) {
- cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
+ /* replace old bitmap with new bitmap */
+ idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask);
- /* Disable Rising Edge detection */
- cos_enable_state &= ~BIT(bank_offset);
- /* Disable Falling Edge detection */
- cos_enable_state &= ~BIT(bank_offset + 4);
+ ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable);
+ if (ret)
+ goto exit_unlock;
- iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
+ /* if COS is currently enabled then update the edge type */
+ if (cos_enable & mask) {
+ ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask,
+ idio24gpio->irq_type);
+ if (ret)
+ goto exit_unlock;
}
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+exit_unlock:
+ raw_spin_unlock(&idio24gpio->lock);
- gpiochip_disable_irq(chip, irqd_to_hwirq(data));
+ return ret;
}
-static void idio_24_irq_unmask(struct irq_data *data)
+static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
+ const unsigned int offset, unsigned int *const reg,
+ unsigned int *const mask)
{
- struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
- struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
- unsigned long flags;
- unsigned char prev_irq_mask;
- const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
- const unsigned long bank_offset = bit_offset / 8;
- unsigned char cos_enable_state;
-
- gpiochip_enable_irq(chip, irqd_to_hwirq(data));
-
- raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+ const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG;
+ const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG;
+ struct regmap *const map = gpio_regmap_get_drvdata(gpio);
+ int err;
+ unsigned int ctrl_reg;
- prev_irq_mask = idio24gpio->irq_mask >> bank_offset * 8;
- idio24gpio->irq_mask |= BIT(bit_offset);
+ switch (base) {
+ case IDIO_24_OUT_BASE:
+ *mask = BIT(offset % IDIO_24_NGPIO_PER_REG);
- if (!prev_irq_mask) {
- cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
+ /* FET Outputs */
+ if (offset < 24) {
+ *reg = IDIO_24_OUT_BASE + out_stride;
+ return 0;
+ }
- /* Enable Rising Edge detection */
- cos_enable_state |= BIT(bank_offset);
- /* Enable Falling Edge detection */
- cos_enable_state |= BIT(bank_offset + 4);
+ /* Isolated Inputs */
+ if (offset < 48) {
+ *reg = IDIO_24_IN_BASE + in_stride;
+ return 0;
+ }
- iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
- }
+ err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg);
+ if (err)
+ return err;
- raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
-}
+ /* TTL/CMOS Outputs */
+ if (ctrl_reg & CONTROL_REG_OUT_MODE) {
+ *reg = IDIO_24_TTLCMOS_OUT_REG;
+ return 0;
+ }
-static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
- /* The only valid irq types are none and both-edges */
- if (flow_type != IRQ_TYPE_NONE &&
- (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
+ /* TTL/CMOS Inputs */
+ *reg = IDIO_24_TTLCMOS_IN_REG;
+ return 0;
+ case IDIO_24_CONTROL_REG:
+ /* We can only set direction for TTL/CMOS lines */
+ if (offset < 48)
+ return -EOPNOTSUPP;
+
+ *reg = IDIO_24_CONTROL_REG;
+ *mask = CONTROL_REG_OUT_MODE;
+ return 0;
+ default:
+ /* Should never reach this path */
return -EINVAL;
-
- return 0;
-}
-
-static const struct irq_chip idio_24_irqchip = {
- .name = "pcie-idio-24",
- .irq_ack = idio_24_irq_ack,
- .irq_mask = idio_24_irq_mask,
- .irq_unmask = idio_24_irq_unmask,
- .irq_set_type = idio_24_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
-};
-
-static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
-{
- struct idio_24_gpio *const idio24gpio = dev_id;
- unsigned long irq_status;
- struct gpio_chip *const chip = &idio24gpio->chip;
- unsigned long irq_mask;
- int gpio;
-
- raw_spin_lock(&idio24gpio->lock);
-
- /* Read Change-Of-State status */
- irq_status = ioread32(&idio24gpio->reg->cos0_7);
-
- raw_spin_unlock(&idio24gpio->lock);
-
- /* Make sure our device generated IRQ */
- if (!irq_status)
- return IRQ_NONE;
-
- /* Handle only unmasked IRQ */
- irq_mask = idio24gpio->irq_mask & irq_status;
-
- for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
- generic_handle_domain_irq(chip->irq.domain, gpio + 24);
-
- raw_spin_lock(&idio24gpio->lock);
-
- /* Clear Change-Of-State status */
- iowrite32(irq_status, &idio24gpio->reg->cos0_7);
-
- raw_spin_unlock(&idio24gpio->lock);
-
- return IRQ_HANDLED;
+ }
}
#define IDIO_24_NGPIO 56
@@ -496,11 +297,12 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
const size_t pci_plx_bar_index = 1;
const size_t pci_bar_index = 2;
const char *const name = pci_name(pdev);
- struct gpio_irq_chip *girq;
-
- idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
- if (!idio24gpio)
- return -ENOMEM;
+ struct gpio_regmap_config gpio_config = {};
+ void __iomem *pex8311_regs;
+ void __iomem *idio_24_regs;
+ struct regmap *intcsr_map;
+ struct regmap_irq_chip *chip;
+ struct regmap_irq_chip_data *chip_data;
err = pcim_enable_device(pdev);
if (err) {
@@ -514,57 +316,72 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return err;
}
- idio24gpio->plx = pcim_iomap_table(pdev)[pci_plx_bar_index];
- idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
-
- idio24gpio->chip.label = name;
- idio24gpio->chip.parent = dev;
- idio24gpio->chip.owner = THIS_MODULE;
- idio24gpio->chip.base = -1;
- idio24gpio->chip.ngpio = IDIO_24_NGPIO;
- idio24gpio->chip.names = idio_24_names;
- idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
- idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
- idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
- idio24gpio->chip.get = idio_24_gpio_get;
- idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
- idio24gpio->chip.set = idio_24_gpio_set;
- idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
-
- girq = &idio24gpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &idio_24_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
+ pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index];
+ idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index];
+
+ intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config);
+ if (IS_ERR(intcsr_map))
+ return dev_err_probe(dev, PTR_ERR(intcsr_map),
+ "Unable to initialize PEX8311 register map\n");
+
+ idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
+ if (!idio24gpio)
+ return -ENOMEM;
+
+ idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config);
+ if (IS_ERR(idio24gpio->map))
+ return dev_err_probe(dev, PTR_ERR(idio24gpio->map),
+ "Unable to initialize register map\n");
raw_spin_lock_init(&idio24gpio->lock);
+ /* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */
+ idio24gpio->irq_type = GENMASK(7, 0);
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->name = name;
+ chip->status_base = IDIO_24_COS_STATUS_BASE;
+ chip->mask_base = IDIO_24_COS_ENABLE;
+ chip->ack_base = IDIO_24_COS_STATUS_BASE;
+ chip->num_regs = 4;
+ chip->irqs = idio_24_regmap_irqs;
+ chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs);
+ chip->handle_mask_sync = idio_24_handle_mask_sync;
+ chip->set_type_config = idio_24_set_type_config;
+ chip->irq_drv_data = idio24gpio;
+
/* Software board reset */
- iowrite8(0, &idio24gpio->reg->soft_reset);
+ err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0);
+ if (err)
+ return err;
/*
* enable PLX PEX8311 internal PCI wire interrupt and local interrupt
* input
*/
- iowrite8((INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT) >> 8,
- idio24gpio->plx + PLX_PEX8311_PCI_LCS_INTCSR + 1);
-
- err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
+ err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ);
+ if (err)
return err;
- }
-
- err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
- name, idio24gpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- return err;
- }
- return 0;
+ err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data);
+ if (err)
+ return dev_err_probe(dev, err, "IRQ registration failed\n");
+
+ gpio_config.parent = dev;
+ gpio_config.regmap = idio24gpio->map;
+ gpio_config.ngpio = IDIO_24_NGPIO;
+ gpio_config.names = idio_24_names;
+ gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
+ gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
+ gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG);
+ gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG;
+ gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
+ gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate;
+ gpio_config.drvdata = idio24gpio->map;
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
}
static const struct pci_device_id idio_24_pci_dev_id[] = {
diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c
index 67071bea08c2..e3013e778e15 100644
--- a/drivers/gpio/gpio-pisosr.c
+++ b/drivers/gpio/gpio-pisosr.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
- * Andrew F. Davis <afd@ti.com>
+ * Copyright (C) 2015-2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Andrew Davis <afd@ti.com>
*/
#include <linux/bitmap.h>
@@ -116,6 +116,11 @@ static const struct gpio_chip template_chip = {
.can_sleep = true,
};
+static void pisosr_mutex_destroy(void *lock)
+{
+ mutex_destroy(lock);
+}
+
static int pisosr_gpio_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
@@ -126,8 +131,6 @@ static int pisosr_gpio_probe(struct spi_device *spi)
if (!gpio)
return -ENOMEM;
- spi_set_drvdata(spi, gpio);
-
gpio->chip = template_chip;
gpio->chip.parent = dev;
of_property_read_u16(dev->of_node, "ngpios", &gpio->chip.ngpio);
@@ -145,8 +148,11 @@ static int pisosr_gpio_probe(struct spi_device *spi)
"Unable to allocate load GPIO\n");
mutex_init(&gpio->lock);
+ ret = devm_add_action_or_reset(dev, pisosr_mutex_destroy, &gpio->lock);
+ if (ret)
+ return ret;
- ret = gpiochip_add_data(&gpio->chip, gpio);
+ ret = devm_gpiochip_add_data(dev, &gpio->chip, gpio);
if (ret < 0) {
dev_err(dev, "Unable to register gpiochip\n");
return ret;
@@ -155,15 +161,6 @@ static int pisosr_gpio_probe(struct spi_device *spi)
return 0;
}
-static void pisosr_gpio_remove(struct spi_device *spi)
-{
- struct pisosr_gpio *gpio = spi_get_drvdata(spi);
-
- gpiochip_remove(&gpio->chip);
-
- mutex_destroy(&gpio->lock);
-}
-
static const struct spi_device_id pisosr_gpio_id_table[] = {
{ "pisosr-gpio", },
{ /* sentinel */ }
@@ -182,11 +179,10 @@ static struct spi_driver pisosr_gpio_driver = {
.of_match_table = pisosr_gpio_of_match_table,
},
.probe = pisosr_gpio_probe,
- .remove = pisosr_gpio_remove,
.id_table = pisosr_gpio_id_table,
};
module_spi_driver(pisosr_gpio_driver);
-MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
+MODULE_AUTHOR("Andrew Davis <afd@ti.com>");
MODULE_DESCRIPTION("SPI Compatible PISO Shift Register GPIO Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c
index c3e4d90f6b18..2b9b7be9b8fd 100644
--- a/drivers/gpio/gpio-pmic-eic-sprd.c
+++ b/drivers/gpio/gpio-pmic-eic-sprd.c
@@ -8,7 +8,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -363,7 +363,6 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, pmic_eic);
return 0;
}
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index a1630ed4b741..7e9f7a32d3ee 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -20,7 +20,6 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c
index ecb0d3800dfe..9d1b95e429f1 100644
--- a/drivers/gpio/gpio-raspberrypi-exp.c
+++ b/drivers/gpio/gpio-raspberrypi-exp.c
@@ -234,7 +234,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev)
return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
}
-static const struct of_device_id rpi_exp_gpio_ids[] __maybe_unused = {
+static const struct of_device_id rpi_exp_gpio_ids[] = {
{ .compatible = "raspberrypi,firmware-gpio" },
{ }
};
@@ -243,7 +243,7 @@ MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
static struct platform_driver rpi_exp_gpio_driver = {
.driver = {
.name = MODULE_NAME,
- .of_match_table = of_match_ptr(rpi_exp_gpio_ids),
+ .of_match_table = rpi_exp_gpio_ids,
},
.probe = rpi_exp_gpio_probe,
};
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 4fae3ebea790..c34dcadaee36 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -121,8 +121,6 @@ static int rc5t583_gpio_probe(struct platform_device *pdev)
if (pdata && pdata->gpio_base)
rc5t583_gpio->gpio_chip.base = pdata->gpio_base;
- platform_set_drvdata(pdev, rc5t583_gpio);
-
return devm_gpiochip_add_data(&pdev->dev, &rc5t583_gpio->gpio_chip,
rc5t583_gpio);
}
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 2525adb52f4f..86e69cde04da 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -15,7 +15,6 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index e5de15a2ab9a..b35b9604413f 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -17,10 +17,10 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "../pinctrl/core.h"
diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c
index 767c33ae3213..d89da7300ddd 100644
--- a/drivers/gpio/gpio-sama5d2-piobu.c
+++ b/drivers/gpio/gpio-sama5d2-piobu.c
@@ -189,7 +189,6 @@ static int sama5d2_piobu_probe(struct platform_device *pdev)
if (!piobu)
return -ENOMEM;
- platform_set_drvdata(pdev, piobu);
piobu->chip.label = pdev->name;
piobu->chip.parent = &pdev->dev;
piobu->chip.owner = THIS_MODULE,
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 8a83f7bf4382..e48392074e4b 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -380,8 +380,6 @@ static int sch_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- platform_set_drvdata(pdev, sch);
-
girq = &sch->chip.irq;
gpio_irq_chip_set_chip(girq, &sch_irqchip);
girq->num_parents = 0;
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index 745e5f67254e..8decd9b5d229 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -6,10 +6,10 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/of_irq.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/regmap.h>
@@ -150,6 +150,7 @@ static const struct irq_chip sifive_gpio_irqchip = {
.irq_disable = sifive_gpio_irq_disable,
.irq_eoi = sifive_gpio_irq_eoi,
.irq_set_affinity = sifive_gpio_irq_set_affinity,
+ .irq_set_wake = irq_chip_set_wake_parent,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
@@ -180,12 +181,10 @@ static const struct regmap_config sifive_gpio_regmap_config = {
static int sifive_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *node = pdev->dev.of_node;
- struct device_node *irq_parent;
struct irq_domain *parent;
struct gpio_irq_chip *girq;
struct sifive_gpio *chip;
- int ret, ngpio, i;
+ int ret, ngpio;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -202,31 +201,22 @@ static int sifive_gpio_probe(struct platform_device *pdev)
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
- ngpio = of_irq_count(node);
- if (ngpio > SIFIVE_GPIO_MAX) {
- dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
- SIFIVE_GPIO_MAX);
- return -ENXIO;
- }
-
- irq_parent = of_irq_find_parent(node);
- if (!irq_parent) {
- dev_err(dev, "no IRQ parent node\n");
- return -ENODEV;
+ for (ngpio = 0; ngpio < SIFIVE_GPIO_MAX; ngpio++) {
+ ret = platform_get_irq_optional(pdev, ngpio);
+ if (ret < 0)
+ break;
+ chip->irq_number[ngpio] = ret;
}
- parent = irq_find_host(irq_parent);
- of_node_put(irq_parent);
- if (!parent) {
- dev_err(dev, "no IRQ parent domain\n");
+ if (!ngpio) {
+ dev_err(dev, "no IRQ found\n");
return -ENODEV;
}
- for (i = 0; i < ngpio; i++) {
- ret = platform_get_irq(pdev, i);
- if (ret < 0)
- return ret;
- chip->irq_number[i] = ret;
- }
+ /*
+ * The check above ensures at least one parent IRQ is valid.
+ * Assume all parent IRQs belong to the same domain.
+ */
+ parent = irq_get_irq_data(chip->irq_number[0])->domain;
ret = bgpio_init(&chip->gc, dev, 4,
chip->base + SIFIVE_GPIO_INPUT_VAL,
@@ -254,7 +244,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
chip->gc.owner = THIS_MODULE;
girq = &chip->gc.irq;
gpio_irq_chip_set_chip(girq, &sifive_gpio_irqchip);
- girq->fwnode = of_node_to_fwnode(node);
+ girq->fwnode = dev_fwnode(dev);
girq->parent_domain = parent;
girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq;
girq->handler = handle_bad_irq;
@@ -277,4 +267,8 @@ static struct platform_driver sifive_gpio_driver = {
.of_match_table = sifive_gpio_match,
},
};
-builtin_platform_driver(sifive_gpio_driver)
+module_platform_driver(sifive_gpio_driver)
+
+MODULE_AUTHOR("Yash Shah <yash.shah@sifive.com>");
+MODULE_DESCRIPTION("SiFive GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index f1f6f1c32987..271db3639a78 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitmap.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/configfs.h>
#include <linux/device.h>
@@ -68,7 +69,7 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip,
gc = &chip->gc;
desc = &gc->gpiodev->descs[offset];
- mutex_lock(&chip->lock);
+ guard(mutex)(&chip->lock);
if (test_bit(FLAG_REQUESTED, &desc->flags) &&
!test_bit(FLAG_IS_OUT, &desc->flags)) {
@@ -104,29 +105,24 @@ set_value:
set_pull:
__assign_bit(offset, chip->pull_map, value);
- mutex_unlock(&chip->lock);
return 0;
}
static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- int ret;
- mutex_lock(&chip->lock);
- ret = !!test_bit(offset, chip->value_map);
- mutex_unlock(&chip->lock);
+ guard(mutex)(&chip->lock);
- return ret;
+ return !!test_bit(offset, chip->value_map);
}
static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- __assign_bit(offset, chip->value_map, value);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ __assign_bit(offset, chip->value_map, value);
}
static int gpio_sim_get_multiple(struct gpio_chip *gc,
@@ -134,9 +130,8 @@ static int gpio_sim_get_multiple(struct gpio_chip *gc,
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- bitmap_replace(bits, bits, chip->value_map, mask, gc->ngpio);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ bitmap_replace(bits, bits, chip->value_map, mask, gc->ngpio);
return 0;
}
@@ -146,9 +141,9 @@ static void gpio_sim_set_multiple(struct gpio_chip *gc,
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- bitmap_replace(chip->value_map, chip->value_map, bits, mask, gc->ngpio);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ bitmap_replace(chip->value_map, chip->value_map, bits, mask,
+ gc->ngpio);
}
static int gpio_sim_direction_output(struct gpio_chip *gc,
@@ -156,10 +151,10 @@ static int gpio_sim_direction_output(struct gpio_chip *gc,
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- __clear_bit(offset, chip->direction_map);
- __assign_bit(offset, chip->value_map, value);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock) {
+ __clear_bit(offset, chip->direction_map);
+ __assign_bit(offset, chip->value_map, value);
+ }
return 0;
}
@@ -168,9 +163,8 @@ static int gpio_sim_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- __set_bit(offset, chip->direction_map);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ __set_bit(offset, chip->direction_map);
return 0;
}
@@ -180,9 +174,8 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset)
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
int direction;
- mutex_lock(&chip->lock);
- direction = !!test_bit(offset, chip->direction_map);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ direction = !!test_bit(offset, chip->direction_map);
return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}
@@ -215,9 +208,9 @@ static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
- mutex_lock(&chip->lock);
- __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map));
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ __assign_bit(offset, chip->value_map,
+ !!test_bit(offset, chip->pull_map));
}
static ssize_t gpio_sim_sysfs_val_show(struct device *dev,
@@ -227,9 +220,8 @@ static ssize_t gpio_sim_sysfs_val_show(struct device *dev,
struct gpio_sim_chip *chip = dev_get_drvdata(dev);
int val;
- mutex_lock(&chip->lock);
- val = !!test_bit(line_attr->offset, chip->value_map);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ val = !!test_bit(line_attr->offset, chip->value_map);
return sysfs_emit(buf, "%d\n", val);
}
@@ -258,9 +250,8 @@ static ssize_t gpio_sim_sysfs_pull_show(struct device *dev,
struct gpio_sim_chip *chip = dev_get_drvdata(dev);
int pull;
- mutex_lock(&chip->lock);
- pull = !!test_bit(line_attr->offset, chip->pull_map);
- mutex_unlock(&chip->lock);
+ scoped_guard(mutex, &chip->lock)
+ pull = !!test_bit(line_attr->offset, chip->pull_map);
return sysfs_emit(buf, "%s\n", gpio_sim_sysfs_pull_strings[pull]);
}
@@ -291,6 +282,15 @@ static void gpio_sim_mutex_destroy(void *data)
mutex_destroy(lock);
}
+static void gpio_sim_dispose_mappings(void *data)
+{
+ struct gpio_sim_chip *chip = data;
+ unsigned int i;
+
+ for (i = 0; i < chip->gc.ngpio; i++)
+ irq_dispose_mapping(irq_find_mapping(chip->irq_sim, i));
+}
+
static void gpio_sim_sysfs_remove(void *data)
{
struct gpio_sim_chip *chip = data;
@@ -402,10 +402,14 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
if (!chip->pull_map)
return -ENOMEM;
- chip->irq_sim = devm_irq_domain_create_sim(dev, NULL, num_lines);
+ chip->irq_sim = devm_irq_domain_create_sim(dev, swnode, num_lines);
if (IS_ERR(chip->irq_sim))
return PTR_ERR(chip->irq_sim);
+ ret = devm_add_action_or_reset(dev, gpio_sim_dispose_mappings, chip);
+ if (ret)
+ return ret;
+
mutex_init(&chip->lock);
ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy,
&chip->lock);
@@ -489,7 +493,7 @@ struct gpio_sim_device {
* This structure however can be modified by callbacks of different
* attributes so we need another lock.
*
- * We use this lock fo protecting all data structures owned by this
+ * We use this lock for protecting all data structures owned by this
* object too.
*/
struct mutex lock;
@@ -643,16 +647,13 @@ static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev)
static char *gpio_sim_strdup_trimmed(const char *str, size_t count)
{
- char *dup, *trimmed;
+ char *trimmed;
- dup = kstrndup(str, count, GFP_KERNEL);
- if (!dup)
+ trimmed = kstrndup(skip_spaces(str), count, GFP_KERNEL);
+ if (!trimmed)
return NULL;
- trimmed = strstrip(dup);
- memmove(dup, trimmed, strlen(trimmed) + 1);
-
- return dup;
+ return strim(trimmed);
}
static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
@@ -660,17 +661,14 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
{
struct gpio_sim_device *dev = to_gpio_sim_device(item);
struct platform_device *pdev;
- int ret;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
+
pdev = dev->pdev;
if (pdev)
- ret = sprintf(page, "%s\n", dev_name(&pdev->dev));
- else
- ret = sprintf(page, "gpio-sim.%d\n", dev->id);
- mutex_unlock(&dev->lock);
+ return sprintf(page, "%s\n", dev_name(&pdev->dev));
- return ret;
+ return sprintf(page, "gpio-sim.%d\n", dev->id);
}
CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name);
@@ -681,9 +679,8 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page)
struct gpio_sim_device *dev = to_gpio_sim_device(item);
bool live;
- mutex_lock(&dev->lock);
- live = gpio_sim_device_is_live_unlocked(dev);
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ live = gpio_sim_device_is_live_unlocked(dev);
return sprintf(page, "%c\n", live ? '1' : '0');
}
@@ -838,8 +835,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
{
struct property_entry properties[GPIO_SIM_PROP_MAX];
unsigned int prop_idx = 0, line_names_size = 0;
- struct fwnode_handle *swnode;
- char **line_names;
+ char **line_names __free(kfree) = NULL;
memset(properties, 0, sizeof(properties));
@@ -858,9 +854,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
"gpio-line-names",
line_names, line_names_size);
- swnode = fwnode_create_software_node(properties, parent);
- kfree(line_names);
- return swnode;
+ return fwnode_create_software_node(properties, parent);
}
static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode)
@@ -985,18 +979,15 @@ gpio_sim_device_config_live_store(struct config_item *item,
if (ret)
return ret;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if ((!live && !gpio_sim_device_is_live_unlocked(dev)) ||
- (live && gpio_sim_device_is_live_unlocked(dev)))
+ if (live == gpio_sim_device_is_live_unlocked(dev))
ret = -EPERM;
else if (live)
ret = gpio_sim_device_activate_unlocked(dev);
else
gpio_sim_device_deactivate_unlocked(dev);
- mutex_unlock(&dev->lock);
-
return ret ?: count;
}
@@ -1033,17 +1024,14 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
- int ret;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
+
if (gpio_sim_device_is_live_unlocked(dev))
- ret = device_for_each_child(&dev->pdev->dev, &ctx,
- gpio_sim_emit_chip_name);
- else
- ret = sprintf(page, "none\n");
- mutex_unlock(&dev->lock);
+ return device_for_each_child(&dev->pdev->dev, &ctx,
+ gpio_sim_emit_chip_name);
- return ret;
+ return sprintf(page, "none\n");
}
CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name);
@@ -1053,13 +1041,10 @@ gpio_sim_bank_config_label_show(struct config_item *item, char *page)
{
struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
- int ret;
- mutex_lock(&dev->lock);
- ret = sprintf(page, "%s\n", bank->label ?: "");
- mutex_unlock(&dev->lock);
+ guard(mutex)(&dev->lock);
- return ret;
+ return sprintf(page, "%s\n", bank->label ?: "");
}
static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
@@ -1069,23 +1054,18 @@ static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
char *trimmed;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return -EBUSY;
- }
trimmed = gpio_sim_strdup_trimmed(page, count);
- if (!trimmed) {
- mutex_unlock(&dev->lock);
+ if (!trimmed)
return -ENOMEM;
- }
kfree(bank->label);
bank->label = trimmed;
- mutex_unlock(&dev->lock);
return count;
}
@@ -1096,13 +1076,10 @@ gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page)
{
struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
- int ret;
- mutex_lock(&dev->lock);
- ret = sprintf(page, "%u\n", bank->num_lines);
- mutex_unlock(&dev->lock);
+ guard(mutex)(&dev->lock);
- return ret;
+ return sprintf(page, "%u\n", bank->num_lines);
}
static ssize_t
@@ -1121,16 +1098,13 @@ gpio_sim_bank_config_num_lines_store(struct config_item *item,
if (num_lines == 0)
return -EINVAL;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return -EBUSY;
- }
bank->num_lines = num_lines;
- mutex_unlock(&dev->lock);
return count;
}
@@ -1148,13 +1122,10 @@ gpio_sim_line_config_name_show(struct config_item *item, char *page)
{
struct gpio_sim_line *line = to_gpio_sim_line(item);
struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
- int ret;
- mutex_lock(&dev->lock);
- ret = sprintf(page, "%s\n", line->name ?: "");
- mutex_unlock(&dev->lock);
+ guard(mutex)(&dev->lock);
- return ret;
+ return sprintf(page, "%s\n", line->name ?: "");
}
static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
@@ -1164,24 +1135,18 @@ static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
char *trimmed;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return -EBUSY;
- }
trimmed = gpio_sim_strdup_trimmed(page, count);
- if (!trimmed) {
- mutex_unlock(&dev->lock);
+ if (!trimmed)
return -ENOMEM;
- }
kfree(line->name);
line->name = trimmed;
- mutex_unlock(&dev->lock);
-
return count;
}
@@ -1197,13 +1162,10 @@ static ssize_t gpio_sim_hog_config_name_show(struct config_item *item,
{
struct gpio_sim_hog *hog = to_gpio_sim_hog(item);
struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
- int ret;
- mutex_lock(&dev->lock);
- ret = sprintf(page, "%s\n", hog->name ?: "");
- mutex_unlock(&dev->lock);
+ guard(mutex)(&dev->lock);
- return ret;
+ return sprintf(page, "%s\n", hog->name ?: "");
}
static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
@@ -1213,24 +1175,18 @@ static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
char *trimmed;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return -EBUSY;
- }
trimmed = gpio_sim_strdup_trimmed(page, count);
- if (!trimmed) {
- mutex_unlock(&dev->lock);
+ if (!trimmed)
return -ENOMEM;
- }
kfree(hog->name);
hog->name = trimmed;
- mutex_unlock(&dev->lock);
-
return count;
}
@@ -1244,9 +1200,8 @@ static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item,
char *repr;
int dir;
- mutex_lock(&dev->lock);
- dir = hog->dir;
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ dir = hog->dir;
switch (dir) {
case GPIOD_IN:
@@ -1273,42 +1228,24 @@ gpio_sim_hog_config_direction_store(struct config_item *item,
{
struct gpio_sim_hog *hog = to_gpio_sim_hog(item);
struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
- char *trimmed;
int dir;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return -EBUSY;
- }
-
- trimmed = gpio_sim_strdup_trimmed(page, count);
- if (!trimmed) {
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
- if (strcmp(trimmed, "input") == 0)
+ if (sysfs_streq(page, "input"))
dir = GPIOD_IN;
- else if (strcmp(trimmed, "output-high") == 0)
+ else if (sysfs_streq(page, "output-high"))
dir = GPIOD_OUT_HIGH;
- else if (strcmp(trimmed, "output-low") == 0)
+ else if (sysfs_streq(page, "output-low"))
dir = GPIOD_OUT_LOW;
else
- dir = -EINVAL;
-
- kfree(trimmed);
-
- if (dir < 0) {
- mutex_unlock(&dev->lock);
- return dir;
- }
+ return -EINVAL;
hog->dir = dir;
- mutex_unlock(&dev->lock);
-
return count;
}
@@ -1326,9 +1263,8 @@ static void gpio_sim_hog_config_item_release(struct config_item *item)
struct gpio_sim_line *line = hog->parent;
struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
- mutex_lock(&dev->lock);
- line->hog = NULL;
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ line->hog = NULL;
kfree(hog->name);
kfree(hog);
@@ -1354,13 +1290,11 @@ gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name)
if (strcmp(name, "hog") != 0)
return ERR_PTR(-EINVAL);
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
hog = kzalloc(sizeof(*hog), GFP_KERNEL);
- if (!hog) {
- mutex_unlock(&dev->lock);
+ if (!hog)
return ERR_PTR(-ENOMEM);
- }
config_item_init_type_name(&hog->item, name,
&gpio_sim_hog_config_type);
@@ -1370,8 +1304,6 @@ gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name)
hog->parent = line;
line->hog = hog;
- mutex_unlock(&dev->lock);
-
return &hog->item;
}
@@ -1380,9 +1312,8 @@ static void gpio_sim_line_config_group_release(struct config_item *item)
struct gpio_sim_line *line = to_gpio_sim_line(item);
struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
- mutex_lock(&dev->lock);
- list_del(&line->siblings);
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ list_del(&line->siblings);
kfree(line->name);
kfree(line);
@@ -1417,18 +1348,14 @@ gpio_sim_bank_config_make_line_group(struct config_group *group,
if (ret != 1 || nchar != strlen(name))
return ERR_PTR(-EINVAL);
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return ERR_PTR(-EBUSY);
- }
line = kzalloc(sizeof(*line), GFP_KERNEL);
- if (!line) {
- mutex_unlock(&dev->lock);
+ if (!line)
return ERR_PTR(-ENOMEM);
- }
config_group_init_type_name(&line->group, name,
&gpio_sim_line_config_type);
@@ -1437,8 +1364,6 @@ gpio_sim_bank_config_make_line_group(struct config_group *group,
line->offset = offset;
list_add_tail(&line->siblings, &bank->line_list);
- mutex_unlock(&dev->lock);
-
return &line->group;
}
@@ -1447,9 +1372,8 @@ static void gpio_sim_bank_config_group_release(struct config_item *item)
struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
- mutex_lock(&dev->lock);
- list_del(&bank->siblings);
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock)
+ list_del(&bank->siblings);
kfree(bank->label);
kfree(bank);
@@ -1477,18 +1401,14 @@ gpio_sim_device_config_make_bank_group(struct config_group *group,
struct gpio_sim_device *dev = to_gpio_sim_device(&group->cg_item);
struct gpio_sim_bank *bank;
- mutex_lock(&dev->lock);
+ guard(mutex)(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev)) {
- mutex_unlock(&dev->lock);
+ if (gpio_sim_device_is_live_unlocked(dev))
return ERR_PTR(-EBUSY);
- }
bank = kzalloc(sizeof(*bank), GFP_KERNEL);
- if (!bank) {
- mutex_unlock(&dev->lock);
+ if (!bank)
return ERR_PTR(-ENOMEM);
- }
config_group_init_type_name(&bank->group, name,
&gpio_sim_bank_config_group_type);
@@ -1497,8 +1417,6 @@ gpio_sim_device_config_make_bank_group(struct config_group *group,
INIT_LIST_HEAD(&bank->line_list);
list_add_tail(&bank->siblings, &dev->bank_list);
- mutex_unlock(&dev->lock);
-
return &bank->group;
}
@@ -1506,10 +1424,10 @@ static void gpio_sim_device_config_group_release(struct config_item *item)
{
struct gpio_sim_device *dev = to_gpio_sim_device(item);
- mutex_lock(&dev->lock);
- if (gpio_sim_device_is_live_unlocked(dev))
- gpio_sim_device_deactivate_unlocked(dev);
- mutex_unlock(&dev->lock);
+ scoped_guard(mutex, &dev->lock) {
+ if (gpio_sim_device_is_live_unlocked(dev))
+ gpio_sim_device_deactivate_unlocked(dev);
+ }
mutex_destroy(&dev->lock);
ida_free(&gpio_sim_ida, dev->id);
@@ -1534,7 +1452,7 @@ static const struct config_item_type gpio_sim_device_config_group_type = {
static struct config_group *
gpio_sim_config_make_device_group(struct config_group *group, const char *name)
{
- struct gpio_sim_device *dev;
+ struct gpio_sim_device *dev __free(kfree) = NULL;
int id;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1542,10 +1460,8 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name)
return ERR_PTR(-ENOMEM);
id = ida_alloc(&gpio_sim_ida, GFP_KERNEL);
- if (id < 0) {
- kfree(dev);
+ if (id < 0)
return ERR_PTR(id);
- }
config_group_init_type_name(&dev->group, name,
&gpio_sim_device_config_group_type);
@@ -1556,7 +1472,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name)
dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call;
init_completion(&dev->probe_completion);
- return &dev->group;
+ return &no_free_ptr(dev)->group;
}
static struct configfs_group_operations gpio_sim_config_group_ops = {
diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c
index 072b4e653216..c117c11bfb29 100644
--- a/drivers/gpio/gpio-sprd.c
+++ b/drivers/gpio/gpio-sprd.c
@@ -7,8 +7,8 @@
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 4750ea34204c..053d616f2e02 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -4,11 +4,12 @@
* Copyright (C) 2012 John Crispin <john@phrozen.org>
*/
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/mutex.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 6076937b18e7..6e1a2581e6ae 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -9,7 +9,6 @@
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
@@ -249,8 +248,6 @@ static int syscon_gpio_probe(struct platform_device *pdev)
priv->chip.direction_output = syscon_gpio_dir_out;
}
- platform_set_drvdata(pdev, priv);
-
return devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
}
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 5b265a6fd3c1..ea715582bcf3 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -15,7 +15,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio/driver.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/seq_file.h>
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 80d08ddde40e..d87dd06db40d 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -11,7 +11,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index de14949a3fe5..bbd9e9191199 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -256,8 +256,6 @@ static int timbgpio_probe(struct platform_device *pdev)
if (err)
return err;
- platform_set_drvdata(pdev, tgpio);
-
/* make sure to disable interrupts */
iowrite32(0x0, tgpio->membase + TGPIO_IER);
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index e1d425a18854..d7d9d50dcddf 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -216,7 +216,7 @@ MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table);
static struct platform_driver tps65218_gpio_driver = {
.driver = {
.name = "tps65218-gpio",
- .of_match_table = of_match_ptr(tps65218_dt_match)
+ .of_match_table = tps65218_dt_match,
},
.probe = tps65218_gpio_probe,
.id_table = tps65218_gpio_id_table,
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index c5713524b581..d277aa951143 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mfd/tps6586x.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
/* GPIO control registers */
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 321e6945f0be..187d21580573 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -15,7 +15,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps65910.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
struct tps65910_gpio {
struct gpio_chip gpio_chip;
diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c
index 6f8bd1155db7..3a28c1f273c3 100644
--- a/drivers/gpio/gpio-tqmx86.c
+++ b/drivers/gpio/gpio-tqmx86.c
@@ -277,8 +277,6 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD);
- platform_set_drvdata(pdev, gpio);
-
chip = &gpio->chip;
chip->label = "gpio-tqmx86";
chip->owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-ts4800.c b/drivers/gpio/gpio-ts4800.c
index 95d80ba14bee..4748e3d47106 100644
--- a/drivers/gpio/gpio-ts4800.c
+++ b/drivers/gpio/gpio-ts4800.c
@@ -7,8 +7,7 @@
#include <linux/gpio/driver.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#define DEFAULT_PIN_NUMBER 16
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
index eba96319dac2..0f6397b77c9d 100644
--- a/drivers/gpio/gpio-ts4900.c
+++ b/drivers/gpio/gpio-ts4900.c
@@ -8,7 +8,7 @@
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/regmap.h>
diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c
index 19ce6675cbc0..9725b7aa18a7 100644
--- a/drivers/gpio/gpio-uniphier.c
+++ b/drivers/gpio/gpio-uniphier.c
@@ -9,7 +9,6 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index d3f3a69d4907..dbc7ba0ee72c 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -17,7 +17,6 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
@@ -259,7 +258,6 @@ static void vf610_gpio_disable_clk(void *data)
static int vf610_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct vf610_gpio_port *port;
struct gpio_chip *gc;
struct gpio_irq_chip *girq;
@@ -319,7 +317,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
gc->parent = dev;
gc->label = dev_name(dev);
gc->ngpio = VF610_GPIO_PER_PORT;
- gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
+ gc->base = -1;
gc->request = gpiochip_generic_request;
gc->free = gpiochip_generic_free;
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 69713fd5485b..8fd6c3913d69 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -240,8 +240,6 @@ static int vx855gpio_probe(struct platform_device *pdev)
if (!vg)
return -ENOMEM;
- platform_set_drvdata(pdev, vg);
-
dev_info(&pdev->dev, "found VX855 GPIO controller\n");
vg->io_gpi = res_gpi->start;
vg->io_gpo = res_gpo->start;
diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c
index 817750e4e033..2bba27b13947 100644
--- a/drivers/gpio/gpio-wcd934x.c
+++ b/drivers/gpio/gpio-wcd934x.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#define WCD_PIN_MASK(p) BIT(p)
#define WCD_REG_DIR_CTL_OFFSET 0x42
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index afb42a8e916f..6289b0510cf2 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -3,19 +3,18 @@
* GPIO driver for the WinSystems WS16C48
* Copyright (C) 2016 William Breathitt Gray
*/
-#include <linux/bitmap.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/err.h>
+#include <linux/gpio/regmap.h>
+#include <linux/irq.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
#define WS16C48_EXTENT 11
@@ -31,371 +30,178 @@ static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
-/**
- * struct ws16c48_reg - device register structure
- * @port: Port 0 through 5 I/O
- * @int_pending: Interrupt Pending
- * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0)
- * @pol_enab_int_id: Interrupt polarity, enable, and ID
- */
-struct ws16c48_reg {
- u8 port[6];
- u8 int_pending;
- u8 page_lock;
- u8 pol_enab_int_id[3];
+#define WS16C48_DAT_BASE 0x0
+#define WS16C48_PAGE_LOCK 0x7
+#define WS16C48_PAGE_BASE 0x8
+#define WS16C48_POL WS16C48_PAGE_BASE
+#define WS16C48_ENAB WS16C48_PAGE_BASE
+#define WS16C48_INT_ID WS16C48_PAGE_BASE
+
+#define PAGE_LOCK_PAGE_FIELD GENMASK(7, 6)
+#define POL_PAGE u8_encode_bits(1, PAGE_LOCK_PAGE_FIELD)
+#define ENAB_PAGE u8_encode_bits(2, PAGE_LOCK_PAGE_FIELD)
+#define INT_ID_PAGE u8_encode_bits(3, PAGE_LOCK_PAGE_FIELD)
+
+static const struct regmap_range ws16c48_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x5), regmap_reg_range(0x7, 0xA),
+};
+static const struct regmap_range ws16c48_rd_ranges[] = {
+ regmap_reg_range(0x0, 0xA),
+};
+static const struct regmap_range ws16c48_volatile_ranges[] = {
+ regmap_reg_range(0x0, 0x6), regmap_reg_range(0x8, 0xA),
+};
+static const struct regmap_access_table ws16c48_wr_table = {
+ .yes_ranges = ws16c48_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ws16c48_wr_ranges),
+};
+static const struct regmap_access_table ws16c48_rd_table = {
+ .yes_ranges = ws16c48_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ws16c48_rd_ranges),
+};
+static const struct regmap_access_table ws16c48_volatile_table = {
+ .yes_ranges = ws16c48_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ws16c48_volatile_ranges),
+};
+static const struct regmap_config ws16c48_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .wr_table = &ws16c48_wr_table,
+ .rd_table = &ws16c48_rd_table,
+ .volatile_table = &ws16c48_volatile_table,
+ .cache_type = REGCACHE_FLAT,
+ .use_raw_spinlock = true,
+};
+
+#define WS16C48_NGPIO_PER_REG 8
+#define WS16C48_REGMAP_IRQ(_id) \
+ [_id] = { \
+ .reg_offset = (_id) / WS16C48_NGPIO_PER_REG, \
+ .mask = BIT((_id) % WS16C48_NGPIO_PER_REG), \
+ .type = { \
+ .type_reg_offset = (_id) / WS16C48_NGPIO_PER_REG, \
+ .types_supported = IRQ_TYPE_EDGE_BOTH, \
+ }, \
+ }
+
+/* Only the first 24 lines (Port 0-2) support interrupts */
+#define WS16C48_NUM_IRQS 24
+static const struct regmap_irq ws16c48_regmap_irqs[WS16C48_NUM_IRQS] = {
+ WS16C48_REGMAP_IRQ(0), WS16C48_REGMAP_IRQ(1), WS16C48_REGMAP_IRQ(2), /* 0-2 */
+ WS16C48_REGMAP_IRQ(3), WS16C48_REGMAP_IRQ(4), WS16C48_REGMAP_IRQ(5), /* 3-5 */
+ WS16C48_REGMAP_IRQ(6), WS16C48_REGMAP_IRQ(7), WS16C48_REGMAP_IRQ(8), /* 6-8 */
+ WS16C48_REGMAP_IRQ(9), WS16C48_REGMAP_IRQ(10), WS16C48_REGMAP_IRQ(11), /* 9-11 */
+ WS16C48_REGMAP_IRQ(12), WS16C48_REGMAP_IRQ(13), WS16C48_REGMAP_IRQ(14), /* 12-14 */
+ WS16C48_REGMAP_IRQ(15), WS16C48_REGMAP_IRQ(16), WS16C48_REGMAP_IRQ(17), /* 15-17 */
+ WS16C48_REGMAP_IRQ(18), WS16C48_REGMAP_IRQ(19), WS16C48_REGMAP_IRQ(20), /* 18-20 */
+ WS16C48_REGMAP_IRQ(21), WS16C48_REGMAP_IRQ(22), WS16C48_REGMAP_IRQ(23), /* 21-23 */
};
/**
* struct ws16c48_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @io_state: bit I/O state (whether bit is set to input or output)
- * @out_state: output bits state
+ * @map: regmap for the device
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
- * @flow_mask: IRQ flow type mask for the respective I/O bits
- * @reg: I/O address offset for the device registers
*/
struct ws16c48_gpio {
- struct gpio_chip chip;
- unsigned char io_state[6];
- unsigned char out_state[6];
+ struct regmap *map;
raw_spinlock_t lock;
- unsigned long irq_mask;
- unsigned long flow_mask;
- struct ws16c48_reg __iomem *reg;
+ u8 irq_mask[WS16C48_NUM_IRQS / WS16C48_NGPIO_PER_REG];
};
-static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int ws16c48_handle_pre_irq(void *const irq_drv_data) __acquires(&ws16c48gpio->lock)
{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
+ struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
- if (ws16c48gpio->io_state[port] & mask)
- return GPIO_LINE_DIRECTION_IN;
-
- return GPIO_LINE_DIRECTION_OUT;
-}
-
-static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- ws16c48gpio->io_state[port] |= mask;
- ws16c48gpio->out_state[port] &= ~mask;
- iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+ /* Lock to prevent Page/Lock register change while we handle IRQ */
+ raw_spin_lock(&ws16c48gpio->lock);
return 0;
}
-static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
+static int ws16c48_handle_post_irq(void *const irq_drv_data) __releases(&ws16c48gpio->lock)
{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
+ struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
- ws16c48gpio->io_state[port] &= ~mask;
- if (value)
- ws16c48gpio->out_state[port] |= mask;
- else
- ws16c48gpio->out_state[port] &= ~mask;
- iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+ raw_spin_unlock(&ws16c48gpio->lock);
return 0;
}
-static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
- unsigned long flags;
- unsigned port_state;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- /* ensure that GPIO is set for input */
- if (!(ws16c48gpio->io_state[port] & mask)) {
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- return -EINVAL;
- }
-
- port_state = ioread8(ws16c48gpio->reg->port + port);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-
- return !!(port_state & mask);
-}
-
-static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- size_t index;
- u8 __iomem *port_addr;
- unsigned long port_state;
-
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
-
- for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
- index = offset / 8;
- port_addr = ws16c48gpio->reg->port + index;
- port_state = ioread8(port_addr) & gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
-
- return 0;
-}
-
-static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- /* ensure that GPIO is set for output */
- if (ws16c48gpio->io_state[port] & mask) {
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- return;
- }
-
- if (value)
- ws16c48gpio->out_state[port] |= mask;
- else
- ws16c48gpio->out_state[port] &= ~mask;
- iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-}
-
-static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- size_t index;
- u8 __iomem *port_addr;
- unsigned long bitmask;
- unsigned long flags;
-
- for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
- index = offset / 8;
- port_addr = ws16c48gpio->reg->port + index;
-
- /* mask out GPIO configured for input */
- gpio_mask &= ~ws16c48gpio->io_state[index];
- bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- /* update output state data and set device gpio register */
- ws16c48gpio->out_state[index] &= ~gpio_mask;
- ws16c48gpio->out_state[index] |= bitmask;
- iowrite8(ws16c48gpio->out_state[index], port_addr);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- }
-}
-
-static void ws16c48_irq_ack(struct irq_data *data)
+static int ws16c48_handle_mask_sync(const int index, const unsigned int mask_buf_def,
+ const unsigned int mask_buf, void *const irq_drv_data)
{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- const unsigned port = offset / 8;
- const unsigned mask = BIT(offset % 8);
+ struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
unsigned long flags;
- unsigned port_state;
-
- /* only the first 3 ports support interrupts */
- if (port > 2)
- return;
+ int ret = 0;
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
- port_state = ws16c48gpio->irq_mask >> (8*port);
+ /* exit early if no change since the last mask sync */
+ if (mask_buf == ws16c48gpio->irq_mask[index])
+ goto exit_unlock;
+ ws16c48gpio->irq_mask[index] = mask_buf;
- /* Select Register Page 2; Unlock all I/O ports */
- iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+ ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, ENAB_PAGE);
+ if (ret)
+ goto exit_unlock;
- /* Clear pending interrupt */
- iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
- iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
+ /* Update ENAB register (inverted mask) */
+ ret = regmap_write(ws16c48gpio->map, WS16C48_ENAB + index, ~mask_buf);
+ if (ret)
+ goto exit_unlock;
- /* Select Register Page 3; Unlock all I/O ports */
- iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+ ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
+ if (ret)
+ goto exit_unlock;
+exit_unlock:
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-}
-
-static void ws16c48_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- const unsigned long mask = BIT(offset);
- const unsigned port = offset / 8;
- unsigned long flags;
- unsigned long port_state;
-
- /* only the first 3 ports support interrupts */
- if (port > 2)
- return;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
- ws16c48gpio->irq_mask &= ~mask;
- gpiochip_disable_irq(chip, offset);
- port_state = ws16c48gpio->irq_mask >> (8 * port);
-
- /* Select Register Page 2; Unlock all I/O ports */
- iowrite8(0x80, &ws16c48gpio->reg->page_lock);
-
- /* Disable interrupt */
- iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
-
- /* Select Register Page 3; Unlock all I/O ports */
- iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+ return ret;
}
-static void ws16c48_irq_unmask(struct irq_data *data)
+static int ws16c48_set_type_config(unsigned int **const buf, const unsigned int type,
+ const struct regmap_irq *const irq_data, const int idx,
+ void *const irq_drv_data)
{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- const unsigned long mask = BIT(offset);
- const unsigned port = offset / 8;
+ struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
+ unsigned int polarity;
unsigned long flags;
- unsigned long port_state;
-
- /* only the first 3 ports support interrupts */
- if (port > 2)
- return;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- gpiochip_enable_irq(chip, offset);
- ws16c48gpio->irq_mask |= mask;
- port_state = ws16c48gpio->irq_mask >> (8 * port);
-
- /* Select Register Page 2; Unlock all I/O ports */
- iowrite8(0x80, &ws16c48gpio->reg->page_lock);
-
- /* Enable interrupt */
- iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
-
- /* Select Register Page 3; Unlock all I/O ports */
- iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
-
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-}
+ int ret;
-static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- const unsigned long mask = BIT(offset);
- const unsigned port = offset / 8;
- unsigned long flags;
- unsigned long port_state;
-
- /* only the first 3 ports support interrupts */
- if (port > 2)
- return -EINVAL;
-
- raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-
- switch (flow_type) {
- case IRQ_TYPE_NONE:
- break;
+ switch (type) {
case IRQ_TYPE_EDGE_RISING:
- ws16c48gpio->flow_mask |= mask;
+ polarity = irq_data->mask;
break;
case IRQ_TYPE_EDGE_FALLING:
- ws16c48gpio->flow_mask &= ~mask;
+ polarity = 0;
break;
default:
- raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
return -EINVAL;
}
- port_state = ws16c48gpio->flow_mask >> (8 * port);
+ raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
- /* Select Register Page 1; Unlock all I/O ports */
- iowrite8(0x40, &ws16c48gpio->reg->page_lock);
+ ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, POL_PAGE);
+ if (ret)
+ goto exit_unlock;
/* Set interrupt polarity */
- iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
+ ret = regmap_update_bits(ws16c48gpio->map, WS16C48_POL + idx, irq_data->mask, polarity);
+ if (ret)
+ goto exit_unlock;
- /* Select Register Page 3; Unlock all I/O ports */
- iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+ ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
+ if (ret)
+ goto exit_unlock;
+exit_unlock:
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- return 0;
-}
-
-static const struct irq_chip ws16c48_irqchip = {
- .name = "ws16c48",
- .irq_ack = ws16c48_irq_ack,
- .irq_mask = ws16c48_irq_mask,
- .irq_unmask = ws16c48_irq_unmask,
- .irq_set_type = ws16c48_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
-};
-
-static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
-{
- struct ws16c48_gpio *const ws16c48gpio = dev_id;
- struct gpio_chip *const chip = &ws16c48gpio->chip;
- struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
- unsigned long int_pending;
- unsigned long port;
- unsigned long int_id;
- unsigned long gpio;
-
- int_pending = ioread8(&reg->int_pending) & 0x7;
- if (!int_pending)
- return IRQ_NONE;
-
- /* loop until all pending interrupts are handled */
- do {
- for_each_set_bit(port, &int_pending, 3) {
- int_id = ioread8(reg->pol_enab_int_id + port);
- for_each_set_bit(gpio, &int_id, 8)
- generic_handle_domain_irq(chip->irq.domain,
- gpio + 8*port);
- }
-
- int_pending = ioread8(&reg->int_pending) & 0x7;
- } while (int_pending);
-
- return IRQ_HANDLED;
+ return ret;
}
#define WS16C48_NGPIO 48
@@ -414,30 +220,37 @@ static const char *ws16c48_names[WS16C48_NGPIO] = {
"Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7"
};
-static int ws16c48_irq_init_hw(struct gpio_chip *gc)
+static int ws16c48_irq_init_hw(struct regmap *const map)
{
- struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);
+ int err;
- /* Select Register Page 2; Unlock all I/O ports */
- iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+ err = regmap_write(map, WS16C48_PAGE_LOCK, ENAB_PAGE);
+ if (err)
+ return err;
/* Disable interrupts for all lines */
- iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
- iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
- iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
-
- /* Select Register Page 3; Unlock all I/O ports */
- iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+ err = regmap_write(map, WS16C48_ENAB + 0, 0x00);
+ if (err)
+ return err;
+ err = regmap_write(map, WS16C48_ENAB + 1, 0x00);
+ if (err)
+ return err;
+ err = regmap_write(map, WS16C48_ENAB + 2, 0x00);
+ if (err)
+ return err;
- return 0;
+ return regmap_write(map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
}
static int ws16c48_probe(struct device *dev, unsigned int id)
{
struct ws16c48_gpio *ws16c48gpio;
const char *const name = dev_name(dev);
- struct gpio_irq_chip *girq;
int err;
+ struct gpio_regmap_config gpio_config = {};
+ void __iomem *regs;
+ struct regmap_irq_chip *chip;
+ struct regmap_irq_chip_data *chip_data;
ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
if (!ws16c48gpio)
@@ -449,50 +262,55 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
- ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
- if (!ws16c48gpio->reg)
+ regs = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
+ if (!regs)
return -ENOMEM;
- ws16c48gpio->chip.label = name;
- ws16c48gpio->chip.parent = dev;
- ws16c48gpio->chip.owner = THIS_MODULE;
- ws16c48gpio->chip.base = -1;
- ws16c48gpio->chip.ngpio = WS16C48_NGPIO;
- ws16c48gpio->chip.names = ws16c48_names;
- ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction;
- ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
- ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
- ws16c48gpio->chip.get = ws16c48_gpio_get;
- ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
- ws16c48gpio->chip.set = ws16c48_gpio_set;
- ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
-
- girq = &ws16c48gpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &ws16c48_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
- girq->init_hw = ws16c48_irq_init_hw;
+ ws16c48gpio->map = devm_regmap_init_mmio(dev, regs, &ws16c48_regmap_config);
+ if (IS_ERR(ws16c48gpio->map))
+ return dev_err_probe(dev, PTR_ERR(ws16c48gpio->map),
+ "Unable to initialize register map\n");
- raw_spin_lock_init(&ws16c48gpio->lock);
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
- err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
+ chip->name = name;
+ chip->status_base = WS16C48_INT_ID;
+ chip->mask_base = WS16C48_ENAB;
+ chip->ack_base = WS16C48_INT_ID;
+ chip->num_regs = 3;
+ chip->irqs = ws16c48_regmap_irqs;
+ chip->num_irqs = ARRAY_SIZE(ws16c48_regmap_irqs);
+ chip->handle_pre_irq = ws16c48_handle_pre_irq;
+ chip->handle_post_irq = ws16c48_handle_post_irq;
+ chip->handle_mask_sync = ws16c48_handle_mask_sync;
+ chip->set_type_config = ws16c48_set_type_config;
+ chip->irq_drv_data = ws16c48gpio;
- err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED,
- name, ws16c48gpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+ raw_spin_lock_init(&ws16c48gpio->lock);
+
+ /* Initialize to prevent spurious interrupts before we're ready */
+ err = ws16c48_irq_init_hw(ws16c48gpio->map);
+ if (err)
return err;
- }
- return 0;
+ err = devm_regmap_add_irq_chip(dev, ws16c48gpio->map, irq[id], 0, 0, chip, &chip_data);
+ if (err)
+ return dev_err_probe(dev, err, "IRQ registration failed\n");
+
+ gpio_config.parent = dev;
+ gpio_config.regmap = ws16c48gpio->map;
+ gpio_config.ngpio = WS16C48_NGPIO;
+ gpio_config.names = ws16c48_names;
+ gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+ gpio_config.reg_set_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+ /* Setting a GPIO to 0 allows it to be used as an input */
+ gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+ gpio_config.ngpio_per_reg = WS16C48_NGPIO_PER_REG;
+ gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
}
static struct isa_driver ws16c48_driver = {
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 1fa66f2a667f..a16945e8319e 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -15,8 +15,8 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c
index bbc06cdd9634..dc2710c21c50 100644
--- a/drivers/gpio/gpio-xra1403.c
+++ b/drivers/gpio/gpio-xra1403.c
@@ -8,9 +8,9 @@
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/seq_file.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
@@ -194,7 +194,7 @@ static const struct spi_device_id xra1403_ids[] = {
};
MODULE_DEVICE_TABLE(spi, xra1403_ids);
-static const struct of_device_id xra1403_spi_of_match[] __maybe_unused = {
+static const struct of_device_id xra1403_spi_of_match[] = {
{ .compatible = "exar,xra1403" },
{},
};
@@ -205,7 +205,7 @@ static struct spi_driver xra1403_driver = {
.id_table = xra1403_ids,
.driver = {
.name = "xra1403",
- .of_match_table = of_match_ptr(xra1403_spi_of_match),
+ .of_match_table = xra1403_spi_of_match,
},
};
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index f0f571b323f2..2de61337ad3b 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -176,8 +176,6 @@ static int zevio_gpio_probe(struct platform_device *pdev)
if (!controller)
return -ENOMEM;
- platform_set_drvdata(pdev, controller);
-
/* Copy our reference */
controller->chip = zevio_gpio_chip;
controller->chip.parent = &pdev->dev;
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 97496c0f9133..fbda452fb4d6 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -128,7 +128,7 @@ static bool acpi_gpio_deferred_req_irqs_done;
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
- return ACPI_HANDLE_FWNODE(gc->fwnode) == data;
+ return device_match_acpi_handle(&gc->gpiodev->dev, data);
}
/**
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 0a33971c964c..e39d344feb28 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -230,9 +230,7 @@ static long linehandle_set_config(struct linehandle_state *lh,
return ret;
}
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIO_V2_LINE_CHANGED_CONFIG,
- desc);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG);
}
return 0;
}
@@ -414,8 +412,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
goto out_free_lh;
}
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIO_V2_LINE_CHANGED_REQUESTED, desc);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
offset);
@@ -555,6 +552,7 @@ struct line {
* @label: consumer label used to tag GPIO descriptors
* @num_lines: the number of lines in the lines array
* @wait: wait queue that handles blocking reads of events
+ * @device_unregistered_nb: notifier block for receiving gdev unregister events
* @event_buffer_size: the number of elements allocated in @events
* @events: KFIFO for the GPIO events
* @seqno: the sequence number for edge events generated on all lines in
@@ -569,6 +567,7 @@ struct linereq {
const char *label;
u32 num_lines;
wait_queue_head_t wait;
+ struct notifier_block device_unregistered_nb;
u32 event_buffer_size;
DECLARE_KFIFO_PTR(events, struct gpio_v2_line_event);
atomic_t seqno;
@@ -610,6 +609,17 @@ struct linereq {
GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_EDGE_FLAGS)
+static int linereq_unregistered_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct linereq *lr = container_of(nb, struct linereq,
+ device_unregistered_nb);
+
+ wake_up_poll(&lr->wait, EPOLLIN | EPOLLERR);
+
+ return NOTIFY_OK;
+}
+
static void linereq_put_event(struct linereq *lr,
struct gpio_v2_line_event *le)
{
@@ -1407,9 +1417,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
WRITE_ONCE(line->edflags, edflags);
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIO_V2_LINE_CHANGED_CONFIG,
- desc);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG);
}
return 0;
}
@@ -1567,6 +1575,10 @@ static void linereq_free(struct linereq *lr)
{
unsigned int i;
+ if (lr->device_unregistered_nb.notifier_call)
+ blocking_notifier_chain_unregister(&lr->gdev->device_notifier,
+ &lr->device_unregistered_nb);
+
for (i = 0; i < lr->num_lines; i++) {
if (lr->lines[i].desc) {
edge_detector_stop(&lr->lines[i]);
@@ -1720,13 +1732,18 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
lr->lines[i].edflags = edflags;
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIO_V2_LINE_CHANGED_REQUESTED, desc);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
offset);
}
+ lr->device_unregistered_nb.notifier_call = linereq_unregistered_notify;
+ ret = blocking_notifier_chain_register(&gdev->device_notifier,
+ &lr->device_unregistered_nb);
+ if (ret)
+ goto out_free_linereq;
+
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
if (fd < 0) {
ret = fd;
@@ -1779,6 +1796,7 @@ out_free_linereq:
* @eflags: the event flags this line was requested with
* @irq: the interrupt that trigger in response to events on this GPIO
* @wait: wait queue that handles blocking reads of events
+ * @device_unregistered_nb: notifier block for receiving gdev unregister events
* @events: KFIFO for the GPIO events
* @timestamp: cache for the timestamp storing it between hardirq
* and IRQ thread, used to bring the timestamp close to the actual
@@ -1791,6 +1809,7 @@ struct lineevent_state {
u32 eflags;
int irq;
wait_queue_head_t wait;
+ struct notifier_block device_unregistered_nb;
DECLARE_KFIFO(events, struct gpioevent_data, 16);
u64 timestamp;
};
@@ -1824,6 +1843,17 @@ static __poll_t lineevent_poll(struct file *file,
return call_poll_locked(file, wait, le->gdev, lineevent_poll_unlocked);
}
+static int lineevent_unregistered_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct lineevent_state *le = container_of(nb, struct lineevent_state,
+ device_unregistered_nb);
+
+ wake_up_poll(&le->wait, EPOLLIN | EPOLLERR);
+
+ return NOTIFY_OK;
+}
+
struct compat_gpioeevent_data {
compat_u64 timestamp;
u32 id;
@@ -1909,6 +1939,9 @@ static ssize_t lineevent_read(struct file *file, char __user *buf,
static void lineevent_free(struct lineevent_state *le)
{
+ if (le->device_unregistered_nb.notifier_call)
+ blocking_notifier_chain_unregister(&le->gdev->device_notifier,
+ &le->device_unregistered_nb);
if (le->irq)
free_irq(le->irq, le);
if (le->desc)
@@ -2117,8 +2150,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
if (ret)
goto out_free_le;
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIO_V2_LINE_CHANGED_REQUESTED, desc);
+ gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
irq = gpiod_to_irq(desc);
if (irq <= 0) {
@@ -2137,6 +2169,12 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait);
+ le->device_unregistered_nb.notifier_call = lineevent_unregistered_notify;
+ ret = blocking_notifier_chain_register(&gdev->device_notifier,
+ &le->device_unregistered_nb);
+ if (ret)
+ goto out_free_le;
+
/* Request a thread to read the events */
ret = request_threaded_irq(irq,
lineevent_irq_handler,
@@ -2320,6 +2358,7 @@ struct gpio_chardev_data {
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpio_v2_line_info_changed, 32);
struct notifier_block lineinfo_changed_nb;
+ struct notifier_block device_unregistered_nb;
unsigned long *watched_lines;
#ifdef CONFIG_GPIO_CDEV_V1
atomic_t watch_abi_version;
@@ -2491,16 +2530,11 @@ static long gpio_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif
-static struct gpio_chardev_data *
-to_gpio_chardev_data(struct notifier_block *nb)
-{
- return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
-}
-
static int lineinfo_changed_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
- struct gpio_chardev_data *cdev = to_gpio_chardev_data(nb);
+ struct gpio_chardev_data *cdev =
+ container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
struct gpio_v2_line_info_changed chg;
struct gpio_desc *desc = data;
int ret;
@@ -2522,6 +2556,18 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
+static int gpio_device_unregistered_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct gpio_chardev_data *cdev = container_of(nb,
+ struct gpio_chardev_data,
+ device_unregistered_nb);
+
+ wake_up_poll(&cdev->wait, EPOLLIN | EPOLLERR);
+
+ return NOTIFY_OK;
+}
+
static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
struct poll_table_struct *pollt)
{
@@ -2671,23 +2717,33 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
cdev->gdev = gpio_device_get(gdev);
cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
- ret = blocking_notifier_chain_register(&gdev->notifier,
+ ret = blocking_notifier_chain_register(&gdev->line_state_notifier,
&cdev->lineinfo_changed_nb);
if (ret)
goto out_free_bitmap;
+ cdev->device_unregistered_nb.notifier_call =
+ gpio_device_unregistered_notify;
+ ret = blocking_notifier_chain_register(&gdev->device_notifier,
+ &cdev->device_unregistered_nb);
+ if (ret)
+ goto out_unregister_line_notifier;
+
file->private_data = cdev;
ret = nonseekable_open(inode, file);
if (ret)
- goto out_unregister_notifier;
+ goto out_unregister_device_notifier;
up_read(&gdev->sem);
return ret;
-out_unregister_notifier:
- blocking_notifier_chain_unregister(&gdev->notifier,
+out_unregister_device_notifier:
+ blocking_notifier_chain_unregister(&gdev->device_notifier,
+ &cdev->device_unregistered_nb);
+out_unregister_line_notifier:
+ blocking_notifier_chain_unregister(&gdev->line_state_notifier,
&cdev->lineinfo_changed_nb);
out_free_bitmap:
gpio_device_put(gdev);
@@ -2711,7 +2767,9 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file)
struct gpio_device *gdev = cdev->gdev;
bitmap_free(cdev->watched_lines);
- blocking_notifier_chain_unregister(&gdev->notifier,
+ blocking_notifier_chain_unregister(&gdev->device_notifier,
+ &cdev->device_unregistered_nb);
+ blocking_notifier_chain_unregister(&gdev->line_state_notifier,
&cdev->lineinfo_changed_nb);
gpio_device_put(gdev);
kfree(cdev);
@@ -2753,4 +2811,5 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
void gpiolib_cdev_unregister(struct gpio_device *gdev)
{
cdev_device_del(&gdev->chrdev, &gdev->dev);
+ blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL);
}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 1436cdb5fa26..531faabead0f 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -209,6 +209,8 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np,
const char *propname,
enum of_gpio_flags *flags)
{
+ const struct device_node *np_compat = np;
+ const struct device_node *np_propname = np;
static const struct {
const char *compatible;
const char *gpio_propname;
@@ -253,14 +255,28 @@ static void of_gpio_set_polarity_by_property(const struct device_node *np,
{ "regulator-gpio", "enable-gpio", "enable-active-high" },
{ "regulator-gpio", "enable-gpios", "enable-active-high" },
#endif
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { "atmel,hsmci", "cd-gpios", "cd-inverted" },
+#endif
};
unsigned int i;
bool active_high;
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ /*
+ * The Atmel HSMCI has compatible property in the parent node and
+ * gpio property in a child node
+ */
+ if (of_device_is_compatible(np->parent, "atmel,hsmci")) {
+ np_compat = np->parent;
+ np_propname = np;
+ }
+#endif
+
for (i = 0; i < ARRAY_SIZE(gpios); i++) {
- if (of_device_is_compatible(np, gpios[i].compatible) &&
+ if (of_device_is_compatible(np_compat, gpios[i].compatible) &&
!strcmp(propname, gpios[i].gpio_propname)) {
- active_high = of_property_read_bool(np,
+ active_high = of_property_read_bool(np_propname,
gpios[i].polarity_propname);
of_gpio_quirk_polarity(np, active_high, flags);
break;
@@ -1078,16 +1094,16 @@ int of_gpiochip_add(struct gpio_chip *chip)
if (ret)
return ret;
- fwnode_handle_get(chip->fwnode);
+ of_node_get(np);
ret = of_gpiochip_scan_gpios(chip);
if (ret)
- fwnode_handle_put(chip->fwnode);
+ of_node_put(np);
return ret;
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
- fwnode_handle_put(chip->fwnode);
+ of_node_put(dev_of_node(&chip->gpiodev->dev));
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 76e0c38026c3..40a0022ea719 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -700,6 +700,40 @@ void *gpiochip_get_data(struct gpio_chip *gc)
}
EXPORT_SYMBOL_GPL(gpiochip_get_data);
+int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev)
+{
+ u32 ngpios = gc->ngpio;
+ int ret;
+
+ if (ngpios == 0) {
+ ret = device_property_read_u32(dev, "ngpios", &ngpios);
+ if (ret == -ENODATA)
+ /*
+ * -ENODATA means that there is no property found and
+ * we want to issue the error message to the user.
+ * Besides that, we want to return different error code
+ * to state that supplied value is not valid.
+ */
+ ngpios = 0;
+ else if (ret)
+ return ret;
+
+ gc->ngpio = ngpios;
+ }
+
+ if (gc->ngpio == 0) {
+ chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
+ return -EINVAL;
+ }
+
+ if (gc->ngpio > FASTPATH_NGPIO)
+ chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
+ gc->ngpio, FASTPATH_NGPIO);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_get_ngpios);
+
int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
@@ -707,18 +741,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct gpio_device *gdev;
unsigned long flags;
unsigned int i;
- u32 ngpios = 0;
int base = 0;
int ret = 0;
/*
- * If the calling driver did not initialize firmware node, do it here
- * using the parent device, if any.
- */
- if (!gc->fwnode && gc->parent)
- gc->fwnode = dev_fwnode(gc->parent);
-
- /*
* First: allocate and populate the internal stat container, and
* set up the struct device.
*/
@@ -732,7 +758,14 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
gc->gpiodev = gdev;
gpiochip_set_data(gc, data);
- device_set_node(&gdev->dev, gc->fwnode);
+ /*
+ * If the calling driver did not initialize firmware node,
+ * do it here using the parent device, if any.
+ */
+ if (gc->fwnode)
+ device_set_node(&gdev->dev, gc->fwnode);
+ else if (gc->parent)
+ device_set_node(&gdev->dev, dev_fwnode(gc->parent));
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
if (gdev->id < 0) {
@@ -753,36 +786,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
else
gdev->owner = THIS_MODULE;
- /*
- * Try the device properties if the driver didn't supply the number
- * of GPIO lines.
- */
- ngpios = gc->ngpio;
- if (ngpios == 0) {
- ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios);
- if (ret == -ENODATA)
- /*
- * -ENODATA means that there is no property found and
- * we want to issue the error message to the user.
- * Besides that, we want to return different error code
- * to state that supplied value is not valid.
- */
- ngpios = 0;
- else if (ret)
- goto err_free_dev_name;
-
- gc->ngpio = ngpios;
- }
-
- if (gc->ngpio == 0) {
- chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
- ret = -EINVAL;
+ ret = gpiochip_get_ngpios(gc, &gdev->dev);
+ if (ret)
goto err_free_dev_name;
- }
-
- if (gc->ngpio > FASTPATH_NGPIO)
- chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
- gc->ngpio, FASTPATH_NGPIO);
gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL);
if (!gdev->descs) {
@@ -841,7 +847,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
spin_unlock_irqrestore(&gpio_lock, flags);
- BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier);
+ BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
+ BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
init_rwsem(&gdev->sem);
#ifdef CONFIG_PINCTRL
@@ -947,7 +954,7 @@ err_print_message:
/* failures here can mean systems won't boot... */
if (ret != -EPROBE_DEFER) {
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
- base, base + (int)ngpios - 1,
+ base, base + (int)gc->ngpio - 1,
gc->label ? : "generic", ret);
}
return ret;
@@ -1292,12 +1299,14 @@ static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops)
ops->free = irq_domain_free_irqs_common;
}
-static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc)
{
+ struct irq_domain *domain;
+
if (!gc->irq.child_to_parent_hwirq ||
!gc->irq.fwnode) {
chip_err(gc, "missing irqdomain vital data\n");
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
if (!gc->irq.child_offset_to_irq)
@@ -1309,7 +1318,7 @@ static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops);
- gc->irq.domain = irq_domain_create_hierarchy(
+ domain = irq_domain_create_hierarchy(
gc->irq.parent_domain,
0,
gc->ngpio,
@@ -1317,12 +1326,12 @@ static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
&gc->irq.child_irq_domain_ops,
gc);
- if (!gc->irq.domain)
- return -ENOMEM;
+ if (!domain)
+ return ERR_PTR(-ENOMEM);
gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip);
- return 0;
+ return domain;
}
static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
@@ -1366,9 +1375,9 @@ EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
#else
-static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc)
{
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
@@ -1445,6 +1454,19 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
+static struct irq_domain *gpiochip_simple_create_domain(struct gpio_chip *gc)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(&gc->gpiodev->dev);
+ struct irq_domain *domain;
+
+ domain = irq_domain_create_simple(fwnode, gc->ngpio, gc->irq.first,
+ &gpiochip_domain_ops, gc);
+ if (!domain)
+ return ERR_PTR(-EINVAL);
+
+ return domain;
+}
+
/*
* TODO: move these activate/deactivate in under the hierarchicial
* irqchip implementation as static once SPMI and SSBI (all external
@@ -1623,6 +1645,31 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
}
}
+static int gpiochip_irqchip_add_allocated_domain(struct gpio_chip *gc,
+ struct irq_domain *domain,
+ bool allocated_externally)
+{
+ if (!domain)
+ return -EINVAL;
+
+ if (gc->to_irq)
+ chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
+
+ gc->to_irq = gpiochip_to_irq;
+ gc->irq.domain = domain;
+ gc->irq.domain_is_allocated_externally = allocated_externally;
+
+ /*
+ * Using barrier() here to prevent compiler from reordering
+ * gc->irq.initialized before adding irqdomain.
+ */
+ barrier();
+
+ gc->irq.initialized = true;
+
+ return 0;
+}
+
/**
* gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
* @gc: the GPIO chip to add the IRQ chip to
@@ -1635,8 +1682,10 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
{
struct fwnode_handle *fwnode = dev_fwnode(&gc->gpiodev->dev);
struct irq_chip *irqchip = gc->irq.chip;
+ struct irq_domain *domain;
unsigned int type;
unsigned int i;
+ int ret;
if (!irqchip)
return 0;
@@ -1657,28 +1706,18 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
"%pfw: Ignoring %u default trigger\n", fwnode, type))
type = IRQ_TYPE_NONE;
- if (gc->to_irq)
- chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
-
- gc->to_irq = gpiochip_to_irq;
gc->irq.default_type = type;
gc->irq.lock_key = lock_key;
gc->irq.request_key = request_key;
/* If a parent irqdomain is provided, let's build a hierarchy */
if (gpiochip_hierarchy_is_hierarchical(gc)) {
- int ret = gpiochip_hierarchy_add_domain(gc);
- if (ret)
- return ret;
+ domain = gpiochip_hierarchy_create_domain(gc);
} else {
- gc->irq.domain = irq_domain_create_simple(fwnode,
- gc->ngpio,
- gc->irq.first,
- &gpiochip_domain_ops,
- gc);
- if (!gc->irq.domain)
- return -EINVAL;
+ domain = gpiochip_simple_create_domain(gc);
}
+ if (IS_ERR(domain))
+ return PTR_ERR(domain);
if (gc->irq.parent_handler) {
for (i = 0; i < gc->irq.num_parents; i++) {
@@ -1702,14 +1741,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
gpiochip_set_irq_hooks(gc);
- /*
- * Using barrier() here to prevent compiler from reordering
- * gc->irq.initialized before initialization of above
- * GPIO chip irq members.
- */
- barrier();
-
- gc->irq.initialized = true;
+ ret = gpiochip_irqchip_add_allocated_domain(gc, domain, false);
+ if (ret)
+ return ret;
acpi_gpiochip_request_interrupts(gc);
@@ -1780,22 +1814,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
struct irq_domain *domain)
{
- if (!domain)
- return -EINVAL;
-
- gc->to_irq = gpiochip_to_irq;
- gc->irq.domain = domain;
- gc->irq.domain_is_allocated_externally = true;
-
- /*
- * Using barrier() here to prevent compiler from reordering
- * gc->irq.initialized before adding irqdomain.
- */
- barrier();
-
- gc->irq.initialized = true;
-
- return 0;
+ return gpiochip_irqchip_add_allocated_domain(gc, domain, true);
}
EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain);
@@ -2159,8 +2178,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
}
spin_unlock_irqrestore(&gpio_lock, flags);
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIOLINE_CHANGED_RELEASED, desc);
+ gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED);
return ret;
}
@@ -3728,6 +3746,12 @@ int gpiod_set_array_value_cansleep(unsigned int array_size,
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
+void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action)
+{
+ blocking_notifier_call_chain(&desc->gdev->line_state_notifier,
+ action, desc);
+}
+
/**
* gpiod_add_lookup_table() - register GPIO device consumers
* @table: table of consumers to register
@@ -3995,8 +4019,7 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
return ERR_PTR(ret);
}
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIOLINE_CHANGED_REQUESTED, desc);
+ gpiod_line_state_notify(desc, GPIOLINE_CHANGED_REQUESTED);
return desc;
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index cca81375f127..a0a67569300b 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -9,12 +9,13 @@
#ifndef GPIOLIB_H
#define GPIOLIB_H
-#include <linux/gpio/driver.h>
-#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
-#include <linux/err.h>
+#include <linux/cdev.h>
#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
+#include <linux/gpio/driver.h>
#include <linux/module.h>
-#include <linux/cdev.h>
+#include <linux/notifier.h>
#include <linux/rwsem.h>
#define GPIOCHIP_NAME "gpiochip"
@@ -38,8 +39,10 @@
* or name of the IP component in a System on Chip.
* @data: per-instance data assigned by the driver
* @list: links gpio_device:s together for traversal
- * @notifier: used to notify subscribers about lines being requested, released
- * or reconfigured
+ * @line_state_notifier: used to notify subscribers about lines being
+ * requested, released or reconfigured
+ * @device_notifier: used to notify character device wait queues about the GPIO
+ * device being unregistered
* @sem: protects the structure from a NULL-pointer dereference of @chip by
* user-space operations when the device gets unregistered during
* a hot-unplug event
@@ -63,7 +66,8 @@ struct gpio_device {
const char *label;
void *data;
struct list_head list;
- struct blocking_notifier_head notifier;
+ struct blocking_notifier_head line_state_notifier;
+ struct blocking_notifier_head device_notifier;
struct rw_semaphore sem;
#ifdef CONFIG_PINCTRL
@@ -143,6 +147,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
extern spinlock_t gpio_lock;
extern struct list_head gpio_devices;
+void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
/**
* struct gpio_desc - Opaque descriptor for a GPIO
@@ -217,6 +222,7 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
int gpiod_hog(struct gpio_desc *desc, const char *name,
unsigned long lflags, enum gpiod_flags dflags);
+int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
/*
* Return the GPIO number of the passed descriptor relative to its chip
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index dbbe6559d6bc..011561605983 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -2659,10 +2659,7 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr,
return -EFAULT;
}
- *is_heap_stack = (vma->vm_start <= vma->vm_mm->brk &&
- vma->vm_end >= vma->vm_mm->start_brk) ||
- (vma->vm_start <= vma->vm_mm->start_stack &&
- vma->vm_end >= vma->vm_mm->start_stack);
+ *is_heap_stack = vma_is_initial_heap(vma) || vma_is_initial_stack(vma);
start_limit = max(vma->vm_start >> PAGE_SHIFT,
(unsigned long)ALIGN_DOWN(addr, 2UL << 8));
diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
index 49a1d7f3539c..9f83baac6ed8 100644
--- a/drivers/gpu/drm/arm/display/include/malidp_utils.h
+++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
@@ -35,7 +35,7 @@ static inline void set_range(struct malidp_range *rg, u32 start, u32 end)
rg->end = end;
}
-static inline bool in_range(struct malidp_range *rg, u32 v)
+static inline bool malidp_in_range(struct malidp_range *rg, u32 v)
{
return (v >= rg->start) && (v <= rg->end);
}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
index 3276a3e82c62..4618687a8f4d 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -305,12 +305,12 @@ komeda_layer_check_cfg(struct komeda_layer *layer,
if (komeda_fb_check_src_coords(kfb, src_x, src_y, src_w, src_h))
return -EINVAL;
- if (!in_range(&layer->hsize_in, src_w)) {
+ if (!malidp_in_range(&layer->hsize_in, src_w)) {
DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", src_w);
return -EINVAL;
}
- if (!in_range(&layer->vsize_in, src_h)) {
+ if (!malidp_in_range(&layer->vsize_in, src_h)) {
DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", src_h);
return -EINVAL;
}
@@ -452,14 +452,14 @@ komeda_scaler_check_cfg(struct komeda_scaler *scaler,
hsize_out = dflow->out_w;
vsize_out = dflow->out_h;
- if (!in_range(&scaler->hsize, hsize_in) ||
- !in_range(&scaler->hsize, hsize_out)) {
+ if (!malidp_in_range(&scaler->hsize, hsize_in) ||
+ !malidp_in_range(&scaler->hsize, hsize_out)) {
DRM_DEBUG_ATOMIC("Invalid horizontal sizes");
return -EINVAL;
}
- if (!in_range(&scaler->vsize, vsize_in) ||
- !in_range(&scaler->vsize, vsize_out)) {
+ if (!malidp_in_range(&scaler->vsize, vsize_in) ||
+ !malidp_in_range(&scaler->vsize, vsize_out)) {
DRM_DEBUG_ATOMIC("Invalid vertical sizes");
return -EINVAL;
}
@@ -574,13 +574,13 @@ komeda_splitter_validate(struct komeda_splitter *splitter,
return -EINVAL;
}
- if (!in_range(&splitter->hsize, dflow->in_w)) {
+ if (!malidp_in_range(&splitter->hsize, dflow->in_w)) {
DRM_DEBUG_ATOMIC("split in_w:%d is out of the acceptable range.\n",
dflow->in_w);
return -EINVAL;
}
- if (!in_range(&splitter->vsize, dflow->in_h)) {
+ if (!malidp_in_range(&splitter->vsize, dflow->in_h)) {
DRM_DEBUG_ATOMIC("split in_h: %d exceeds the acceptable range.\n",
dflow->in_h);
return -EINVAL;
@@ -624,13 +624,13 @@ komeda_merger_validate(struct komeda_merger *merger,
return -EINVAL;
}
- if (!in_range(&merger->hsize_merged, output->out_w)) {
+ if (!malidp_in_range(&merger->hsize_merged, output->out_w)) {
DRM_DEBUG_ATOMIC("merged_w: %d is out of the accepted range.\n",
output->out_w);
return -EINVAL;
}
- if (!in_range(&merger->vsize_merged, output->out_h)) {
+ if (!malidp_in_range(&merger->vsize_merged, output->out_h)) {
DRM_DEBUG_ATOMIC("merged_h: %d is out of the accepted range.\n",
output->out_h);
return -EINVAL;
@@ -866,8 +866,8 @@ void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
* input/output range.
*/
if (dflow->en_scaling && scaler)
- dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
- !in_range(&scaler->hsize, dflow->out_w);
+ dflow->en_split = !malidp_in_range(&scaler->hsize, dflow->in_w) ||
+ !malidp_in_range(&scaler->hsize, dflow->out_w);
}
static bool merger_is_available(struct komeda_pipeline *pipe,
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index c49091691ab1..cf777bdb25d2 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -1387,6 +1387,18 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi)
disable_irq(dsi->irq);
}
+static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable)
+{
+ u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
+
+ if (enable)
+ reg |= DSIM_FORCE_STOP_STATE;
+ else
+ reg &= ~DSIM_FORCE_STOP_STATE;
+
+ samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
+}
+
static int samsung_dsim_init(struct samsung_dsim *dsi)
{
const struct samsung_dsim_driver_data *driver_data = dsi->driver_data;
@@ -1446,15 +1458,12 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- u32 reg;
if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) {
samsung_dsim_set_display_mode(dsi);
samsung_dsim_set_display_enable(dsi, true);
} else {
- reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
- reg &= ~DSIM_FORCE_STOP_STATE;
- samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
+ samsung_dsim_set_stop_state(dsi, false);
}
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
@@ -1464,16 +1473,12 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- u32 reg;
if (!(dsi->state & DSIM_STATE_ENABLED))
return;
- if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) {
- reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG);
- reg |= DSIM_FORCE_STOP_STATE;
- samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg);
- }
+ if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type))
+ samsung_dsim_set_stop_state(dsi, true);
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
}
@@ -1776,6 +1781,8 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host,
if (ret)
return ret;
+ samsung_dsim_set_stop_state(dsi, false);
+
ret = mipi_dsi_create_packet(&xfer.packet, msg);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index a9b19e80bff7..6d68b36292d3 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -21,6 +21,7 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <linux/math.h>
#include <linux/string_helpers.h>
#include "i915_reg.h"
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
index ba62eb5d7c51..04e6810954b2 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h
@@ -29,13 +29,6 @@
#include "intel_wakeref.h"
-/*FIXME: Move this to a more appropriate place. */
-#define abs_diff(a, b) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- (void) (&__a == &__b); \
- __a > __b ? (__a - __b) : (__b - __a); })
-
enum tc_port;
struct drm_i915_private;
struct intel_atomic_state;
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index b870c0df081a..ec4d26b3c17c 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -443,7 +443,6 @@ static int i915_pcode_init(struct drm_i915_private *i915)
static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
{
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
- struct pci_dev *root_pdev;
int ret;
if (i915_inject_probe_failure(dev_priv))
@@ -557,15 +556,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
intel_bw_init_hw(dev_priv);
- /*
- * FIXME: Temporary hammer to avoid freezing the machine on our DGFX
- * This should be totally removed when we handle the pci states properly
- * on runtime PM and on s2idle cases.
- */
- root_pdev = pcie_find_root_port(pdev);
- if (root_pdev)
- pci_d3cold_disable(root_pdev);
-
return 0;
err_opregion:
@@ -591,7 +581,6 @@ err_perf:
static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
{
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
- struct pci_dev *root_pdev;
i915_perf_fini(dev_priv);
@@ -599,10 +588,6 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
if (pdev->msi_enabled)
pci_disable_msi(pdev);
-
- root_pdev = pcie_find_root_port(pdev);
- if (root_pdev)
- pci_d3cold_enable(root_pdev);
}
/**
@@ -1519,6 +1504,8 @@ static int intel_runtime_suspend(struct device *kdev)
{
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
struct intel_runtime_pm *rpm = &dev_priv->runtime_pm;
+ struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+ struct pci_dev *root_pdev;
struct intel_gt *gt;
int ret, i;
@@ -1570,6 +1557,15 @@ static int intel_runtime_suspend(struct device *kdev)
drm_err(&dev_priv->drm,
"Unclaimed access detected prior to suspending\n");
+ /*
+ * FIXME: Temporary hammer to avoid freezing the machine on our DGFX
+ * This should be totally removed when we handle the pci states properly
+ * on runtime PM.
+ */
+ root_pdev = pcie_find_root_port(pdev);
+ if (root_pdev)
+ pci_d3cold_disable(root_pdev);
+
rpm->suspended = true;
/*
@@ -1608,6 +1604,8 @@ static int intel_runtime_resume(struct device *kdev)
{
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
struct intel_runtime_pm *rpm = &dev_priv->runtime_pm;
+ struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
+ struct pci_dev *root_pdev;
struct intel_gt *gt;
int ret, i;
@@ -1621,6 +1619,11 @@ static int intel_runtime_resume(struct device *kdev)
intel_opregion_notify_adapter(dev_priv, PCI_D0);
rpm->suspended = false;
+
+ root_pdev = pcie_find_root_port(pdev);
+ if (root_pdev)
+ pci_d3cold_enable(root_pdev);
+
if (intel_uncore_unclaimed_mmio(&dev_priv->uncore))
drm_dbg(&dev_priv->drm,
"Unclaimed access during suspend, bios?\n");
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index cd73ee0cbf23..7923129363b0 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -678,12 +678,6 @@ struct block_header {
u32 data[];
};
-/* this should be a general kernel helper */
-static int in_range(u32 addr, u32 start, u32 size)
-{
- return addr >= start && addr < start + size;
-}
-
static bool fw_block_mem(struct a6xx_gmu_bo *bo, const struct block_header *blk)
{
if (!in_range(blk->addr, bo->iova, bo->size))
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
index 58dfb15a8757..e78de99e9933 100644
--- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c
+++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c
@@ -96,7 +96,7 @@ static int panfrost_read_speedbin(struct device *dev)
* keep going without it; any other error means that we are
* supposed to read the bin value, but we failed doing so.
*/
- if (ret != -ENOENT) {
+ if (ret != -ENOENT && ret != -EOPNOTSUPP) {
DRM_DEV_ERROR(dev, "Cannot read speed-bin (%d).", ret);
return ret;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
index 82094c137855..c43853597776 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
@@ -497,10 +497,9 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp,
if (!(flags & drm_vmw_synccpu_allow_cs)) {
atomic_dec(&vmw_bo->cpu_writers);
}
- ttm_bo_put(&vmw_bo->tbo);
+ vmw_user_bo_unref(vmw_bo);
}
- drm_gem_object_put(&vmw_bo->tbo.base);
return ret;
}
@@ -540,8 +539,7 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data,
return ret;
ret = vmw_user_bo_synccpu_grab(vbo, arg->flags);
- vmw_bo_unreference(&vbo);
- drm_gem_object_put(&vbo->tbo.base);
+ vmw_user_bo_unref(vbo);
if (unlikely(ret != 0)) {
if (ret == -ERESTARTSYS || ret == -EBUSY)
return -EBUSY;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
index 50a836e70994..1d433fceed3d 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
@@ -195,6 +195,14 @@ static inline struct vmw_bo *vmw_bo_reference(struct vmw_bo *buf)
return buf;
}
+static inline void vmw_user_bo_unref(struct vmw_bo *vbo)
+{
+ if (vbo) {
+ ttm_bo_put(&vbo->tbo);
+ drm_gem_object_put(&vbo->tbo.base);
+ }
+}
+
static inline struct vmw_bo *to_vmw_bo(struct drm_gem_object *gobj)
{
return container_of((gobj), struct vmw_bo, tbo.base);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 3810a9984a7f..58bfdf203eca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -1513,4 +1513,16 @@ static inline bool vmw_has_fences(struct vmw_private *vmw)
return (vmw_fifo_caps(vmw) & SVGA_FIFO_CAP_FENCE) != 0;
}
+static inline bool vmw_shadertype_is_valid(enum vmw_sm_type shader_model,
+ u32 shader_type)
+{
+ SVGA3dShaderType max_allowed = SVGA3D_SHADERTYPE_PREDX_MAX;
+
+ if (shader_model >= VMW_SM_5)
+ max_allowed = SVGA3D_SHADERTYPE_MAX;
+ else if (shader_model >= VMW_SM_4)
+ max_allowed = SVGA3D_SHADERTYPE_DX10_MAX;
+ return shader_type >= SVGA3D_SHADERTYPE_MIN && shader_type < max_allowed;
+}
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 6b9aa2b4ef54..98e0723ca6f5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1164,8 +1164,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
}
vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_MOB, VMW_BO_DOMAIN_MOB);
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
- ttm_bo_put(&vmw_bo->tbo);
- drm_gem_object_put(&vmw_bo->tbo.base);
+ vmw_user_bo_unref(vmw_bo);
if (unlikely(ret != 0))
return ret;
@@ -1221,8 +1220,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
vmw_bo_placement_set(vmw_bo, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM,
VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM);
ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo);
- ttm_bo_put(&vmw_bo->tbo);
- drm_gem_object_put(&vmw_bo->tbo.base);
+ vmw_user_bo_unref(vmw_bo);
if (unlikely(ret != 0))
return ret;
@@ -1992,7 +1990,7 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
cmd = container_of(header, typeof(*cmd), header);
- if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) {
+ if (!vmw_shadertype_is_valid(VMW_SM_LEGACY, cmd->body.type)) {
VMW_DEBUG_USER("Illegal shader type %u.\n",
(unsigned int) cmd->body.type);
return -EINVAL;
@@ -2115,8 +2113,6 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
SVGA3dCmdHeader *header)
{
VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetSingleConstantBuffer);
- SVGA3dShaderType max_shader_num = has_sm5_context(dev_priv) ?
- SVGA3D_NUM_SHADERTYPE : SVGA3D_NUM_SHADERTYPE_DX10;
struct vmw_resource *res = NULL;
struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
@@ -2133,6 +2129,14 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
if (unlikely(ret != 0))
return ret;
+ if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type) ||
+ cmd->body.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
+ VMW_DEBUG_USER("Illegal const buffer shader %u slot %u.\n",
+ (unsigned int) cmd->body.type,
+ (unsigned int) cmd->body.slot);
+ return -EINVAL;
+ }
+
binding.bi.ctx = ctx_node->ctx;
binding.bi.res = res;
binding.bi.bt = vmw_ctx_binding_cb;
@@ -2141,14 +2145,6 @@ vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
binding.size = cmd->body.sizeInBytes;
binding.slot = cmd->body.slot;
- if (binding.shader_slot >= max_shader_num ||
- binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
- VMW_DEBUG_USER("Illegal const buffer shader %u slot %u.\n",
- (unsigned int) cmd->body.type,
- (unsigned int) binding.slot);
- return -EINVAL;
- }
-
vmw_binding_add(ctx_node->staged, &binding.bi, binding.shader_slot,
binding.slot);
@@ -2207,15 +2203,13 @@ static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv,
{
VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShaderResources) =
container_of(header, typeof(*cmd), header);
- SVGA3dShaderType max_allowed = has_sm5_context(dev_priv) ?
- SVGA3D_SHADERTYPE_MAX : SVGA3D_SHADERTYPE_DX10_MAX;
u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) /
sizeof(SVGA3dShaderResourceViewId);
if ((u64) cmd->body.startView + (u64) num_sr_view >
(u64) SVGA3D_DX_MAX_SRVIEWS ||
- cmd->body.type >= max_allowed) {
+ !vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
VMW_DEBUG_USER("Invalid shader binding.\n");
return -EINVAL;
}
@@ -2239,8 +2233,6 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
SVGA3dCmdHeader *header)
{
VMW_DECLARE_CMD_VAR(*cmd, SVGA3dCmdDXSetShader);
- SVGA3dShaderType max_allowed = has_sm5_context(dev_priv) ?
- SVGA3D_SHADERTYPE_MAX : SVGA3D_SHADERTYPE_DX10_MAX;
struct vmw_resource *res = NULL;
struct vmw_ctx_validation_info *ctx_node = VMW_GET_CTX_NODE(sw_context);
struct vmw_ctx_bindinfo_shader binding;
@@ -2251,8 +2243,7 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
cmd = container_of(header, typeof(*cmd), header);
- if (cmd->body.type >= max_allowed ||
- cmd->body.type < SVGA3D_SHADERTYPE_MIN) {
+ if (!vmw_shadertype_is_valid(dev_priv->sm_type, cmd->body.type)) {
VMW_DEBUG_USER("Illegal shader type %u.\n",
(unsigned int) cmd->body.type);
return -EINVAL;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index b62207be3363..1489ad73c103 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1665,10 +1665,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
err_out:
/* vmw_user_lookup_handle takes one ref so does new_fb */
- if (bo) {
- vmw_bo_unreference(&bo);
- drm_gem_object_put(&bo->tbo.base);
- }
+ if (bo)
+ vmw_user_bo_unref(bo);
if (surface)
vmw_surface_unreference(&surface);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
index 7e112319a23c..fb85f244c3d0 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
@@ -451,8 +451,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data,
ret = vmw_overlay_update_stream(dev_priv, buf, arg, true);
- vmw_bo_unreference(&buf);
- drm_gem_object_put(&buf->tbo.base);
+ vmw_user_bo_unref(buf);
out_unlock:
mutex_unlock(&overlay->mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
index e7226db8b242..1e81ff2422cf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
@@ -809,8 +809,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv,
shader_type, num_input_sig,
num_output_sig, tfile, shader_handle);
out_bad_arg:
- vmw_bo_unreference(&buffer);
- drm_gem_object_put(&buffer->tbo.base);
+ vmw_user_bo_unref(buffer);
return ret;
}
diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c
index af1612044eef..841316582ea9 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -7,7 +7,10 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/math.h>
+
#include <video/imx-ipu-image-convert.h>
+
#include "ipu-prv.h"
/*
@@ -543,7 +546,7 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
unsigned int in_pos;
unsigned int in_pos_aligned;
unsigned int in_pos_rounded;
- unsigned int abs_diff;
+ unsigned int diff;
/*
* Tiles in the right row / bottom column may not be allowed to
@@ -575,15 +578,11 @@ static void find_best_seam(struct ipu_image_convert_ctx *ctx,
(in_edge - in_pos_rounded) % in_burst)
continue;
- if (in_pos < in_pos_aligned)
- abs_diff = in_pos_aligned - in_pos;
- else
- abs_diff = in_pos - in_pos_aligned;
-
- if (abs_diff < min_diff) {
+ diff = abs_diff(in_pos, in_pos_aligned);
+ if (diff < min_diff) {
in_seam = in_pos_rounded;
out_seam = out_pos;
- min_diff = abs_diff;
+ min_diff = diff;
}
}
diff --git a/drivers/hid/bpf/entrypoints/Makefile b/drivers/hid/bpf/entrypoints/Makefile
index a12edcfa4fe3..43b99b5575cf 100644
--- a/drivers/hid/bpf/entrypoints/Makefile
+++ b/drivers/hid/bpf/entrypoints/Makefile
@@ -58,7 +58,7 @@ entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL)
$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT)
$(call msg,BPF,$@)
- $(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES) \
+ $(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \
-c $(filter %.c,$^) -o $@ && \
$(LLVM_STRIP) -g $@
diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c
index 84ba8b875199..4c1a00f9929e 100644
--- a/drivers/hsi/controllers/omap_ssi_core.c
+++ b/drivers/hsi/controllers/omap_ssi_core.c
@@ -25,6 +25,7 @@
#include <linux/debugfs.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/hsi/hsi.h>
#include <linux/idr.h>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 307477b8a371..ec38c8892158 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -734,6 +734,16 @@ config SENSORS_HIH6130
This driver can also be built as a module. If so, the module
will be called hih6130.
+config SENSORS_HS3001
+ tristate "Renesas HS3001 humidity and temperature sensors"
+ depends on I2C
+ help
+ If you say yes here you get support for the Renesas HS3001,
+ to HS3004 humidity and temperature sensors.
+
+ This driver can also be built as a module. If so, the module
+ will be called hs3001.
+
config SENSORS_IBMAEM
tristate "IBM Active Energy Manager temperature/power sensors and control"
select IPMI_SI
@@ -1951,20 +1961,6 @@ config SENSORS_SFCTEMP
This driver can also be built as a module. If so, the module
will be called sfctemp.
-config SENSORS_SMM665
- tristate "Summit Microelectronics SMM665"
- depends on I2C
- help
- If you say yes here you get support for the hardware monitoring
- features of the Summit Microelectronics SMM665/SMM665B Six-Channel
- Active DC Output Controller / Monitor.
-
- Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
- Support for those chips is untested.
-
- This driver can also be built as a module. If so, the module will
- be called smm665.
-
config SENSORS_ADC128D818
tristate "Texas Instruments ADC128D818"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 3f4b0fda0998..4ac9452b5430 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
+obj-$(CONFIG_SENSORS_HS3001) += hs3001.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
@@ -191,7 +192,6 @@ obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o
obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
-obj-$(CONFIG_SENSORS_SMM665) += smm665.o
obj-$(CONFIG_SENSORS_SMPRO) += smpro-hwmon.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index ffe81e445010..4829f83ff52e 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -16,7 +16,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -253,7 +253,7 @@ static int ad7418_probe(struct i2c_client *client)
mutex_init(&data->lock);
data->client = client;
if (dev->of_node)
- data->type = (enum chips)of_device_get_match_data(dev);
+ data->type = (uintptr_t)of_device_get_match_data(dev);
else
data->type = i2c_match_id(ad7418_id, client)->driver_data;
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 1932613ec095..809e830f52a6 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -18,7 +18,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_data/ads7828.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -139,8 +139,7 @@ static int ads7828_probe(struct i2c_client *client)
}
if (client->dev.of_node)
- chip = (enum ads7828_chips)
- of_device_get_match_data(&client->dev);
+ chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = i2c_match_id(ads7828_device_ids, client)->driver_data;
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index c0ce88324ea6..03acadc3a6cb 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
@@ -1653,7 +1652,7 @@ static int adt7475_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
if (client->dev.of_node)
- chip = (enum chips)of_device_get_match_data(&client->dev);
+ chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c
index fffbf385a57f..316454bd983d 100644
--- a/drivers/hwmon/as370-hwmon.c
+++ b/drivers/hwmon/as370-hwmon.c
@@ -11,7 +11,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#define CTRL 0x0
#define PD BIT(0)
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index d11f674e3dc3..997df4b40509 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -12,8 +12,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index f52a539eb33e..51f9c2db403e 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -340,7 +340,7 @@ static const struct ec_board_info board_info_crosshair_x670e_hero = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
SENSOR_SET_TEMP_WATER,
- .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
+ .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
.family = family_amd_600_series,
};
diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c
index 8d402a627306..b77ebac2e0ce 100644
--- a/drivers/hwmon/bt1-pvt.c
+++ b/drivers/hwmon/bt1-pvt.c
@@ -891,15 +891,8 @@ static struct pvt_hwmon *pvt_create_data(struct platform_device *pdev)
static int pvt_request_regs(struct pvt_hwmon *pvt)
{
struct platform_device *pdev = to_platform_device(pvt->dev);
- struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(pvt->dev, "Couldn't find PVT memresource\n");
- return -EINVAL;
- }
-
- pvt->regs = devm_ioremap_resource(pvt->dev, res);
+ pvt->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pvt->regs))
return PTR_ERR(pvt->regs);
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
index 1b6ff4712138..fad69ef56c75 100644
--- a/drivers/hwmon/g762.c
+++ b/drivers/hwmon/g762.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_data/g762.h>
#define DRVNAME "g762"
diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c
index 2e05bc2f627a..00e057050437 100644
--- a/drivers/hwmon/gxp-fan-ctrl.c
+++ b/drivers/hwmon/gxp-fan-ctrl.c
@@ -6,7 +6,7 @@
#include <linux/hwmon.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */
diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c
index ebe2fb513480..17ae62f88bbf 100644
--- a/drivers/hwmon/hp-wmi-sensors.c
+++ b/drivers/hwmon/hp-wmi-sensors.c
@@ -435,25 +435,11 @@ static union acpi_object *hp_wmi_get_wobj(const char *guid, u8 instance)
/* hp_wmi_wobj_instance_count - find count of WMI object instances */
static u8 hp_wmi_wobj_instance_count(const char *guid)
{
- u8 hi = HP_WMI_MAX_INSTANCES;
- union acpi_object *wobj;
- u8 lo = 0;
- u8 mid;
-
- while (lo < hi) {
- mid = (lo + hi) / 2;
+ int count;
- wobj = hp_wmi_get_wobj(guid, mid);
- if (!wobj) {
- hi = mid;
- continue;
- }
+ count = wmi_instance_count(guid);
- lo = mid + 1;
- kfree(wobj);
- }
-
- return lo;
+ return clamp(count, 0, (int)HP_WMI_MAX_INSTANCES);
}
static int check_wobj(const union acpi_object *wobj,
@@ -1927,7 +1913,7 @@ static bool add_event_handler(struct hp_wmi_sensors *state)
static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
{
struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES];
- struct hp_wmi_platform_events *pevents;
+ struct hp_wmi_platform_events *pevents = NULL;
struct device *dev = &state->wdev->dev;
struct hp_wmi_info *info;
struct device *hwdev;
diff --git a/drivers/hwmon/hs3001.c b/drivers/hwmon/hs3001.c
new file mode 100644
index 000000000000..ac574e46d069
--- /dev/null
+++ b/drivers/hwmon/hs3001.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * This is a non-complete driver implementation for the
+ * HS3001 humidity and temperature sensor and compatibles. It does not include
+ * the configuration possibilities, where it needs to be set to 'programming mode'
+ * during power-up.
+ *
+ *
+ * Copyright (C) 2023 SYS TEC electronic AG
+ * Author: Andre Werner <andre.werner@systec-electronic.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/* Measurement times */
+#define HS3001_WAKEUP_TIME 100 /* us */
+#define HS3001_8BIT_RESOLUTION 550 /* us */
+#define HS3001_10BIT_RESOLUTION 1310 /* us */
+#define HS3001_12BIT_RESOLUTION 4500 /* us */
+#define HS3001_14BIT_RESOLUTION 16900 /* us */
+
+#define HS3001_RESPONSE_LENGTH 4
+
+#define HS3001_FIXPOINT_ARITH 1000U
+
+#define HS3001_MASK_HUMIDITY_0X3FFF GENMASK(13, 0)
+#define HS3001_MASK_STATUS_0XC0 GENMASK(7, 6)
+
+/* Definitions for Status Bits of A/D Data */
+#define HS3001_DATA_VALID 0x00 /* Valid Data */
+#define HS3001_DATA_STALE 0x01 /* Stale Data */
+
+struct hs3001_data {
+ struct i2c_client *client;
+ struct mutex i2c_lock; /* lock for sending i2c commands */
+ u32 wait_time; /* in us */
+ int temperature; /* in milli degree */
+ u32 humidity; /* in milli % */
+};
+
+static int hs3001_extract_temperature(u16 raw)
+{
+ /* fixpoint arithmetic 1 digit */
+ u32 temp = (raw >> 2) * HS3001_FIXPOINT_ARITH * 165;
+
+ temp /= (1 << 14) - 1;
+
+ return (int)temp - 40 * HS3001_FIXPOINT_ARITH;
+}
+
+static u32 hs3001_extract_humidity(u16 raw)
+{
+ u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100;
+
+ return hum /= (1 << 14) - 1;
+}
+
+static int hs3001_data_fetch_command(struct i2c_client *client,
+ struct hs3001_data *data)
+{
+ int ret;
+ u8 buf[HS3001_RESPONSE_LENGTH];
+ u8 hs3001_status;
+
+ ret = i2c_master_recv(client, buf, HS3001_RESPONSE_LENGTH);
+ if (ret != HS3001_RESPONSE_LENGTH) {
+ ret = ret < 0 ? ret : -EIO;
+ dev_dbg(&client->dev,
+ "Error in i2c communication. Error code: %d.\n", ret);
+ return ret;
+ }
+
+ hs3001_status = FIELD_GET(HS3001_MASK_STATUS_0XC0, buf[0]);
+ if (hs3001_status == HS3001_DATA_STALE) {
+ dev_dbg(&client->dev, "Sensor busy.\n");
+ return -EBUSY;
+ }
+ if (hs3001_status != HS3001_DATA_VALID) {
+ dev_dbg(&client->dev, "Data invalid.\n");
+ return -EIO;
+ }
+
+ data->humidity =
+ hs3001_extract_humidity(be16_to_cpup((__be16 *)&buf[0]));
+ data->temperature =
+ hs3001_extract_temperature(be16_to_cpup((__be16 *)&buf[2]));
+
+ return 0;
+}
+
+static umode_t hs3001_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ /* Both, humidity and temperature can only be read. */
+ return 0444;
+}
+
+static int hs3001_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct hs3001_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int ret;
+
+ mutex_lock(&data->i2c_lock);
+ ret = i2c_master_send(client, NULL, 0);
+ if (ret < 0) {
+ mutex_unlock(&data->i2c_lock);
+ return ret;
+ }
+
+ /*
+ * Sensor needs some time to process measurement depending on
+ * resolution (ref. datasheet)
+ */
+ fsleep(data->wait_time);
+
+ ret = hs3001_data_fetch_command(client, data);
+ mutex_unlock(&data->i2c_lock);
+
+ if (ret < 0)
+ return ret;
+
+ switch (type) {
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = data->temperature;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case hwmon_humidity:
+ switch (attr) {
+ case hwmon_humidity_input:
+ *val = data->humidity;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct hwmon_channel_info *hs3001_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops hs3001_hwmon_ops = {
+ .is_visible = hs3001_is_visible,
+ .read = hs3001_read,
+};
+
+static const struct hwmon_chip_info hs3001_chip_info = {
+ .ops = &hs3001_hwmon_ops,
+ .info = hs3001_info,
+};
+
+/* device ID table */
+static const struct i2c_device_id hs3001_ids[] = {
+ { "hs3001", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, hs3001_ids);
+
+static const struct of_device_id hs3001_of_match[] = {
+ {.compatible = "renesas,hs3001"},
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, hs3001_of_match);
+
+static int hs3001_probe(struct i2c_client *client)
+{
+ struct hs3001_data *data;
+ struct device *hwmon_dev;
+ struct device *dev = &client->dev;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->client = client;
+
+ /*
+ * Measurement time = wake-up time + measurement time temperature
+ * + measurement time humidity. This is currently static, because
+ * enabling programming mode is not supported, yet.
+ */
+ data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION +
+ HS3001_14BIT_RESOLUTION);
+
+ mutex_init(&data->i2c_lock);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev,
+ client->name,
+ data,
+ &hs3001_chip_info,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return dev_err_probe(dev, PTR_ERR(hwmon_dev),
+ "Unable to register hwmon device.\n");
+
+ return 0;
+}
+
+static struct i2c_driver hs3001_i2c_driver = {
+ .driver = {
+ .name = "hs3001",
+ .of_match_table = hs3001_of_match,
+ },
+ .probe = hs3001_probe,
+ .id_table = hs3001_ids,
+};
+
+module_i2c_driver(hs3001_i2c_driver);
+
+MODULE_AUTHOR("Andre Werner <andre.werner@systec-electronic.com>");
+MODULE_DESCRIPTION("HS3001 humidity and temperature sensor base driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index cfd7efef5cdf..d8415d1f21fc 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -31,7 +31,6 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
@@ -625,7 +624,7 @@ static int ina2xx_probe(struct i2c_client *client)
enum ina2xx_ids chip;
if (client->dev.of_node)
- chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev);
+ chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = i2c_match_id(ina2xx_id, client)->driver_data;
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 5deff5e5f693..fbe86cec6055 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -221,6 +221,10 @@ static bool fix_pwm_polarity;
* Super-I/O configuration space.
*/
#define IT87_REG_VID 0x0a
+
+/* Interface Selection register on other chips */
+#define IT87_REG_IFSEL 0x0a
+
/*
* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
* for fan divisors. Later IT8712F revisions must use 16-bit tachometer
@@ -1159,28 +1163,66 @@ static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
+static int get_temp_type(struct it87_data *data, int index)
+{
+ /*
+ * 2 is deprecated;
+ * 3 = thermal diode;
+ * 4 = thermistor;
+ * 5 = AMDTSI;
+ * 6 = Intel PECI;
+ * 0 = disabled
+ */
+ u8 reg, extra;
+ int ttype, type = 0;
+
+ /* Detect PECI vs. AMDTSI */
+ ttype = 6;
+ if ((has_temp_peci(data, index)) || data->type == it8721 ||
+ data->type == it8720) {
+ extra = it87_read_value(data, IT87_REG_IFSEL);
+ if ((extra & 0x70) == 0x40)
+ ttype = 5;
+ }
+
+ reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+
+ /* Per chip special detection */
+ switch (data->type) {
+ case it8622:
+ if (!(reg & 0xc0) && index == 3)
+ type = ttype;
+ break;
+ default:
+ break;
+ }
+
+ if (type || index >= 3)
+ return type;
+
+ extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+
+ if ((has_temp_peci(data, index) && (reg >> 6 == index + 1)) ||
+ (has_temp_old_peci(data, index) && (extra & 0x80)))
+ type = ttype; /* Intel PECI or AMDTSI */
+ else if (reg & BIT(index))
+ type = 3; /* thermal diode */
+ else if (reg & BIT(index + 3))
+ type = 4; /* thermistor */
+
+ return type;
+}
+
static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
- u8 reg, extra;
if (IS_ERR(data))
return PTR_ERR(data);
- reg = data->sensor; /* In case value is updated while used */
- extra = data->extra;
-
- if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) ||
- (has_temp_old_peci(data, nr) && (extra & 0x80)))
- return sprintf(buf, "6\n"); /* Intel PECI */
- if (reg & (1 << nr))
- return sprintf(buf, "3\n"); /* thermal diode */
- if (reg & (8 << nr))
- return sprintf(buf, "4\n"); /* thermistor */
- return sprintf(buf, "0\n"); /* disabled */
+ return sprintf(buf, "%d\n", get_temp_type(data, sensor_attr->index));
}
static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
@@ -2313,6 +2355,12 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
if (!(data->has_temp & BIT(i)))
return 0;
+ if (a == 3) {
+ if (get_temp_type(data, i) == 0)
+ return 0;
+ return attr->mode;
+ }
+
if (a == 5 && !has_temp_offset(data))
return 0;
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index a267b11731a8..bae0becfa24b 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -65,7 +65,7 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
#define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64
#define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
-/* Common for Zen CPU families (Family 17h and 18h and 19h) */
+/* Common for Zen CPU families (Family 17h and 18h and 19h and 1Ah) */
#define ZEN_REPORTED_TEMP_CTRL_BASE 0x00059800
#define ZEN_CCD_TEMP(offset, x) (ZEN_REPORTED_TEMP_CTRL_BASE + \
@@ -475,6 +475,10 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
k10temp_get_ccd_support(pdev, data, 12);
break;
}
+ } else if (boot_cpu_data.x86 == 0x1a) {
+ data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK;
+ data->read_tempreg = read_tempreg_nb_zen;
+ data->is_zen = true;
} else {
data->read_htcreg = read_htcreg_pci;
data->read_tempreg = read_tempreg_pci;
@@ -521,6 +525,8 @@ static const struct pci_device_id k10temp_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M60H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M70H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3) },
{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
{}
};
diff --git a/drivers/hwmon/lan966x-hwmon.c b/drivers/hwmon/lan966x-hwmon.c
index f8658359a098..7247c03e4f44 100644
--- a/drivers/hwmon/lan966x-hwmon.c
+++ b/drivers/hwmon/lan966x-hwmon.c
@@ -334,24 +334,6 @@ static struct regmap *lan966x_init_regmap(struct platform_device *pdev,
return devm_regmap_init_mmio(&pdev->dev, base, &regmap_config);
}
-static void lan966x_clk_disable(void *data)
-{
- struct lan966x_hwmon *hwmon = data;
-
- clk_disable_unprepare(hwmon->clk);
-}
-
-static int lan966x_clk_enable(struct device *dev, struct lan966x_hwmon *hwmon)
-{
- int ret;
-
- ret = clk_prepare_enable(hwmon->clk);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, lan966x_clk_disable, hwmon);
-}
-
static int lan966x_hwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -363,15 +345,11 @@ static int lan966x_hwmon_probe(struct platform_device *pdev)
if (!hwmon)
return -ENOMEM;
- hwmon->clk = devm_clk_get(dev, NULL);
+ hwmon->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(hwmon->clk))
return dev_err_probe(dev, PTR_ERR(hwmon->clk),
"failed to get clock\n");
- ret = lan966x_clk_enable(dev, hwmon);
- if (ret)
- return dev_err_probe(dev, ret, "failed to enable clock\n");
-
hwmon->clk_rate = clk_get_rate(hwmon->clk);
hwmon->regmap_pvt = lan966x_init_regmap(pdev, "pvt");
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 6972454eb4e0..0878a044dd8e 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -33,7 +33,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@@ -1105,7 +1105,7 @@ static int lm63_probe(struct i2c_client *client)
/* Set the device type */
if (client->dev.of_node)
- data->kind = (enum chips)of_device_get_match_data(&client->dev);
+ data->kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->kind = i2c_match_id(lm63_id, client)->driver_data;
if (data->kind == lm64)
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 72e634d1b857..5b2ea05c951e 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -13,7 +13,6 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/util_macros.h>
@@ -579,7 +578,7 @@ static int lm75_probe(struct i2c_client *client)
enum lm75_type kind;
if (client->dev.of_node)
- kind = (enum lm75_type)of_device_get_match_data(&client->dev);
+ kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
kind = i2c_match_id(lm75_ids, client)->driver_data;
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 8540178f5b74..68c210002357 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -12,7 +12,7 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -1559,7 +1559,7 @@ static int lm85_probe(struct i2c_client *client)
data->client = client;
if (client->dev.of_node)
- data->type = (enum chips)of_device_get_match_data(&client->dev);
+ data->type = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->type = i2c_match_id(lm85_id, client)->driver_data;
mutex_init(&data->update_lock);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 90101c236f35..e0d7454a301c 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -106,7 +106,7 @@
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -2765,7 +2765,7 @@ static int lm90_probe(struct i2c_client *client)
/* Set the device type */
if (client->dev.of_node)
- data->kind = (enum chips)of_device_get_match_data(&client->dev);
+ data->kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->kind = i2c_match_id(lm90_id, client)->driver_data;
diff --git a/drivers/hwmon/lochnagar-hwmon.c b/drivers/hwmon/lochnagar-hwmon.c
index 6350904a8a8b..5202dddfd61e 100644
--- a/drivers/hwmon/lochnagar-hwmon.c
+++ b/drivers/hwmon/lochnagar-hwmon.c
@@ -16,7 +16,6 @@
#include <linux/mfd/lochnagar2_regs.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/hwmon/ltq-cputemp.c b/drivers/hwmon/ltq-cputemp.c
index 08e09a82acab..f7e4a4ca5239 100644
--- a/drivers/hwmon/ltq-cputemp.c
+++ b/drivers/hwmon/ltq-cputemp.c
@@ -9,8 +9,9 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/init.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <lantiq_soc.h>
diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c
index b1300ca9db1f..7d237db6e57c 100644
--- a/drivers/hwmon/max31730.c
+++ b/drivers/hwmon/max31730.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/hwmon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/slab.h>
diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c
index 7f709fd1af89..af7e62685898 100644
--- a/drivers/hwmon/max6621.c
+++ b/drivers/hwmon/max6621.c
@@ -12,7 +12,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#define MAX6621_DRV_NAME "max6621"
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index caf527154fca..aa7f21ab2395 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -618,11 +618,17 @@ MODULE_DEVICE_TABLE(i2c, max6639_id);
static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
+static const struct of_device_id max6639_of_match[] = {
+ { .compatible = "maxim,max6639", },
+ { },
+};
+
static struct i2c_driver max6639_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max6639",
.pm = pm_sleep_ptr(&max6639_pm_ops),
+ .of_match_table = max6639_of_match,
},
.probe = max6639_probe,
.id_table = max6639_id,
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
index 3a67778f111c..7d10dd434f2e 100644
--- a/drivers/hwmon/max6697.c
+++ b/drivers/hwmon/max6697.c
@@ -15,7 +15,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/max6697.h>
@@ -703,7 +702,7 @@ static int max6697_probe(struct i2c_client *client)
return -ENOMEM;
if (client->dev.of_node)
- data->type = (enum chips)of_device_get_match_data(&client->dev);
+ data->type = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->type = i2c_match_id(max6697_id, client)->driver_data;
data->chip = &max6697_chip_data[data->type];
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index 127e15ff3e76..9814eaf24564 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -20,7 +20,6 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
/* Vdd / reference voltage in millivolt */
#define MCP3021_VDD_REF_MAX 5500
diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c
index c2a96468c9b4..a5f89aab3fb4 100644
--- a/drivers/hwmon/mlxreg-fan.c
+++ b/drivers/hwmon/mlxreg-fan.c
@@ -12,7 +12,7 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
-#define MLXREG_FAN_MAX_TACHO 14
+#define MLXREG_FAN_MAX_TACHO 24
#define MLXREG_FAN_MAX_PWM 4
#define MLXREG_FAN_PWM_NOT_CONNECTED 0xff
#define MLXREG_FAN_MAX_STATE 10
@@ -300,6 +300,16 @@ static const struct hwmon_channel_info * const mlxreg_fan_hwmon_info[] = {
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT,
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index 08ce4984151d..02a71244fc3b 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -33,7 +33,8 @@
* (0xd451)
* nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3
* (0xd429)
- * nct6799d 14 7 7 2+6 0xd802 0xc1 0x5ca3
+ * nct6796d-s 18 7 7 6+2 0xd801 0xc1 0x5ca3
+ * nct6799d-r 18 7 7 6+2 0xd802 0xc1 0x5ca3
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
@@ -79,14 +80,17 @@ static const char * const nct6775_device_names[] = {
/* Common and NCT6775 specific data */
-/* Voltage min/max registers for nr=7..14 are in bank 5 */
+/*
+ * Voltage min/max registers for nr=7..14 are in bank 5
+ * min/max: 15-17 for NCT6799 only
+ */
static const u16 NCT6775_REG_IN_MAX[] = {
0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
- 0x55c, 0x55e, 0x560, 0x562 };
+ 0x55c, 0x55e, 0x560, 0x562, 0x564, 0x570, 0x572 };
static const u16 NCT6775_REG_IN_MIN[] = {
0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
- 0x55d, 0x55f, 0x561, 0x563 };
+ 0x55d, 0x55f, 0x561, 0x563, 0x565, 0x571, 0x573 };
static const u16 NCT6775_REG_IN[] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
};
@@ -97,31 +101,23 @@ static const u16 NCT6775_REG_IN[] = {
static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
-/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
-
-static const s8 NCT6775_ALARM_BITS[] = {
- 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
- 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
- -1, /* unused */
- 6, 7, 11, -1, -1, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
- 12, -1 }; /* intrusion0, intrusion1 */
+static const s8 NCT6775_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, 17, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, -1, /* intr0-intr1 */
+};
static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
-/*
- * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
- * 30..31 intrusion
- */
-static const s8 NCT6775_BEEP_BITS[] = {
- 0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
- 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
- 21, /* global beep enable */
- 6, 7, 11, 28, -1, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
- 12, -1 }; /* intrusion0, intrusion1 */
+static const s8 NCT6775_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 8, 9, 10, 16, 17, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, 28, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, -1, 21 /* intr0-intr1, beep_en */
+};
/* DC or PWM output fan configuration */
static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
@@ -255,25 +251,24 @@ static const u16 NCT6775_REG_TSI_TEMP[] = { 0x669 };
#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
-static const s8 NCT6776_ALARM_BITS[] = {
- 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
- 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
- -1, /* unused */
- 6, 7, 11, 10, 23, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
- 12, 9 }; /* intrusion0, intrusion1 */
-
-static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
-
-static const s8 NCT6776_BEEP_BITS[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
- 8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
- 24, /* global beep enable */
- 25, 26, 27, 28, 29, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
- 30, 31 }; /* intrusion0, intrusion1 */
+static const s8 NCT6776_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, 17, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, 9, /* intr0-intr1 */
+};
+
+/* 0xbf: nct6799 only */
+static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
+
+static const s8 NCT6776_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 30, 31, 24 /* intr0-intr1, beep_en */
+};
static const u16 NCT6776_REG_TOLERANCE_H[] = {
0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
@@ -337,30 +332,35 @@ static const u16 NCT6776_REG_TSI_TEMP[] = {
/* NCT6779 specific data */
+/*
+ * 15-17 for NCT6799 only, register labels are:
+ * CPUVC, VIN1, AVSB, 3VCC, VIN0, VIN8, VIN4, 3VSB
+ * VBAT, VTT, VIN5, VIN6, VIN2, VIN3, VIN7, VIN9
+ * VHIF, VIN10
+ */
static const u16 NCT6779_REG_IN[] = {
0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
- 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
+ 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e, 0x48f,
+ 0x470, 0x471};
static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568 };
-static const s8 NCT6779_ALARM_BITS[] = {
- 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
- 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
- -1, /* unused */
- 6, 7, 11, 10, 23, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
- 12, 9 }; /* intrusion0, intrusion1 */
-
-static const s8 NCT6779_BEEP_BITS[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
- 8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
- 24, /* global beep enable */
- 25, 26, 27, 28, 29, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, -1, -1, -1, -1, /* temp1..temp6 */
- 30, 31 }; /* intrusion0, intrusion1 */
+static const s8 NCT6779_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, 17, 24, 25, 26, /* in0-in11 */
+ 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, 9, /* intr0-intr1 */
+};
+
+static const s8 NCT6779_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* in0-in11 */
+ 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 30, 31, 24 /* intr0-intr1, beep_en */
+};
static const u16 NCT6779_REG_FAN[] = {
0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
@@ -448,14 +448,13 @@ static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568, 0x45D };
-static const s8 NCT6791_ALARM_BITS[] = {
- 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
- 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
- -1, /* unused */
- 6, 7, 11, 10, 23, 33, /* fan1..fan6 */
- -1, -1, /* unused */
- 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
- 12, 9 }; /* intrusion0, intrusion1 */
+static const s8 NCT6791_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, 17, 24, 25, 26, /* in0-in11 */
+ 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, 10, 23, 33, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, 9, /* intr0-intr1 */
+};
/* NCT6792/NCT6793 specific data */
@@ -618,6 +617,28 @@ static const char *const nct6796_temp_label[] = {
static const u16 NCT6796_REG_TSI_TEMP[] = { 0x409, 0x40b };
+static const u16 NCT6798_REG_TEMP[] = {
+ 0x27, 0x150, 0x670, 0x672, 0x674, 0x676, 0x678, 0x67a};
+
+static const u16 NCT6798_REG_TEMP_SOURCE[] = {
+ 0x621, 0x622, 0xc26, 0xc27, 0xc28, 0xc29, 0xc2a, 0xc2b };
+
+static const u16 NCT6798_REG_TEMP_MON[] = {
+ 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x4a0 };
+static const u16 NCT6798_REG_TEMP_OVER[] = {
+ 0x39, 0x155, 0xc1a, 0xc1b, 0xc1c, 0xc1d, 0xc1e, 0xc1f };
+static const u16 NCT6798_REG_TEMP_HYST[] = {
+ 0x3a, 0x153, 0xc20, 0xc21, 0xc22, 0xc23, 0xc24, 0xc25 };
+
+static const u16 NCT6798_REG_TEMP_CRIT[32] = {
+ 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35, 0 };
+
+static const u16 NCT6798_REG_TEMP_ALTERNATE[32] = {
+ 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0x496, 0,
+ 0, 0, 0, 0, 0x4a2, 0, 0, 0,
+ 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
+ 0x408, 0x419, 0x41a, 0x4f4, 0x4f5 };
+
static const char *const nct6798_temp_label[] = {
"",
"SYSTIN",
@@ -656,6 +677,26 @@ static const char *const nct6798_temp_label[] = {
#define NCT6798_TEMP_MASK 0xbfff0ffe
#define NCT6798_VIRT_TEMP_MASK 0x80000c00
+static const u16 NCT6799_REG_ALARM[NUM_REG_ALARM] = {
+ 0x459, 0x45A, 0x45B, 0x568, 0x45D, 0xc01 };
+
+static const s8 NCT6799_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 8, -1, 20, 16, 17, 24, 25, 26, /* in0-in11 */
+ 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 6, 7, 11, 10, 23, 33, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 4, 5, 40, 41, 42, 43, 44, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 12, 9, /* intr0-intr1 */
+};
+
+static const s8 NCT6799_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* in0-in11 */
+ 12, 13, 14, 15, 34, 35, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, 19, 20, 21, 22, 23, -1, -1, -1, -1, /* temp1-temp12 */
+ 30, 31, 24 /* intr0-intr1, beep_en */
+};
+
+/* PECI Calibration only for NCT6799D, not NCT6796D-S */
static const char *const nct6799_temp_label[] = {
"",
"SYSTIN",
@@ -685,8 +726,8 @@ static const char *const nct6799_temp_label[] = {
"Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
- "PECI Agent 0 Calibration", /* undocumented */
- "PECI Agent 1 Calibration", /* undocumented */
+ "PECI/TSI Agent 0 Calibration",
+ "PECI/TSI Agent 1 Calibration",
"",
"Virtual_TEMP"
};
@@ -763,27 +804,23 @@ static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
-static const s8 NCT6106_ALARM_BITS[] = {
- 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
- 9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
- -1, /* unused */
- 32, 33, 34, -1, -1, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
- 48, -1 /* intrusion0, intrusion1 */
+static const s8 NCT6106_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, 9, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 48, -1, /* intr0-intr1 */
};
static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
-static const s8 NCT6106_BEEP_BITS[] = {
- 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
- 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
- 32, /* global beep enable */
- 24, 25, 26, 27, 28, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, 18, 19, 20, 21, /* temp1..temp6 */
- 34, -1 /* intrusion0, intrusion1 */
+static const s8 NCT6106_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 34, -1, 32 /* intr0-intr1, beep_en */
};
static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
@@ -843,24 +880,20 @@ static const u16 NCT6116_REG_AUTO_TEMP[] = {
static const u16 NCT6116_REG_AUTO_PWM[] = {
0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
-static const s8 NCT6116_ALARM_BITS[] = {
- 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
- 9, -1, -1, -1, -1, -1, -1, /* in8..in9 */
- -1, /* unused */
- 32, 33, 34, 35, 36, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
- 48, -1 /* intrusion0, intrusion1 */
+static const s8 NCT6116_ALARM_BITS[NUM_ALARM_BITS] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, 9, -1, -1, -1, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 48, -1, /* intr0-intr1 */
};
-static const s8 NCT6116_BEEP_BITS[] = {
- 0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
- 9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
- 32, /* global beep enable */
- 24, 25, 26, 27, 28, /* fan1..fan5 */
- -1, -1, -1, /* unused */
- 16, 17, 18, -1, -1, -1, /* temp1..temp6 */
- 34, -1 /* intrusion0, intrusion1 */
+static const s8 NCT6116_BEEP_BITS[NUM_BEEP_BITS] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, /* in0-in11 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
+ 24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
+ 16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
+ 34, -1, 32 /* intr0-intr1, beep_en */
};
static const u16 NCT6116_REG_TSI_TEMP[] = { 0x59, 0x5b };
@@ -958,12 +991,12 @@ static const u16 scale_in[15] = {
/*
* NCT6798 scaling:
* CPUVC, IN1, AVSB, 3VCC, IN0, IN8, IN4, 3VSB, VBAT, VTT, IN5, IN6, IN2,
- * IN3, IN7
- * Additional scales to be added later: IN9 (800), VHIF (1600)
+ * IN3, IN7, IN9, VHIF, IN10
+ * 15-17 for NCT6799 only
*/
-static const u16 scale_in_6798[15] = {
+static const u16 scale_in_6798[NUM_IN] = {
800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 1600, 1600, 1600, 800,
- 800, 800
+ 800, 800, 800, 1600, 800
};
static inline long in_from_reg(u8 reg, u8 nr, const u16 *scales)
@@ -3862,13 +3895,9 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
case nct6795:
case nct6796:
case nct6797:
- case nct6798:
- case nct6799:
data->in_num = 15;
data->pwm_num = (data->kind == nct6796 ||
- data->kind == nct6797 ||
- data->kind == nct6798 ||
- data->kind == nct6799) ? 7 : 6;
+ data->kind == nct6797) ? 7 : 6;
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 6;
@@ -3912,16 +3941,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
data->temp_mask = NCT6796_TEMP_MASK;
data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
break;
- case nct6798:
- data->temp_label = nct6798_temp_label;
- data->temp_mask = NCT6798_TEMP_MASK;
- data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
- break;
- case nct6799:
- data->temp_label = nct6799_temp_label;
- data->temp_mask = NCT6799_TEMP_MASK;
- data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
- break;
}
data->REG_CONFIG = NCT6775_REG_CONFIG;
@@ -3980,8 +3999,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
case nct6795:
case nct6796:
case nct6797:
- case nct6798:
- case nct6799:
data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
break;
@@ -3990,9 +4007,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
break;
}
- if (data->kind == nct6798 || data->kind == nct6799)
- data->scale_in = scale_in_6798;
-
reg_temp = NCT6779_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
if (data->kind == nct6791) {
@@ -4009,6 +4023,95 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_crit = NCT6779_REG_TEMP_CRIT;
break;
+ case nct6798:
+ case nct6799:
+ data->in_num = data->kind == nct6799 ? 18 : 15;
+ data->scale_in = scale_in_6798;
+ data->pwm_num = 7;
+ data->auto_pwm_num = 4;
+ data->has_fan_div = false;
+ data->temp_fixed_num = 6;
+ data->num_temp_alarms = 7;
+ data->num_temp_beeps = 8;
+
+ data->ALARM_BITS = NCT6799_ALARM_BITS;
+ data->BEEP_BITS = NCT6799_BEEP_BITS;
+
+ data->fan_from_reg = fan_from_reg_rpm;
+ data->fan_from_reg_min = fan_from_reg13;
+ data->target_temp_mask = 0xff;
+ data->tolerance_mask = 0x07;
+ data->speed_tolerance_limit = 63;
+
+ switch (data->kind) {
+ default:
+ case nct6798:
+ data->temp_label = nct6798_temp_label;
+ data->temp_mask = NCT6798_TEMP_MASK;
+ data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
+ break;
+ case nct6799:
+ data->temp_label = nct6799_temp_label;
+ data->temp_mask = NCT6799_TEMP_MASK;
+ data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
+ break;
+ }
+
+ data->REG_CONFIG = NCT6775_REG_CONFIG;
+ data->REG_VBAT = NCT6775_REG_VBAT;
+ data->REG_DIODE = NCT6775_REG_DIODE;
+ data->DIODE_MASK = NCT6775_DIODE_MASK;
+ data->REG_VIN = NCT6779_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6779_REG_FAN;
+ data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+ data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+ data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
+ data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+ data->REG_PWM[0] = NCT6775_REG_PWM;
+ data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
+ data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+ data->CRITICAL_PWM_ENABLE_MASK = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+ data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+ data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6798_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6799_REG_ALARM;
+ data->REG_BEEP = NCT6792_REG_BEEP;
+ data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
+ num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
+
+ reg_temp = NCT6798_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6798_REG_TEMP);
+ reg_temp_mon = NCT6798_REG_TEMP_MON;
+ num_reg_temp_mon = ARRAY_SIZE(NCT6798_REG_TEMP_MON);
+ reg_temp_over = NCT6798_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6798_REG_TEMP_HYST;
+ reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6798_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6798_REG_TEMP_CRIT;
+
+ break;
default:
return -ENODEV;
}
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
index a409d7a0b813..81bf03dad6bb 100644
--- a/drivers/hwmon/nct6775-platform.c
+++ b/drivers/hwmon/nct6775-platform.c
@@ -35,7 +35,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6796D",
"NCT6797D",
"NCT6798D",
- "NCT6799D",
+ "NCT6796D-S/NCT6799D-R",
};
static unsigned short force_id;
diff --git a/drivers/hwmon/nct6775.h b/drivers/hwmon/nct6775.h
index a84c6ce7275d..296eff99d003 100644
--- a/drivers/hwmon/nct6775.h
+++ b/drivers/hwmon/nct6775.h
@@ -8,7 +8,7 @@ enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 };
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
-#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP 12 /* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
#define NUM_TSI_TEMP 8 /* Max number of TSI temp register pairs */
@@ -16,6 +16,7 @@ enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
#define NUM_REG_BEEP 5 /* Max number of beep registers */
#define NUM_FAN 7
+#define NUM_IN 18
struct nct6775_data {
int addr; /* IO base of hw monitor block */
@@ -97,7 +98,7 @@ struct nct6775_data {
/* Register values */
u8 bank; /* current register bank */
u8 in_num; /* number of in inputs we have */
- u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
+ u8 in[NUM_IN][3]; /* [0]=in, [1]=in_max, [2]=in_min */
const u16 *scale_in; /* internal scaling factors */
unsigned int rpm[NUM_FAN];
u16 fan_min[NUM_FAN];
@@ -166,7 +167,7 @@ struct nct6775_data {
u16 have_temp;
u16 have_temp_fixed;
u16 have_tsi_temp;
- u16 have_in;
+ u32 have_in;
/* Remember extra register values over suspend/resume */
u8 vbat;
@@ -239,10 +240,25 @@ nct6775_add_attr_group(struct nct6775_data *data, const struct attribute_group *
#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
-#define FAN_ALARM_BASE 16
-#define TEMP_ALARM_BASE 24
-#define INTRUSION_ALARM_BASE 30
-#define BEEP_ENABLE_BASE 15
+/*
+ * ALARM_BITS and BEEP_BITS store bit-index for the mask of the registers
+ * loaded into data->alarm and data->beep.
+ *
+ * Every input register (IN/TEMP/FAN) must have a corresponding
+ * ALARM/BEEP bit at the same index BITS[BASE + index]
+ * Set value to -1 to disable the visibility of that '*_alarm' attribute and
+ * to pad the bits until the next BASE
+ *
+ * Beep has an additional GLOBAL_BEEP_ENABLE bit
+ */
+#define VIN_ALARM_BASE 0
+#define FAN_ALARM_BASE 24
+#define TEMP_ALARM_BASE 36
+#define INTRUSION_ALARM_BASE 48
+#define BEEP_ENABLE_BASE 50
+
+#define NUM_ALARM_BITS (INTRUSION_ALARM_BASE + 4)
+#define NUM_BEEP_BITS (BEEP_ENABLE_BASE + 1)
/*
* Not currently used:
diff --git a/drivers/hwmon/nsa320-hwmon.c b/drivers/hwmon/nsa320-hwmon.c
index ebe6b031e56f..18076ba7fc14 100644
--- a/drivers/hwmon/nsa320-hwmon.c
+++ b/drivers/hwmon/nsa320-hwmon.c
@@ -20,8 +20,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
/* Tests for error return values rely upon this value being < 0x80 */
@@ -193,7 +191,7 @@ static struct platform_driver nsa320_hwmon_driver = {
.probe = nsa320_hwmon_probe,
.driver = {
.name = "nsa320-hwmon",
- .of_match_table = of_match_ptr(of_nsa320_hwmon_match),
+ .of_match_table = of_nsa320_hwmon_match,
},
};
diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c
index 1e1cc67bcdea..ea9602063eab 100644
--- a/drivers/hwmon/oxp-sensors.c
+++ b/drivers/hwmon/oxp-sensors.c
@@ -434,23 +434,9 @@ static const struct hwmon_chip_info oxp_ec_chip_info = {
/* Initialization logic */
static int oxp_platform_probe(struct platform_device *pdev)
{
- const struct dmi_system_id *dmi_entry;
struct device *dev = &pdev->dev;
struct device *hwdev;
- /*
- * Have to check for AMD processor here because DMI strings are the
- * same between Intel and AMD boards, the only way to tell them apart
- * is the CPU.
- * Intel boards seem to have different EC registers and values to
- * read/write.
- */
- dmi_entry = dmi_first_match(dmi_table);
- if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
- return -ENODEV;
-
- board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
-
hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
&oxp_ec_chip_info, NULL);
@@ -469,6 +455,21 @@ static struct platform_device *oxp_platform_device;
static int __init oxp_platform_init(void)
{
+ const struct dmi_system_id *dmi_entry;
+
+ /*
+ * Have to check for AMD processor here because DMI strings are the
+ * same between Intel and AMD boards, the only way to tell them apart
+ * is the CPU.
+ * Intel boards seem to have different EC registers and values to
+ * read/write.
+ */
+ dmi_entry = dmi_first_match(dmi_table);
+ if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ return -ENODEV;
+
+ board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
+
oxp_platform_device =
platform_create_bundle(&oxp_platform_driver,
oxp_platform_probe, NULL, 0, NULL, 0);
diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c
index ed968401f93c..ce89da3937a0 100644
--- a/drivers/hwmon/peci/dimmtemp.c
+++ b/drivers/hwmon/peci/dimmtemp.c
@@ -219,19 +219,21 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
{
int chan_rank_max = priv->gen_info->chan_rank_max;
int dimm_idx_max = priv->gen_info->dimm_idx_max;
- u32 chan_rank_empty = 0;
- u32 dimm_mask = 0;
- int chan_rank, dimm_idx, ret;
+ DECLARE_BITMAP(dimm_mask, DIMM_NUMS_MAX);
+ DECLARE_BITMAP(chan_rank_empty, CHAN_RANK_MAX);
+
+ int chan_rank, dimm_idx, ret, i;
u32 pcs;
- BUILD_BUG_ON(BITS_PER_TYPE(chan_rank_empty) < CHAN_RANK_MAX);
- BUILD_BUG_ON(BITS_PER_TYPE(dimm_mask) < DIMM_NUMS_MAX);
if (chan_rank_max * dimm_idx_max > DIMM_NUMS_MAX) {
WARN_ONCE(1, "Unsupported number of DIMMs - chan_rank_max: %d, dimm_idx_max: %d",
chan_rank_max, dimm_idx_max);
return -EINVAL;
}
+ bitmap_zero(dimm_mask, DIMM_NUMS_MAX);
+ bitmap_zero(chan_rank_empty, CHAN_RANK_MAX);
+
for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &pcs);
if (ret) {
@@ -242,7 +244,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* detection to be performed at a later point in time.
*/
if (ret == -EINVAL) {
- chan_rank_empty |= BIT(chan_rank);
+ bitmap_set(chan_rank_empty, chan_rank, 1);
continue;
}
@@ -251,7 +253,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
if (__dimm_temp(pcs, dimm_idx))
- dimm_mask |= BIT(chan_rank * dimm_idx_max + dimm_idx);
+ bitmap_set(dimm_mask, chan_rank * dimm_idx_max + dimm_idx, 1);
}
/*
@@ -260,7 +262,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* host platform boot. Retrying a couple of times lets us make sure
* that the state is persistent.
*/
- if (chan_rank_empty == GENMASK(chan_rank_max - 1, 0)) {
+ if (bitmap_full(chan_rank_empty, chan_rank_max)) {
if (priv->no_dimm_retry_count < NO_DIMM_RETRY_COUNT_MAX) {
priv->no_dimm_retry_count++;
@@ -274,14 +276,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* It's possible that memory training is not done yet. In this case we
* defer the detection to be performed at a later point in time.
*/
- if (!dimm_mask) {
+ if (bitmap_empty(dimm_mask, DIMM_NUMS_MAX)) {
priv->no_dimm_retry_count = 0;
return -EAGAIN;
}
- dev_dbg(priv->dev, "Scanned populated DIMMs: %#x\n", dimm_mask);
+ for_each_set_bit(i, dimm_mask, DIMM_NUMS_MAX) {
+ dev_dbg(priv->dev, "Found DIMM%#x\n", i);
+ }
- bitmap_from_arr32(priv->dimm_mask, &dimm_mask, DIMM_NUMS_MAX);
+ bitmap_copy(priv->dimm_mask, dimm_mask, DIMM_NUMS_MAX);
return 0;
}
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 270b6336b76d..b4e93bd5835e 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -317,6 +317,13 @@ config SENSORS_MP2975
This driver can also be built as a module. If so, the module will
be called mp2975.
+config SENSORS_MP2975_REGULATOR
+ depends on SENSORS_MP2975 && REGULATOR
+ bool "Regulator support for MPS MP2975"
+ help
+ If you say yes here you get regulator support for MPS MP2975
+ Dual Loop Digital Multi-Phase Controller.
+
config SENSORS_MP5023
tristate "MPS MP5023"
help
diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c
index 0a0ef4ce3493..e0c55fd8f3a6 100644
--- a/drivers/hwmon/pmbus/acbel-fsg032.c
+++ b/drivers/hwmon/pmbus/acbel-fsg032.c
@@ -3,14 +3,51 @@
* Copyright 2023 IBM Corp.
*/
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pmbus.h>
#include <linux/hwmon-sysfs.h>
#include "pmbus.h"
+#define ACBEL_MFR_FW_REVISION 0xd9
+
+static ssize_t acbel_fsg032_debugfs_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct i2c_client *client = file->private_data;
+ u8 data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
+ char out[8];
+ int rc;
+
+ rc = i2c_smbus_read_block_data(client, ACBEL_MFR_FW_REVISION, data);
+ if (rc < 0)
+ return rc;
+
+ rc = snprintf(out, sizeof(out), "%*phN\n", min(rc, 3), data);
+ return simple_read_from_buffer(buf, count, ppos, out, rc);
+}
+
+static const struct file_operations acbel_debugfs_ops = {
+ .llseek = noop_llseek,
+ .read = acbel_fsg032_debugfs_read,
+ .write = NULL,
+ .open = simple_open,
+};
+
+static void acbel_fsg032_init_debugfs(struct i2c_client *client)
+{
+ struct dentry *debugfs = pmbus_get_debugfs_dir(client);
+
+ if (!debugfs)
+ return;
+
+ debugfs_create_file("fw_version", 0444, debugfs, client, &acbel_debugfs_ops);
+}
+
static const struct i2c_device_id acbel_fsg032_id[] = {
{ "acbel_fsg032" },
{}
@@ -59,6 +96,7 @@ static int acbel_fsg032_probe(struct i2c_client *client)
if (rc)
return rc;
+ acbel_fsg032_init_debugfs(client);
return 0;
}
diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c
index f7ff3e4650b7..04e0d598a6e5 100644
--- a/drivers/hwmon/pmbus/dps920ab.c
+++ b/drivers/hwmon/pmbus/dps920ab.c
@@ -9,7 +9,7 @@
#include <linux/debugfs.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include "pmbus.h"
struct dps920ab_data {
diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c
index c791925b8907..1ba4c5e95820 100644
--- a/drivers/hwmon/pmbus/ibm-cffps.c
+++ b/drivers/hwmon/pmbus/ibm-cffps.c
@@ -13,7 +13,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pmbus.h>
#include "pmbus.h"
@@ -489,7 +489,7 @@ static int ibm_cffps_probe(struct i2c_client *client)
const struct i2c_device_id *id;
if (md) {
- vs = (enum versions)md;
+ vs = (uintptr_t)md;
} else {
id = i2c_match_id(ibm_cffps_id, client);
if (id)
diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c
index 871c322d3d51..04185be3fdb6 100644
--- a/drivers/hwmon/pmbus/ir38064.c
+++ b/drivers/hwmon/pmbus/ir38064.c
@@ -6,7 +6,7 @@
*
* VOUT_MODE is not supported by the device. The driver fakes VOUT linear16
* mode with exponent value -8 as direct mode with m=256/b=0/R=0.
- *
+ *
* The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however
* this driver does not currently support them.
*/
@@ -16,7 +16,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regulator/driver.h>
#include "pmbus.h"
diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c
index 7bcf27995033..d56ec24764fd 100644
--- a/drivers/hwmon/pmbus/max20730.c
+++ b/drivers/hwmon/pmbus/max20730.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pmbus.h>
#include <linux/util_macros.h>
#include "pmbus.h"
@@ -114,6 +114,7 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
const struct pmbus_driver_info *info;
const struct max20730_data *data;
char tbuf[DEBUG_FS_DATA_MAX] = { 0 };
+ char *result = tbuf;
u16 val;
info = pmbus_get_driver_info(psu->client);
@@ -148,13 +149,13 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET1_TSTAT_BIT_POS;
if (val == 0)
- len = strlcpy(tbuf, "2000\n", DEBUG_FS_DATA_MAX);
+ result = "2000\n";
else if (val == 1)
- len = strlcpy(tbuf, "125\n", DEBUG_FS_DATA_MAX);
+ result = "125\n";
else if (val == 2)
- len = strlcpy(tbuf, "62.5\n", DEBUG_FS_DATA_MAX);
+ result = "62.5\n";
else
- len = strlcpy(tbuf, "32\n", DEBUG_FS_DATA_MAX);
+ result = "32\n";
break;
case MAX20730_DEBUGFS_INTERNAL_GAIN:
val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_RGAIN_MASK)
@@ -163,35 +164,35 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
if (data->id == max20734) {
/* AN6209 */
if (val == 0)
- len = strlcpy(tbuf, "0.8\n", DEBUG_FS_DATA_MAX);
+ result = "0.8\n";
else if (val == 1)
- len = strlcpy(tbuf, "3.2\n", DEBUG_FS_DATA_MAX);
+ result = "3.2\n";
else if (val == 2)
- len = strlcpy(tbuf, "1.6\n", DEBUG_FS_DATA_MAX);
+ result = "1.6\n";
else
- len = strlcpy(tbuf, "6.4\n", DEBUG_FS_DATA_MAX);
+ result = "6.4\n";
} else if (data->id == max20730 || data->id == max20710) {
/* AN6042 or AN6140 */
if (val == 0)
- len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX);
+ result = "0.9\n";
else if (val == 1)
- len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX);
+ result = "3.6\n";
else if (val == 2)
- len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX);
+ result = "1.8\n";
else
- len = strlcpy(tbuf, "7.2\n", DEBUG_FS_DATA_MAX);
+ result = "7.2\n";
} else if (data->id == max20743) {
/* AN6042 */
if (val == 0)
- len = strlcpy(tbuf, "0.45\n", DEBUG_FS_DATA_MAX);
+ result = "0.45\n";
else if (val == 1)
- len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX);
+ result = "1.8\n";
else if (val == 2)
- len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX);
+ result = "0.9\n";
else
- len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX);
+ result = "3.6\n";
} else {
- len = strlcpy(tbuf, "Not supported\n", DEBUG_FS_DATA_MAX);
+ result = "Not supported\n";
}
break;
case MAX20730_DEBUGFS_BOOT_VOLTAGE:
@@ -199,26 +200,26 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET1_VBOOT_BIT_POS;
if (val == 0)
- len = strlcpy(tbuf, "0.6484\n", DEBUG_FS_DATA_MAX);
+ result = "0.6484\n";
else if (val == 1)
- len = strlcpy(tbuf, "0.8984\n", DEBUG_FS_DATA_MAX);
+ result = "0.8984\n";
else if (val == 2)
- len = strlcpy(tbuf, "1.0\n", DEBUG_FS_DATA_MAX);
+ result = "1.0\n";
else
- len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
+ result = "Invalid\n";
break;
case MAX20730_DEBUGFS_OUT_V_RAMP_RATE:
val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_VRATE)
>> MAX20730_MFR_DEVSET2_VRATE_BIT_POS;
if (val == 0)
- len = strlcpy(tbuf, "4\n", DEBUG_FS_DATA_MAX);
+ result = "4\n";
else if (val == 1)
- len = strlcpy(tbuf, "2\n", DEBUG_FS_DATA_MAX);
+ result = "2\n";
else if (val == 2)
- len = strlcpy(tbuf, "1\n", DEBUG_FS_DATA_MAX);
+ result = "1\n";
else
- len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
+ result = "Invalid\n";
break;
case MAX20730_DEBUGFS_OC_PROTECT_MODE:
ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_OCPM_MASK)
@@ -230,13 +231,13 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET2_SS_BIT_POS;
if (val == 0)
- len = strlcpy(tbuf, "0.75\n", DEBUG_FS_DATA_MAX);
+ result = "0.75\n";
else if (val == 1)
- len = strlcpy(tbuf, "1.5\n", DEBUG_FS_DATA_MAX);
+ result = "1.5\n";
else if (val == 2)
- len = strlcpy(tbuf, "3\n", DEBUG_FS_DATA_MAX);
+ result = "3\n";
else
- len = strlcpy(tbuf, "6\n", DEBUG_FS_DATA_MAX);
+ result = "6\n";
break;
case MAX20730_DEBUGFS_IMAX:
ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_IMAX_MASK)
@@ -287,10 +288,11 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
"%d.%d\n", ret / 10000, ret % 10000);
break;
default:
- len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
+ result = "Invalid\n";
}
- return simple_read_from_buffer(buf, count, ppos, tbuf, len);
+ len = strlen(result);
+ return simple_read_from_buffer(buf, count, ppos, result, len);
}
static const struct file_operations max20730_fops = {
@@ -714,7 +716,7 @@ static int max20730_probe(struct i2c_client *client)
}
if (client->dev.of_node)
- chip_id = (enum chips)of_device_get_match_data(dev);
+ chip_id = (uintptr_t)of_device_get_match_data(dev);
else
chip_id = i2c_match_id(max20730_id, client)->driver_data;
diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 2109b0458a8b..26ba50633100 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include "pmbus.h"
/* Vendor specific registers. */
@@ -34,6 +35,8 @@
#define MP2975_MFR_OVP_TH_SET 0xe5
#define MP2975_MFR_UVP_SET 0xe6
+#define MP2973_MFR_RESO_SET 0xc7
+
#define MP2975_VOUT_FORMAT BIT(15)
#define MP2975_VID_STEP_SEL_R1 BIT(4)
#define MP2975_IMVP9_EN_R1 BIT(13)
@@ -48,43 +51,80 @@
#define MP2975_SENSE_AMPL_HALF 2
#define MP2975_VIN_UV_LIMIT_UNIT 8
+#define MP2973_VOUT_FORMAT_R1 GENMASK(7, 6)
+#define MP2973_VOUT_FORMAT_R2 GENMASK(4, 3)
+#define MP2973_VOUT_FORMAT_DIRECT_R1 BIT(7)
+#define MP2973_VOUT_FORMAT_LINEAR_R1 BIT(6)
+#define MP2973_VOUT_FORMAT_DIRECT_R2 BIT(4)
+#define MP2973_VOUT_FORMAT_LINEAR_R2 BIT(3)
+
+#define MP2973_MFR_VR_MULTI_CONFIG_R1 0x0d
+#define MP2973_MFR_VR_MULTI_CONFIG_R2 0x1d
+#define MP2973_VID_STEP_SEL_R1 BIT(4)
+#define MP2973_IMVP9_EN_R1 BIT(14)
+#define MP2973_VID_STEP_SEL_R2 BIT(3)
+#define MP2973_IMVP9_EN_R2 BIT(13)
+
+#define MP2973_MFR_OCP_TOTAL_SET 0x5f
+#define MP2973_OCP_TOTAL_CUR_MASK GENMASK(6, 0)
+#define MP2973_MFR_OCP_LEVEL_RES BIT(15)
+
+#define MP2973_MFR_READ_IOUT_PK 0x90
+#define MP2973_MFR_READ_POUT_PK 0x91
+
#define MP2975_MAX_PHASE_RAIL1 8
#define MP2975_MAX_PHASE_RAIL2 4
+
+#define MP2973_MAX_PHASE_RAIL1 14
+#define MP2973_MAX_PHASE_RAIL2 6
+
+#define MP2971_MAX_PHASE_RAIL1 8
+#define MP2971_MAX_PHASE_RAIL2 3
+
#define MP2975_PAGE_NUM 2
#define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
+enum chips {
+ mp2971, mp2973, mp2975
+};
+
+static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
+ [mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
+ [mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 },
+ [mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 },
+};
+
struct mp2975_data {
struct pmbus_driver_info info;
+ enum chips chip_id;
int vout_scale;
+ int max_phases[MP2975_PAGE_NUM];
int vid_step[MP2975_PAGE_NUM];
int vref[MP2975_PAGE_NUM];
int vref_off[MP2975_PAGE_NUM];
int vout_max[MP2975_PAGE_NUM];
int vout_ov_fixed[MP2975_PAGE_NUM];
- int vout_format[MP2975_PAGE_NUM];
int curr_sense_gain[MP2975_PAGE_NUM];
};
-#define to_mp2975_data(x) container_of(x, struct mp2975_data, info)
+static const struct i2c_device_id mp2975_id[] = {
+ {"mp2971", mp2971},
+ {"mp2973", mp2973},
+ {"mp2975", mp2975},
+ {}
+};
-static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
-{
- switch (reg) {
- case PMBUS_VOUT_MODE:
- /*
- * Enforce VOUT direct format, since device allows to set the
- * different formats for the different rails. Conversion from
- * VID to direct provided by driver internally, in case it is
- * necessary.
- */
- return PB_VOUT_MODE_DIRECT;
- default:
- return -ENODATA;
- }
-}
+MODULE_DEVICE_TABLE(i2c, mp2975_id);
+
+static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = {
+ PMBUS_REGULATOR("vout", 0),
+ PMBUS_REGULATOR("vout", 1),
+};
+
+#define to_mp2975_data(x) container_of(x, struct mp2975_data, info)
static int
mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
@@ -117,6 +157,41 @@ mp2975_vid2direct(int vrf, int val)
return 0;
}
+#define MAX_LIN_MANTISSA (1023 * 1000)
+#define MIN_LIN_MANTISSA (511 * 1000)
+
+/* Converts a milli-unit DIRECT value to LINEAR11 format */
+static u16 mp2975_data2reg_linear11(s64 val)
+{
+ s16 exponent = 0, mantissa;
+ bool negative = false;
+
+ /* simple case */
+ if (val == 0)
+ return 0;
+
+ /* Reduce large mantissa until it fits into 10 bit */
+ while (val >= MAX_LIN_MANTISSA && exponent < 15) {
+ exponent++;
+ val >>= 1;
+ }
+ /* Increase small mantissa to improve precision */
+ while (val < MIN_LIN_MANTISSA && exponent > -15) {
+ exponent--;
+ val <<= 1;
+ }
+
+ /* Convert mantissa from milli-units to units */
+ mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff);
+
+ /* restore sign */
+ if (negative)
+ mantissa = -mantissa;
+
+ /* Convert to 5 bit exponent, 11 bit mantissa */
+ return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
static int
mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data,
int page, int phase, u8 reg)
@@ -214,6 +289,89 @@ mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data,
return ret;
}
+static int mp2973_read_word_data(struct i2c_client *client, int page,
+ int phase, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct mp2975_data *data = to_mp2975_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_OT_FAULT_LIMIT:
+ ret = mp2975_read_word_helper(client, page, phase, reg,
+ GENMASK(7, 0));
+ break;
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ ret = mp2975_read_word_helper(client, page, phase, reg,
+ GENMASK(7, 0));
+ if (ret < 0)
+ return ret;
+
+ ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT);
+ break;
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ /*
+ * MP2971 and mp2973 only supports tracking (ovp1) mode.
+ */
+ ret = mp2975_read_word_helper(client, page, phase,
+ MP2975_MFR_OVP_TH_SET,
+ GENMASK(2, 0));
+ if (ret < 0)
+ return ret;
+
+ ret = data->vout_max[page] + 50 * (ret + 1);
+ break;
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ ret = mp2975_read_word_helper(client, page, phase, reg,
+ GENMASK(8, 0));
+ if (ret < 0)
+ return ret;
+ ret = mp2975_vid2direct(info->vrm_version[page], ret);
+ break;
+ case PMBUS_VIRT_READ_POUT_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ MP2973_MFR_READ_POUT_PK);
+ break;
+ case PMBUS_VIRT_READ_IOUT_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ MP2973_MFR_READ_IOUT_PK);
+ break;
+ case PMBUS_IOUT_OC_FAULT_LIMIT:
+ ret = mp2975_read_word_helper(client, page, phase,
+ MP2973_MFR_OCP_TOTAL_SET,
+ GENMASK(15, 0));
+ if (ret < 0)
+ return ret;
+
+ if (ret & MP2973_MFR_OCP_LEVEL_RES)
+ ret = 2 * (ret & MP2973_OCP_TOTAL_CUR_MASK);
+ else
+ ret = ret & MP2973_OCP_TOTAL_CUR_MASK;
+
+ ret = mp2975_data2reg_linear11(ret * info->phases[page] * 1000);
+ break;
+ case PMBUS_UT_WARN_LIMIT:
+ case PMBUS_UT_FAULT_LIMIT:
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_IIN_OC_FAULT_LIMIT:
+ case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ case PMBUS_POUT_OP_FAULT_LIMIT:
+ case PMBUS_POUT_OP_WARN_LIMIT:
+ case PMBUS_PIN_OP_WARN_LIMIT:
+ return -ENXIO;
+ default:
+ return -ENODATA;
+ }
+
+ return ret;
+}
+
static int mp2975_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
@@ -222,6 +380,11 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
int ret;
switch (reg) {
+ case PMBUS_STATUS_WORD:
+ /* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ ret ^= PB_STATUS_POWER_GOOD_N;
+ break;
case PMBUS_OT_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(7, 0));
@@ -260,24 +423,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 *
(ret + 1) * data->vout_scale, 10);
break;
- case PMBUS_READ_VOUT:
- ret = mp2975_read_word_helper(client, page, phase, reg,
- GENMASK(11, 0));
- if (ret < 0)
- return ret;
-
- /*
- * READ_VOUT can be provided in VID or direct format. The
- * format type is specified by bit 15 of the register
- * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct
- * format, since device allows to set the different formats for
- * the different rails and also all VOUT limits registers are
- * provided in a direct format. In case format is VID - convert
- * to direct.
- */
- if (data->vout_format[page] == vid)
- ret = mp2975_vid2direct(info->vrm_version[page], ret);
- break;
case PMBUS_VIRT_READ_POUT_MAX:
ret = mp2975_read_word_helper(client, page, phase,
MP2975_MFR_READ_POUT_PK,
@@ -326,25 +471,25 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
return ret;
}
-static int mp2975_identify_multiphase_rail2(struct i2c_client *client)
+static int mp2975_identify_multiphase_rail2(struct i2c_client *client,
+ struct mp2975_data *data)
{
int ret;
/*
- * Identify multiphase for rail 2 - could be from 0 to 4.
+ * Identify multiphase for rail 2 - could be from 0 to data->max_phases[1].
* In case phase number is zero – only page zero is supported
*/
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
if (ret < 0)
return ret;
- /* Identify multiphase for rail 2 - could be from 0 to 4. */
ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2);
if (ret < 0)
return ret;
ret &= GENMASK(2, 0);
- return (ret >= 4) ? 4 : ret;
+ return (ret >= data->max_phases[1]) ? data->max_phases[1] : ret;
}
static void mp2975_set_phase_rail1(struct pmbus_driver_info *info)
@@ -375,7 +520,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
if (ret < 0)
return ret;
- /* Identify multiphase for rail 1 - could be from 1 to 8. */
+ /* Identify multiphase for rail 1 - could be from 1 to data->max_phases[0]. */
ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1);
if (ret <= 0)
return ret;
@@ -383,21 +528,23 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
info->phases[0] = ret & GENMASK(3, 0);
/*
- * The device provides a total of 8 PWM pins, and can be configured
+ * The device provides a total of $n PWM pins, and can be configured
* to different phase count applications for rail 1 and rail 2.
- * Rail 1 can be set to 8 phases, while rail 2 can only be set to 4
- * phases at most. When rail 1’s phase count is configured as 0, rail
+ * Rail 1 can be set to $n phases, while rail 2 can be set to less than
+ * that. When rail 1’s phase count is configured as 0, rail
* 1 operates with 1-phase DCM. When rail 2 phase count is configured
* as 0, rail 2 is disabled.
*/
- if (info->phases[0] > MP2975_MAX_PHASE_RAIL1)
+ if (info->phases[0] > data->max_phases[0])
return -EINVAL;
- mp2975_set_phase_rail1(info);
- num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0],
- MP2975_MAX_PHASE_RAIL2);
- if (info->phases[1] && info->phases[1] <= num_phases2)
- mp2975_set_phase_rail2(info, num_phases2);
+ if (data->chip_id == mp2975) {
+ mp2975_set_phase_rail1(info);
+ num_phases2 = min(data->max_phases[0] - info->phases[0],
+ data->max_phases[1]);
+ if (info->phases[1] && info->phases[1] <= num_phases2)
+ mp2975_set_phase_rail2(info, num_phases2);
+ }
return 0;
}
@@ -451,6 +598,35 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
MP2975_MFR_VR_MULTI_CONFIG_R2, 1,
MP2975_IMVP9_EN_R2,
MP2975_VID_STEP_SEL_R2);
+
+ return ret;
+}
+
+static int
+mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
+ struct pmbus_driver_info *info)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
+ if (ret < 0)
+ return ret;
+
+ /* Identify VID mode for rail 1. */
+ ret = mp2975_identify_vid(client, data, info,
+ MP2973_MFR_VR_MULTI_CONFIG_R1, 0,
+ MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1);
+
+ if (ret < 0)
+ return ret;
+
+ /* Identify VID mode for rail 2, if connected. */
+ if (info->phases[1])
+ ret = mp2975_identify_vid(client, data, info,
+ MP2973_MFR_VR_MULTI_CONFIG_R2, 1,
+ MP2973_IMVP9_EN_R2,
+ MP2973_VID_STEP_SEL_R2);
+
return ret;
}
@@ -565,20 +741,37 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
}
static int
-mp2975_identify_vout_format(struct i2c_client *client,
- struct mp2975_data *data, int page)
+mp2975_set_vout_format(struct i2c_client *client,
+ struct mp2975_data *data, int page)
{
- int ret;
+ int ret, i;
- ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
- if (ret < 0)
- return ret;
-
- if (ret & MP2975_VOUT_FORMAT)
- data->vout_format[page] = vid;
- else
- data->vout_format[page] = direct;
- return 0;
+ /* Enable DIRECT VOUT format 1mV/LSB */
+ if (data->chip_id == mp2975) {
+ ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
+ if (ret < 0)
+ return ret;
+ if (ret & MP2975_VOUT_FORMAT) {
+ ret &= ~MP2975_VOUT_FORMAT;
+ ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
+ }
+ } else {
+ ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET);
+ if (ret < 0)
+ return ret;
+ i = ret;
+
+ if (page == 0) {
+ i &= ~MP2973_VOUT_FORMAT_R1;
+ i |= MP2973_VOUT_FORMAT_DIRECT_R1;
+ } else {
+ i &= ~MP2973_VOUT_FORMAT_R2;
+ i |= MP2973_VOUT_FORMAT_DIRECT_R2;
+ }
+ if (i != ret)
+ ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, i);
+ }
+ return ret;
}
static int
@@ -600,7 +793,7 @@ mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data,
if (ret < 0)
return ret;
thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON :
- MP2975_PROT_DEV_OV_OFF;
+ MP2975_PROT_DEV_OV_OFF;
/* Select the gain of remote sense amplifier. */
ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP);
@@ -624,10 +817,10 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
for (i = 0; i < data->info.pages; i++) {
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
if (ret < 0)
- return ret;
+ continue;
- /* Obtain voltage reference offsets. */
- ret = mp2975_vref_offset_get(client, data, i);
+ /* Set VOUT format for READ_VOUT command : direct. */
+ ret = mp2975_set_vout_format(client, data, i);
if (ret < 0)
return ret;
@@ -636,12 +829,12 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
if (ret < 0)
return ret;
- /*
- * Get VOUT format for READ_VOUT command : VID or direct.
- * Pages on same device can be configured with different
- * formats.
- */
- ret = mp2975_identify_vout_format(client, data, i);
+ /* Skip if reading Vref is unsupported */
+ if (data->chip_id != mp2975)
+ continue;
+
+ /* Obtain voltage reference offsets. */
+ ret = mp2975_vref_offset_get(client, data, i);
if (ret < 0)
return ret;
@@ -676,8 +869,32 @@ static struct pmbus_driver_info mp2975_info = {
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
- .read_byte_data = mp2975_read_byte_data,
.read_word_data = mp2975_read_word_data,
+#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
+ .num_regulators = 1,
+ .reg_desc = mp2975_reg_desc,
+#endif
+};
+
+static struct pmbus_driver_info mp2973_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_TEMPERATURE] = linear,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_POWER] = linear,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
+ PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
+ .read_word_data = mp2973_read_word_data,
+#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
+ .num_regulators = 1,
+ .reg_desc = mp2975_reg_desc,
+#endif
};
static int mp2975_probe(struct i2c_client *client)
@@ -691,11 +908,23 @@ static int mp2975_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- memcpy(&data->info, &mp2975_info, sizeof(*info));
+ if (client->dev.of_node)
+ data->chip_id = (enum chips)(unsigned long)of_device_get_match_data(&client->dev);
+ else
+ data->chip_id = i2c_match_id(mp2975_id, client)->driver_data;
+
+ memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
+ sizeof(data->max_phases));
+
+ if (data->chip_id == mp2975)
+ memcpy(&data->info, &mp2975_info, sizeof(*info));
+ else
+ memcpy(&data->info, &mp2973_info, sizeof(*info));
+
info = &data->info;
/* Identify multiphase configuration for rail 2. */
- ret = mp2975_identify_multiphase_rail2(client);
+ ret = mp2975_identify_multiphase_rail2(client, data);
if (ret < 0)
return ret;
@@ -704,6 +933,8 @@ static int mp2975_probe(struct i2c_client *client)
data->info.pages = MP2975_PAGE_NUM;
data->info.phases[1] = ret;
data->info.func[1] = MP2975_RAIL2_FUNC;
+ if (IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR))
+ data->info.num_regulators = MP2975_PAGE_NUM;
}
/* Identify multiphase configuration. */
@@ -711,25 +942,32 @@ static int mp2975_probe(struct i2c_client *client)
if (ret)
return ret;
- /* Identify VID setting per rail. */
- ret = mp2975_identify_rails_vid(client, data, info);
- if (ret < 0)
- return ret;
+ if (data->chip_id == mp2975) {
+ /* Identify VID setting per rail. */
+ ret = mp2975_identify_rails_vid(client, data, info);
+ if (ret < 0)
+ return ret;
- /* Obtain current sense gain of power stage. */
- ret = mp2975_current_sense_gain_get(client, data);
- if (ret)
- return ret;
+ /* Obtain current sense gain of power stage. */
+ ret = mp2975_current_sense_gain_get(client, data);
+ if (ret)
+ return ret;
- /* Obtain voltage reference values. */
- ret = mp2975_vref_get(client, data, info);
- if (ret)
- return ret;
+ /* Obtain voltage reference values. */
+ ret = mp2975_vref_get(client, data, info);
+ if (ret)
+ return ret;
- /* Obtain vout over-voltage scales. */
- ret = mp2975_vout_ov_scale_get(client, data, info);
- if (ret < 0)
- return ret;
+ /* Obtain vout over-voltage scales. */
+ ret = mp2975_vout_ov_scale_get(client, data, info);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* Identify VID setting per rail. */
+ ret = mp2973_identify_rails_vid(client, data, info);
+ if (ret < 0)
+ return ret;
+ }
/* Obtain offsets, maximum and format for vout. */
ret = mp2975_vout_per_rail_config_get(client, data, info);
@@ -739,15 +977,10 @@ static int mp2975_probe(struct i2c_client *client)
return pmbus_do_probe(client, info);
}
-static const struct i2c_device_id mp2975_id[] = {
- {"mp2975", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, mp2975_id);
-
static const struct of_device_id __maybe_unused mp2975_of_match[] = {
- {.compatible = "mps,mp2975"},
+ {.compatible = "mps,mp2971", .data = (void *)mp2971},
+ {.compatible = "mps,mp2973", .data = (void *)mp2973},
+ {.compatible = "mps,mp2975", .data = (void *)mp2975},
{}
};
MODULE_DEVICE_TABLE(of, mp2975_of_match);
diff --git a/drivers/hwmon/pmbus/mp5023.c b/drivers/hwmon/pmbus/mp5023.c
index c4c4324d2b74..21acb7fd9a1a 100644
--- a/drivers/hwmon/pmbus/mp5023.c
+++ b/drivers/hwmon/pmbus/mp5023.c
@@ -5,7 +5,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include "pmbus.h"
static struct pmbus_driver_info mp5023_info = {
diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c
index 865d42edda1a..6c62f01da7c6 100644
--- a/drivers/hwmon/pmbus/mpq7932.c
+++ b/drivers/hwmon/pmbus/mpq7932.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pmbus.h>
#include "pmbus.h"
diff --git a/drivers/hwmon/pmbus/pli1209bc.c b/drivers/hwmon/pmbus/pli1209bc.c
index 7d8bd3167b21..c95433790b11 100644
--- a/drivers/hwmon/pmbus/pli1209bc.c
+++ b/drivers/hwmon/pmbus/pli1209bc.c
@@ -5,6 +5,7 @@
* Copyright (c) 2022 9elements GmbH
*/
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pmbus.h>
@@ -53,6 +54,30 @@ static int pli1209bc_read_word_data(struct i2c_client *client, int page,
}
}
+static int pli1209bc_write_byte(struct i2c_client *client, int page, u8 reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_CLEAR_FAULTS:
+ ret = pmbus_write_byte(client, page, reg);
+ /*
+ * PLI1209 takes 230 usec to execute the CLEAR_FAULTS command.
+ * During that time it's busy and NACKs all requests on the
+ * SMBUS interface. It also NACKs reads on PMBUS_STATUS_BYTE
+ * making it impossible to poll the BUSY flag.
+ *
+ * Just wait for not BUSY unconditionally.
+ */
+ usleep_range(250, 300);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
static const struct regulator_desc pli1209bc_reg_desc = {
.name = "vout2",
@@ -102,6 +127,7 @@ static struct pmbus_driver_info pli1209bc_info = {
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT,
.read_word_data = pli1209bc_read_word_data,
+ .write_byte = pli1209bc_write_byte,
#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
.num_regulators = 1,
.reg_desc = &pli1209bc_reg_desc,
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 69a4e62b6c8d..1363d9f89181 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -561,7 +561,8 @@ static bool pmbus_check_register(struct i2c_client *client,
rv = pmbus_check_status_cml(client);
if (rv < 0 && (data->flags & PMBUS_READ_STATUS_AFTER_FAILED_CHECK))
data->read_status(client, -1);
- pmbus_clear_fault_page(client, -1);
+ if (reg < PMBUS_VIRT_BASE)
+ pmbus_clear_fault_page(client, -1);
return rv >= 0;
}
@@ -2540,7 +2541,6 @@ static int pmbus_identify_common(struct i2c_client *client,
}
}
- pmbus_clear_fault_page(client, page);
return 0;
}
diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c
index b830f3b02bcc..a235c1cdf4fe 100644
--- a/drivers/hwmon/pmbus/q54sj108a2.c
+++ b/drivers/hwmon/pmbus/q54sj108a2.c
@@ -10,7 +10,7 @@
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include "pmbus.h"
#define STORE_DEFAULT_ALL 0x11
diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
index ef99005a3af5..5c9466244d70 100644
--- a/drivers/hwmon/pmbus/tps53679.c
+++ b/drivers/hwmon/pmbus/tps53679.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include "pmbus.h"
enum chips {
@@ -235,7 +235,7 @@ static int tps53679_probe(struct i2c_client *client)
enum chips chip_id;
if (dev->of_node)
- chip_id = (enum chips)of_device_get_match_data(dev);
+ chip_id = (uintptr_t)of_device_get_match_data(dev);
else
chip_id = i2c_match_id(tps53679_id, client)->driver_data;
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
index c404d306e8f7..8d9d422450e5 100644
--- a/drivers/hwmon/pmbus/ucd9000.c
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -10,7 +10,7 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
@@ -588,7 +588,7 @@ static int ucd9000_probe(struct i2c_client *client)
}
if (client->dev.of_node)
- chip = (enum chips)of_device_get_match_data(&client->dev);
+ chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = mid->driver_data;
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
index a82847945508..7920d1c06df0 100644
--- a/drivers/hwmon/pmbus/ucd9200.c
+++ b/drivers/hwmon/pmbus/ucd9200.c
@@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
@@ -103,7 +103,7 @@ static int ucd9200_probe(struct i2c_client *client)
}
if (client->dev.of_node)
- chip = (enum chips)of_device_get_match_data(&client->dev);
+ chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = mid->driver_data;
diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index b79cece4ac9a..dd85cf89f008 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -13,7 +13,6 @@
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/of.h>
/*
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c
index 121e5e9f487f..a0d220609565 100644
--- a/drivers/hwmon/scpi-hwmon.c
+++ b/drivers/hwmon/scpi-hwmon.c
@@ -8,7 +8,7 @@
#include <linux/hwmon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>
diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c
index bf18630619e0..79657910b79e 100644
--- a/drivers/hwmon/sht3x.c
+++ b/drivers/hwmon/sht3x.c
@@ -147,8 +147,20 @@ static const u16 mode_to_update_interval[] = {
100,
};
+static const struct hwmon_channel_info * const sht3x_channel_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN |
+ HWMON_T_MIN_HYST | HWMON_T_MAX |
+ HWMON_T_MAX_HYST | HWMON_T_ALARM),
+ HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN |
+ HWMON_H_MIN_HYST | HWMON_H_MAX |
+ HWMON_H_MAX_HYST | HWMON_H_ALARM),
+ NULL,
+};
+
struct sht3x_data {
struct i2c_client *client;
+ enum sht3x_chips chip_id;
struct mutex i2c_lock; /* lock for sending i2c commands */
struct mutex data_lock; /* lock for updating driver data */
@@ -276,27 +288,24 @@ out:
return data;
}
-/* sysfs attributes */
-static ssize_t temp1_input_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int temp1_input_read(struct device *dev)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
- return sprintf(buf, "%d\n", data->temperature);
+ return data->temperature;
}
-static ssize_t humidity1_input_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int humidity1_input_read(struct device *dev)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
- return sprintf(buf, "%u\n", data->humidity);
+ return data->humidity;
}
/*
@@ -332,33 +341,24 @@ static int limits_update(struct sht3x_data *data)
return ret;
}
-static ssize_t temp1_limit_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int temp1_limit_read(struct device *dev, int index)
{
struct sht3x_data *data = dev_get_drvdata(dev);
- u8 index = to_sensor_dev_attr(attr)->index;
- int temperature_limit = data->temperature_limits[index];
- return sysfs_emit(buf, "%d\n", temperature_limit);
+ return data->temperature_limits[index];
}
-static ssize_t humidity1_limit_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int humidity1_limit_read(struct device *dev, int index)
{
struct sht3x_data *data = dev_get_drvdata(dev);
- u8 index = to_sensor_dev_attr(attr)->index;
- u32 humidity_limit = data->humidity_limits[index];
- return sysfs_emit(buf, "%u\n", humidity_limit);
+ return data->humidity_limits[index];
}
/*
- * limit_store must only be called with data_lock held
+ * limit_write must only be called with data_lock held
*/
-static size_t limit_store(struct device *dev,
- size_t count,
+static size_t limit_write(struct device *dev,
u8 index,
int temperature,
u32 humidity)
@@ -379,7 +379,7 @@ static size_t limit_store(struct device *dev,
* ST = (T + 45) / 175 * 2^16
* SRH = RH / 100 * 2^16
* adapted for fixed point arithmetic and packed the same as
- * in limit_show()
+ * in limit_read()
*/
raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7);
raw |= ((humidity * 42950) >> 16) & 0xfe00;
@@ -400,50 +400,35 @@ static size_t limit_store(struct device *dev,
data->temperature_limits[index] = temperature;
data->humidity_limits[index] = humidity;
- return count;
+
+ return 0;
}
-static ssize_t temp1_limit_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
+static int temp1_limit_write(struct device *dev, int index, int val)
{
int temperature;
int ret;
struct sht3x_data *data = dev_get_drvdata(dev);
- u8 index = to_sensor_dev_attr(attr)->index;
- ret = kstrtoint(buf, 0, &temperature);
- if (ret)
- return ret;
-
- temperature = clamp_val(temperature, SHT3X_MIN_TEMPERATURE,
+ temperature = clamp_val(val, SHT3X_MIN_TEMPERATURE,
SHT3X_MAX_TEMPERATURE);
mutex_lock(&data->data_lock);
- ret = limit_store(dev, count, index, temperature,
+ ret = limit_write(dev, index, temperature,
data->humidity_limits[index]);
mutex_unlock(&data->data_lock);
return ret;
}
-static ssize_t humidity1_limit_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
+static int humidity1_limit_write(struct device *dev, int index, int val)
{
u32 humidity;
int ret;
struct sht3x_data *data = dev_get_drvdata(dev);
- u8 index = to_sensor_dev_attr(attr)->index;
-
- ret = kstrtou32(buf, 0, &humidity);
- if (ret)
- return ret;
- humidity = clamp_val(humidity, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY);
+ humidity = clamp_val(val, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY);
mutex_lock(&data->data_lock);
- ret = limit_store(dev, count, index, data->temperature_limits[index],
+ ret = limit_write(dev, index, data->temperature_limits[index],
humidity);
mutex_unlock(&data->data_lock);
@@ -474,7 +459,6 @@ static void sht3x_select_command(struct sht3x_data *data)
}
static int status_register_read(struct device *dev,
- struct device_attribute *attr,
char *buffer, int length)
{
int ret;
@@ -487,34 +471,30 @@ static int status_register_read(struct device *dev,
return ret;
}
-static ssize_t temp1_alarm_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int temp1_alarm_read(struct device *dev)
{
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
- ret = status_register_read(dev, attr, buffer,
+ ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
- return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x04));
+ return !!(buffer[0] & 0x04);
}
-static ssize_t humidity1_alarm_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int humidity1_alarm_read(struct device *dev)
{
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
- ret = status_register_read(dev, attr, buffer,
+ ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
- return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x08));
+ return !!(buffer[0] & 0x08);
}
static ssize_t heater_enable_show(struct device *dev,
@@ -524,7 +504,7 @@ static ssize_t heater_enable_show(struct device *dev,
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
- ret = status_register_read(dev, attr, buffer,
+ ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
@@ -560,39 +540,28 @@ static ssize_t heater_enable_store(struct device *dev,
return ret;
}
-static ssize_t update_interval_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int update_interval_read(struct device *dev)
{
struct sht3x_data *data = dev_get_drvdata(dev);
- return sysfs_emit(buf, "%u\n",
- mode_to_update_interval[data->mode]);
+ return mode_to_update_interval[data->mode];
}
-static ssize_t update_interval_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
+static int update_interval_write(struct device *dev, int val)
{
- u16 update_interval;
u8 mode;
int ret;
const char *command;
struct sht3x_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- ret = kstrtou16(buf, 0, &update_interval);
- if (ret)
- return ret;
-
- mode = get_mode_from_update_interval(update_interval);
+ mode = get_mode_from_update_interval(val);
mutex_lock(&data->data_lock);
/* mode did not change */
if (mode == data->mode) {
mutex_unlock(&data->data_lock);
- return count;
+ return 0;
}
mutex_lock(&data->i2c_lock);
@@ -634,7 +603,7 @@ out:
if (ret != SHT3X_CMD_LENGTH)
return ret < 0 ? ret : -EIO;
- return count;
+ return 0;
}
static ssize_t repeatability_show(struct device *dev,
@@ -668,60 +637,219 @@ static ssize_t repeatability_store(struct device *dev,
return count;
}
-static SENSOR_DEVICE_ATTR_RO(temp1_input, temp1_input, 0);
-static SENSOR_DEVICE_ATTR_RO(humidity1_input, humidity1_input, 0);
-static SENSOR_DEVICE_ATTR_RW(temp1_max, temp1_limit, limit_max);
-static SENSOR_DEVICE_ATTR_RW(humidity1_max, humidity1_limit, limit_max);
-static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp1_limit, limit_max_hyst);
-static SENSOR_DEVICE_ATTR_RW(humidity1_max_hyst, humidity1_limit,
- limit_max_hyst);
-static SENSOR_DEVICE_ATTR_RW(temp1_min, temp1_limit, limit_min);
-static SENSOR_DEVICE_ATTR_RW(humidity1_min, humidity1_limit, limit_min);
-static SENSOR_DEVICE_ATTR_RW(temp1_min_hyst, temp1_limit, limit_min_hyst);
-static SENSOR_DEVICE_ATTR_RW(humidity1_min_hyst, humidity1_limit,
- limit_min_hyst);
-static SENSOR_DEVICE_ATTR_RO(temp1_alarm, temp1_alarm, 0);
-static SENSOR_DEVICE_ATTR_RO(humidity1_alarm, humidity1_alarm, 0);
static SENSOR_DEVICE_ATTR_RW(heater_enable, heater_enable, 0);
-static SENSOR_DEVICE_ATTR_RW(update_interval, update_interval, 0);
static SENSOR_DEVICE_ATTR_RW(repeatability, repeatability, 0);
static struct attribute *sht3x_attrs[] = {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_humidity1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
- &sensor_dev_attr_humidity1_max.dev_attr.attr,
- &sensor_dev_attr_humidity1_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
- &sensor_dev_attr_humidity1_min.dev_attr.attr,
- &sensor_dev_attr_humidity1_min_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_alarm.dev_attr.attr,
- &sensor_dev_attr_humidity1_alarm.dev_attr.attr,
&sensor_dev_attr_heater_enable.dev_attr.attr,
- &sensor_dev_attr_update_interval.dev_attr.attr,
&sensor_dev_attr_repeatability.dev_attr.attr,
NULL
};
-static struct attribute *sts3x_attrs[] = {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_alarm.dev_attr.attr,
- &sensor_dev_attr_heater_enable.dev_attr.attr,
- &sensor_dev_attr_update_interval.dev_attr.attr,
- &sensor_dev_attr_repeatability.dev_attr.attr,
- NULL
+ATTRIBUTE_GROUPS(sht3x);
+
+static umode_t sht3x_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct sht3x_data *chip_data = data;
+
+ switch (type) {
+ case hwmon_chip:
+ switch (attr) {
+ case hwmon_chip_update_interval:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ case hwmon_temp_alarm:
+ return 0444;
+ case hwmon_temp_max:
+ case hwmon_temp_max_hyst:
+ case hwmon_temp_min:
+ case hwmon_temp_min_hyst:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_humidity:
+ if (chip_data->chip_id == sts3x)
+ break;
+ switch (attr) {
+ case hwmon_humidity_input:
+ case hwmon_humidity_alarm:
+ return 0444;
+ case hwmon_humidity_max:
+ case hwmon_humidity_max_hyst:
+ case hwmon_humidity_min:
+ case hwmon_humidity_min_hyst:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int sht3x_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ enum sht3x_limits index;
+
+ switch (type) {
+ case hwmon_chip:
+ switch (attr) {
+ case hwmon_chip_update_interval:
+ *val = update_interval_read(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = temp1_input_read(dev);
+ break;
+ case hwmon_temp_alarm:
+ *val = temp1_alarm_read(dev);
+ break;
+ case hwmon_temp_max:
+ index = limit_max;
+ *val = temp1_limit_read(dev, index);
+ break;
+ case hwmon_temp_max_hyst:
+ index = limit_max_hyst;
+ *val = temp1_limit_read(dev, index);
+ break;
+ case hwmon_temp_min:
+ index = limit_min;
+ *val = temp1_limit_read(dev, index);
+ break;
+ case hwmon_temp_min_hyst:
+ index = limit_min_hyst;
+ *val = temp1_limit_read(dev, index);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ break;
+ case hwmon_humidity:
+ switch (attr) {
+ case hwmon_humidity_input:
+ *val = humidity1_input_read(dev);
+ break;
+ case hwmon_humidity_alarm:
+ *val = humidity1_alarm_read(dev);
+ break;
+ case hwmon_humidity_max:
+ index = limit_max;
+ *val = humidity1_limit_read(dev, index);
+ break;
+ case hwmon_humidity_max_hyst:
+ index = limit_max_hyst;
+ *val = humidity1_limit_read(dev, index);
+ break;
+ case hwmon_humidity_min:
+ index = limit_min;
+ *val = humidity1_limit_read(dev, index);
+ break;
+ case hwmon_humidity_min_hyst:
+ index = limit_min_hyst;
+ *val = humidity1_limit_read(dev, index);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int sht3x_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ enum sht3x_limits index;
+
+ switch (type) {
+ case hwmon_chip:
+ switch (attr) {
+ case hwmon_chip_update_interval:
+ return update_interval_write(dev, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_max:
+ index = limit_max;
+ break;
+ case hwmon_temp_max_hyst:
+ index = limit_max_hyst;
+ break;
+ case hwmon_temp_min:
+ index = limit_min;
+ break;
+ case hwmon_temp_min_hyst:
+ index = limit_min_hyst;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return temp1_limit_write(dev, index, val);
+ case hwmon_humidity:
+ switch (attr) {
+ case hwmon_humidity_max:
+ index = limit_max;
+ break;
+ case hwmon_humidity_max_hyst:
+ index = limit_max_hyst;
+ break;
+ case hwmon_humidity_min:
+ index = limit_min;
+ break;
+ case hwmon_humidity_min_hyst:
+ index = limit_min_hyst;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return humidity1_limit_write(dev, index, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_ops sht3x_ops = {
+ .is_visible = sht3x_is_visible,
+ .read = sht3x_read,
+ .write = sht3x_write,
};
-ATTRIBUTE_GROUPS(sht3x);
-ATTRIBUTE_GROUPS(sts3x);
+static const struct hwmon_chip_info sht3x_chip_info = {
+ .ops = &sht3x_ops,
+ .info = sht3x_channel_info,
+};
+
+/* device ID table */
+static const struct i2c_device_id sht3x_ids[] = {
+ {"sht3x", sht3x},
+ {"sts3x", sts3x},
+ {}
+};
-static const struct i2c_device_id sht3x_ids[];
+MODULE_DEVICE_TABLE(i2c, sht3x_ids);
static int sht3x_probe(struct i2c_client *client)
{
@@ -730,7 +858,6 @@ static int sht3x_probe(struct i2c_client *client)
struct device *hwmon_dev;
struct i2c_adapter *adap = client->adapter;
struct device *dev = &client->dev;
- const struct attribute_group **attribute_groups;
/*
* we require full i2c support since the sht3x uses multi-byte read and
@@ -753,6 +880,7 @@ static int sht3x_probe(struct i2c_client *client)
data->mode = 0;
data->last_update = jiffies - msecs_to_jiffies(3000);
data->client = client;
+ data->chip_id = i2c_match_id(sht3x_ids, client)->driver_data;
crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL);
sht3x_select_command(data);
@@ -771,15 +899,11 @@ static int sht3x_probe(struct i2c_client *client)
if (ret)
return ret;
- if (i2c_match_id(sht3x_ids, client)->driver_data == sts3x)
- attribute_groups = sts3x_groups;
- else
- attribute_groups = sht3x_groups;
-
- hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- client->name,
- data,
- attribute_groups);
+ hwmon_dev = devm_hwmon_device_register_with_info(dev,
+ client->name,
+ data,
+ &sht3x_chip_info,
+ sht3x_groups);
if (IS_ERR(hwmon_dev))
dev_dbg(dev, "unable to register hwmon device\n");
@@ -787,15 +911,6 @@ static int sht3x_probe(struct i2c_client *client)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
-/* device ID table */
-static const struct i2c_device_id sht3x_ids[] = {
- {"sht3x", sht3x},
- {"sts3x", sts3x},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, sht3x_ids);
-
static struct i2c_driver sht3x_i2c_driver = {
.driver.name = "sht3x",
.probe = sht3x_probe,
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index b0b05fd12221..0a0479501e11 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -798,7 +798,7 @@ static int sis5595_pci_probe(struct pci_dev *dev,
{
u16 address;
u8 enable;
- int *i;
+ int *i, err;
for (i = blacklist; *i != 0; i++) {
struct pci_dev *d;
@@ -818,8 +818,8 @@ static int sis5595_pci_probe(struct pci_dev *dev,
pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
}
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+ err = pci_read_config_word(dev, SIS5595_BASE_REG, &address);
+ if (err != PCIBIOS_SUCCESSFUL) {
dev_err(&dev->dev, "Failed to read ISA address\n");
return -ENODEV;
}
@@ -836,22 +836,23 @@ static int sis5595_pci_probe(struct pci_dev *dev,
return -ENODEV;
}
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+ err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
+ if (err != PCIBIOS_SUCCESSFUL) {
dev_err(&dev->dev, "Failed to read enable register\n");
return -ENODEV;
}
if (!(enable & 0x80)) {
- if ((PCIBIOS_SUCCESSFUL !=
- pci_write_config_byte(dev, SIS5595_ENABLE_REG,
- enable | 0x80))
- || (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
- || (!(enable & 0x80))) {
- /* doesn't work for some chips! */
- dev_err(&dev->dev, "Failed to enable HWM device\n");
- return -ENODEV;
- }
+ err = pci_write_config_byte(dev, SIS5595_ENABLE_REG, enable | 0x80);
+ if (err != PCIBIOS_SUCCESSFUL)
+ goto enable_fail;
+
+ err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
+ if (err != PCIBIOS_SUCCESSFUL)
+ goto enable_fail;
+
+ /* doesn't work for some chips! */
+ if (!(enable & 0x80))
+ goto enable_fail;
}
if (platform_driver_register(&sis5595_driver)) {
@@ -871,6 +872,10 @@ static int sis5595_pci_probe(struct pci_dev *dev,
*/
return -ENODEV;
+enable_fail:
+ dev_err(&dev->dev, "Failed to enable HWM device\n");
+ goto exit;
+
exit_unregister:
pci_dev_put(dev);
platform_driver_unregister(&sis5595_driver);
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
deleted file mode 100644
index 026c76f8c22e..000000000000
--- a/drivers/hwmon/smm665.c
+++ /dev/null
@@ -1,706 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for SMM665 Power Controller / Monitor
- *
- * Copyright (C) 2010 Ericsson AB.
- *
- * This driver should also work for SMM465, SMM764, and SMM766, but is untested
- * for those chips. Only monitoring functionality is implemented.
- *
- * Datasheets:
- * http://www.summitmicro.com/prod_select/summary/SMM665/SMM665B_2089_20.pdf
- * http://www.summitmicro.com/prod_select/summary/SMM766B/SMM766B_2122.pdf
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-
-/* Internal reference voltage (VREF, x 1000 */
-#define SMM665_VREF_ADC_X1000 1250
-
-/* module parameters */
-static int vref = SMM665_VREF_ADC_X1000;
-module_param(vref, int, 0);
-MODULE_PARM_DESC(vref, "Reference voltage in mV");
-
-enum chips { smm465, smm665, smm665c, smm764, smm766 };
-
-/*
- * ADC channel addresses
- */
-#define SMM665_MISC16_ADC_DATA_A 0x00
-#define SMM665_MISC16_ADC_DATA_B 0x01
-#define SMM665_MISC16_ADC_DATA_C 0x02
-#define SMM665_MISC16_ADC_DATA_D 0x03
-#define SMM665_MISC16_ADC_DATA_E 0x04
-#define SMM665_MISC16_ADC_DATA_F 0x05
-#define SMM665_MISC16_ADC_DATA_VDD 0x06
-#define SMM665_MISC16_ADC_DATA_12V 0x07
-#define SMM665_MISC16_ADC_DATA_INT_TEMP 0x08
-#define SMM665_MISC16_ADC_DATA_AIN1 0x09
-#define SMM665_MISC16_ADC_DATA_AIN2 0x0a
-
-/*
- * Command registers
- */
-#define SMM665_MISC8_CMD_STS 0x80
-#define SMM665_MISC8_STATUS1 0x81
-#define SMM665_MISC8_STATUSS2 0x82
-#define SMM665_MISC8_IO_POLARITY 0x83
-#define SMM665_MISC8_PUP_POLARITY 0x84
-#define SMM665_MISC8_ADOC_STATUS1 0x85
-#define SMM665_MISC8_ADOC_STATUS2 0x86
-#define SMM665_MISC8_WRITE_PROT 0x87
-#define SMM665_MISC8_STS_TRACK 0x88
-
-/*
- * Configuration registers and register groups
- */
-#define SMM665_ADOC_ENABLE 0x0d
-#define SMM665_LIMIT_BASE 0x80 /* First limit register */
-
-/*
- * Limit register bit masks
- */
-#define SMM665_TRIGGER_RST 0x8000
-#define SMM665_TRIGGER_HEALTHY 0x4000
-#define SMM665_TRIGGER_POWEROFF 0x2000
-#define SMM665_TRIGGER_SHUTDOWN 0x1000
-#define SMM665_ADC_MASK 0x03ff
-
-#define smm665_is_critical(lim) ((lim) & (SMM665_TRIGGER_RST \
- | SMM665_TRIGGER_POWEROFF \
- | SMM665_TRIGGER_SHUTDOWN))
-/*
- * Fault register bit definitions
- * Values are merged from status registers 1/2,
- * with status register 1 providing the upper 8 bits.
- */
-#define SMM665_FAULT_A 0x0001
-#define SMM665_FAULT_B 0x0002
-#define SMM665_FAULT_C 0x0004
-#define SMM665_FAULT_D 0x0008
-#define SMM665_FAULT_E 0x0010
-#define SMM665_FAULT_F 0x0020
-#define SMM665_FAULT_VDD 0x0040
-#define SMM665_FAULT_12V 0x0080
-#define SMM665_FAULT_TEMP 0x0100
-#define SMM665_FAULT_AIN1 0x0200
-#define SMM665_FAULT_AIN2 0x0400
-
-/*
- * I2C Register addresses
- *
- * The configuration register needs to be the configured base register.
- * The command/status register address is derived from it.
- */
-#define SMM665_REGMASK 0x78
-#define SMM665_CMDREG_BASE 0x48
-#define SMM665_CONFREG_BASE 0x50
-
-/*
- * Equations given by chip manufacturer to calculate voltage/temperature values
- * vref = Reference voltage on VREF_ADC pin (module parameter)
- * adc = 10bit ADC value read back from registers
- */
-
-/* Voltage A-F and VDD */
-#define SMM665_VMON_ADC_TO_VOLTS(adc) ((adc) * vref / 256)
-
-/* Voltage 12VIN */
-#define SMM665_12VIN_ADC_TO_VOLTS(adc) ((adc) * vref * 3 / 256)
-
-/* Voltage AIN1, AIN2 */
-#define SMM665_AIN_ADC_TO_VOLTS(adc) ((adc) * vref / 512)
-
-/* Temp Sensor */
-#define SMM665_TEMP_ADC_TO_CELSIUS(adc) (((adc) <= 511) ? \
- ((int)(adc) * 1000 / 4) : \
- (((int)(adc) - 0x400) * 1000 / 4))
-
-#define SMM665_NUM_ADC 11
-
-/*
- * Chip dependent ADC conversion time, in uS
- */
-#define SMM665_ADC_WAIT_SMM665 70
-#define SMM665_ADC_WAIT_SMM766 185
-
-struct smm665_data {
- enum chips type;
- int conversion_time; /* ADC conversion time */
- struct i2c_client *client;
- struct mutex update_lock;
- bool valid;
- unsigned long last_updated; /* in jiffies */
- u16 adc[SMM665_NUM_ADC]; /* adc values (raw) */
- u16 faults; /* fault status */
- /* The following values are in mV */
- int critical_min_limit[SMM665_NUM_ADC];
- int alarm_min_limit[SMM665_NUM_ADC];
- int critical_max_limit[SMM665_NUM_ADC];
- int alarm_max_limit[SMM665_NUM_ADC];
- struct i2c_client *cmdreg;
-};
-
-/*
- * smm665_read16()
- *
- * Read 16 bit value from <reg>, <reg+1>. Upper 8 bits are in <reg>.
- */
-static int smm665_read16(struct i2c_client *client, int reg)
-{
- int rv, val;
-
- rv = i2c_smbus_read_byte_data(client, reg);
- if (rv < 0)
- return rv;
- val = rv << 8;
- rv = i2c_smbus_read_byte_data(client, reg + 1);
- if (rv < 0)
- return rv;
- val |= rv;
- return val;
-}
-
-/*
- * Read adc value.
- */
-static int smm665_read_adc(struct smm665_data *data, int adc)
-{
- struct i2c_client *client = data->cmdreg;
- int rv;
- int radc;
-
- /*
- * Algorithm for reading ADC, per SMM665 datasheet
- *
- * {[S][addr][W][Ack]} {[offset][Ack]} {[S][addr][R][Nack]}
- * [wait conversion time]
- * {[S][addr][R][Ack]} {[datahi][Ack]} {[datalo][Ack][P]}
- *
- * To implement the first part of this exchange,
- * do a full read transaction and expect a failure/Nack.
- * This sets up the address pointer on the SMM665
- * and starts the ADC conversion.
- * Then do a two-byte read transaction.
- */
- rv = i2c_smbus_read_byte_data(client, adc << 3);
- if (rv != -ENXIO) {
- /*
- * We expect ENXIO to reflect NACK
- * (per Documentation/i2c/fault-codes.rst).
- * Everything else is an error.
- */
- dev_dbg(&client->dev,
- "Unexpected return code %d when setting ADC index", rv);
- return (rv < 0) ? rv : -EIO;
- }
-
- udelay(data->conversion_time);
-
- /*
- * Now read two bytes.
- *
- * Neither i2c_smbus_read_byte() nor
- * i2c_smbus_read_block_data() worked here,
- * so use i2c_smbus_read_word_swapped() instead.
- * We could also try to use i2c_master_recv(),
- * but that is not always supported.
- */
- rv = i2c_smbus_read_word_swapped(client, 0);
- if (rv < 0) {
- dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
- return rv;
- }
- /*
- * Validate/verify readback adc channel (in bit 11..14).
- */
- radc = (rv >> 11) & 0x0f;
- if (radc != adc) {
- dev_dbg(&client->dev, "Unexpected RADC: Expected %d got %d",
- adc, radc);
- return -EIO;
- }
-
- return rv & SMM665_ADC_MASK;
-}
-
-static struct smm665_data *smm665_update_device(struct device *dev)
-{
- struct smm665_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- struct smm665_data *ret = data;
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- int i, val;
-
- /*
- * read status registers
- */
- val = smm665_read16(client, SMM665_MISC8_STATUS1);
- if (unlikely(val < 0)) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->faults = val;
-
- /* Read adc registers */
- for (i = 0; i < SMM665_NUM_ADC; i++) {
- val = smm665_read_adc(data, i);
- if (unlikely(val < 0)) {
- ret = ERR_PTR(val);
- goto abort;
- }
- data->adc[i] = val;
- }
- data->last_updated = jiffies;
- data->valid = true;
- }
-abort:
- mutex_unlock(&data->update_lock);
- return ret;
-}
-
-/* Return converted value from given adc */
-static int smm665_convert(u16 adcval, int index)
-{
- int val = 0;
-
- switch (index) {
- case SMM665_MISC16_ADC_DATA_12V:
- val = SMM665_12VIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
- break;
-
- case SMM665_MISC16_ADC_DATA_VDD:
- case SMM665_MISC16_ADC_DATA_A:
- case SMM665_MISC16_ADC_DATA_B:
- case SMM665_MISC16_ADC_DATA_C:
- case SMM665_MISC16_ADC_DATA_D:
- case SMM665_MISC16_ADC_DATA_E:
- case SMM665_MISC16_ADC_DATA_F:
- val = SMM665_VMON_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
- break;
-
- case SMM665_MISC16_ADC_DATA_AIN1:
- case SMM665_MISC16_ADC_DATA_AIN2:
- val = SMM665_AIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
- break;
-
- case SMM665_MISC16_ADC_DATA_INT_TEMP:
- val = SMM665_TEMP_ADC_TO_CELSIUS(adcval & SMM665_ADC_MASK);
- break;
-
- default:
- /* If we get here, the developer messed up */
- WARN_ON_ONCE(1);
- break;
- }
-
- return val;
-}
-
-static int smm665_get_min(struct device *dev, int index)
-{
- struct smm665_data *data = dev_get_drvdata(dev);
-
- return data->alarm_min_limit[index];
-}
-
-static int smm665_get_max(struct device *dev, int index)
-{
- struct smm665_data *data = dev_get_drvdata(dev);
-
- return data->alarm_max_limit[index];
-}
-
-static int smm665_get_lcrit(struct device *dev, int index)
-{
- struct smm665_data *data = dev_get_drvdata(dev);
-
- return data->critical_min_limit[index];
-}
-
-static int smm665_get_crit(struct device *dev, int index)
-{
- struct smm665_data *data = dev_get_drvdata(dev);
-
- return data->critical_max_limit[index];
-}
-
-static ssize_t smm665_show_crit_alarm(struct device *dev,
- struct device_attribute *da, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct smm665_data *data = smm665_update_device(dev);
- int val = 0;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- if (data->faults & (1 << attr->index))
- val = 1;
-
- return sysfs_emit(buf, "%d\n", val);
-}
-
-static ssize_t smm665_show_input(struct device *dev,
- struct device_attribute *da, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct smm665_data *data = smm665_update_device(dev);
- int adc = attr->index;
- int val;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- val = smm665_convert(data->adc[adc], adc);
- return sysfs_emit(buf, "%d\n", val);
-}
-
-#define SMM665_SHOW(what) \
-static ssize_t smm665_show_##what(struct device *dev, \
- struct device_attribute *da, char *buf) \
-{ \
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
- const int val = smm665_get_##what(dev, attr->index); \
- return snprintf(buf, PAGE_SIZE, "%d\n", val); \
-}
-
-SMM665_SHOW(min);
-SMM665_SHOW(max);
-SMM665_SHOW(lcrit);
-SMM665_SHOW(crit);
-
-/*
- * These macros are used below in constructing device attribute objects
- * for use with sysfs_create_group() to make a sysfs device file
- * for each register.
- */
-
-#define SMM665_ATTR(name, type, cmd_idx) \
- static SENSOR_DEVICE_ATTR(name##_##type, S_IRUGO, \
- smm665_show_##type, NULL, cmd_idx)
-
-/* Construct a sensor_device_attribute structure for each register */
-
-/* Input voltages */
-SMM665_ATTR(in1, input, SMM665_MISC16_ADC_DATA_12V);
-SMM665_ATTR(in2, input, SMM665_MISC16_ADC_DATA_VDD);
-SMM665_ATTR(in3, input, SMM665_MISC16_ADC_DATA_A);
-SMM665_ATTR(in4, input, SMM665_MISC16_ADC_DATA_B);
-SMM665_ATTR(in5, input, SMM665_MISC16_ADC_DATA_C);
-SMM665_ATTR(in6, input, SMM665_MISC16_ADC_DATA_D);
-SMM665_ATTR(in7, input, SMM665_MISC16_ADC_DATA_E);
-SMM665_ATTR(in8, input, SMM665_MISC16_ADC_DATA_F);
-SMM665_ATTR(in9, input, SMM665_MISC16_ADC_DATA_AIN1);
-SMM665_ATTR(in10, input, SMM665_MISC16_ADC_DATA_AIN2);
-
-/* Input voltages min */
-SMM665_ATTR(in1, min, SMM665_MISC16_ADC_DATA_12V);
-SMM665_ATTR(in2, min, SMM665_MISC16_ADC_DATA_VDD);
-SMM665_ATTR(in3, min, SMM665_MISC16_ADC_DATA_A);
-SMM665_ATTR(in4, min, SMM665_MISC16_ADC_DATA_B);
-SMM665_ATTR(in5, min, SMM665_MISC16_ADC_DATA_C);
-SMM665_ATTR(in6, min, SMM665_MISC16_ADC_DATA_D);
-SMM665_ATTR(in7, min, SMM665_MISC16_ADC_DATA_E);
-SMM665_ATTR(in8, min, SMM665_MISC16_ADC_DATA_F);
-SMM665_ATTR(in9, min, SMM665_MISC16_ADC_DATA_AIN1);
-SMM665_ATTR(in10, min, SMM665_MISC16_ADC_DATA_AIN2);
-
-/* Input voltages max */
-SMM665_ATTR(in1, max, SMM665_MISC16_ADC_DATA_12V);
-SMM665_ATTR(in2, max, SMM665_MISC16_ADC_DATA_VDD);
-SMM665_ATTR(in3, max, SMM665_MISC16_ADC_DATA_A);
-SMM665_ATTR(in4, max, SMM665_MISC16_ADC_DATA_B);
-SMM665_ATTR(in5, max, SMM665_MISC16_ADC_DATA_C);
-SMM665_ATTR(in6, max, SMM665_MISC16_ADC_DATA_D);
-SMM665_ATTR(in7, max, SMM665_MISC16_ADC_DATA_E);
-SMM665_ATTR(in8, max, SMM665_MISC16_ADC_DATA_F);
-SMM665_ATTR(in9, max, SMM665_MISC16_ADC_DATA_AIN1);
-SMM665_ATTR(in10, max, SMM665_MISC16_ADC_DATA_AIN2);
-
-/* Input voltages lcrit */
-SMM665_ATTR(in1, lcrit, SMM665_MISC16_ADC_DATA_12V);
-SMM665_ATTR(in2, lcrit, SMM665_MISC16_ADC_DATA_VDD);
-SMM665_ATTR(in3, lcrit, SMM665_MISC16_ADC_DATA_A);
-SMM665_ATTR(in4, lcrit, SMM665_MISC16_ADC_DATA_B);
-SMM665_ATTR(in5, lcrit, SMM665_MISC16_ADC_DATA_C);
-SMM665_ATTR(in6, lcrit, SMM665_MISC16_ADC_DATA_D);
-SMM665_ATTR(in7, lcrit, SMM665_MISC16_ADC_DATA_E);
-SMM665_ATTR(in8, lcrit, SMM665_MISC16_ADC_DATA_F);
-SMM665_ATTR(in9, lcrit, SMM665_MISC16_ADC_DATA_AIN1);
-SMM665_ATTR(in10, lcrit, SMM665_MISC16_ADC_DATA_AIN2);
-
-/* Input voltages crit */
-SMM665_ATTR(in1, crit, SMM665_MISC16_ADC_DATA_12V);
-SMM665_ATTR(in2, crit, SMM665_MISC16_ADC_DATA_VDD);
-SMM665_ATTR(in3, crit, SMM665_MISC16_ADC_DATA_A);
-SMM665_ATTR(in4, crit, SMM665_MISC16_ADC_DATA_B);
-SMM665_ATTR(in5, crit, SMM665_MISC16_ADC_DATA_C);
-SMM665_ATTR(in6, crit, SMM665_MISC16_ADC_DATA_D);
-SMM665_ATTR(in7, crit, SMM665_MISC16_ADC_DATA_E);
-SMM665_ATTR(in8, crit, SMM665_MISC16_ADC_DATA_F);
-SMM665_ATTR(in9, crit, SMM665_MISC16_ADC_DATA_AIN1);
-SMM665_ATTR(in10, crit, SMM665_MISC16_ADC_DATA_AIN2);
-
-/* critical alarms */
-SMM665_ATTR(in1, crit_alarm, SMM665_FAULT_12V);
-SMM665_ATTR(in2, crit_alarm, SMM665_FAULT_VDD);
-SMM665_ATTR(in3, crit_alarm, SMM665_FAULT_A);
-SMM665_ATTR(in4, crit_alarm, SMM665_FAULT_B);
-SMM665_ATTR(in5, crit_alarm, SMM665_FAULT_C);
-SMM665_ATTR(in6, crit_alarm, SMM665_FAULT_D);
-SMM665_ATTR(in7, crit_alarm, SMM665_FAULT_E);
-SMM665_ATTR(in8, crit_alarm, SMM665_FAULT_F);
-SMM665_ATTR(in9, crit_alarm, SMM665_FAULT_AIN1);
-SMM665_ATTR(in10, crit_alarm, SMM665_FAULT_AIN2);
-
-/* Temperature */
-SMM665_ATTR(temp1, input, SMM665_MISC16_ADC_DATA_INT_TEMP);
-SMM665_ATTR(temp1, min, SMM665_MISC16_ADC_DATA_INT_TEMP);
-SMM665_ATTR(temp1, max, SMM665_MISC16_ADC_DATA_INT_TEMP);
-SMM665_ATTR(temp1, lcrit, SMM665_MISC16_ADC_DATA_INT_TEMP);
-SMM665_ATTR(temp1, crit, SMM665_MISC16_ADC_DATA_INT_TEMP);
-SMM665_ATTR(temp1, crit_alarm, SMM665_FAULT_TEMP);
-
-/*
- * Finally, construct an array of pointers to members of the above objects,
- * as required for sysfs_create_group()
- */
-static struct attribute *smm665_attrs[] = {
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in1_lcrit.dev_attr.attr,
- &sensor_dev_attr_in1_crit.dev_attr.attr,
- &sensor_dev_attr_in1_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in2_lcrit.dev_attr.attr,
- &sensor_dev_attr_in2_crit.dev_attr.attr,
- &sensor_dev_attr_in2_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in3_min.dev_attr.attr,
- &sensor_dev_attr_in3_max.dev_attr.attr,
- &sensor_dev_attr_in3_lcrit.dev_attr.attr,
- &sensor_dev_attr_in3_crit.dev_attr.attr,
- &sensor_dev_attr_in3_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in4_min.dev_attr.attr,
- &sensor_dev_attr_in4_max.dev_attr.attr,
- &sensor_dev_attr_in4_lcrit.dev_attr.attr,
- &sensor_dev_attr_in4_crit.dev_attr.attr,
- &sensor_dev_attr_in4_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in5_input.dev_attr.attr,
- &sensor_dev_attr_in5_min.dev_attr.attr,
- &sensor_dev_attr_in5_max.dev_attr.attr,
- &sensor_dev_attr_in5_lcrit.dev_attr.attr,
- &sensor_dev_attr_in5_crit.dev_attr.attr,
- &sensor_dev_attr_in5_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in6_input.dev_attr.attr,
- &sensor_dev_attr_in6_min.dev_attr.attr,
- &sensor_dev_attr_in6_max.dev_attr.attr,
- &sensor_dev_attr_in6_lcrit.dev_attr.attr,
- &sensor_dev_attr_in6_crit.dev_attr.attr,
- &sensor_dev_attr_in6_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in7_input.dev_attr.attr,
- &sensor_dev_attr_in7_min.dev_attr.attr,
- &sensor_dev_attr_in7_max.dev_attr.attr,
- &sensor_dev_attr_in7_lcrit.dev_attr.attr,
- &sensor_dev_attr_in7_crit.dev_attr.attr,
- &sensor_dev_attr_in7_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in8_input.dev_attr.attr,
- &sensor_dev_attr_in8_min.dev_attr.attr,
- &sensor_dev_attr_in8_max.dev_attr.attr,
- &sensor_dev_attr_in8_lcrit.dev_attr.attr,
- &sensor_dev_attr_in8_crit.dev_attr.attr,
- &sensor_dev_attr_in8_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in9_input.dev_attr.attr,
- &sensor_dev_attr_in9_min.dev_attr.attr,
- &sensor_dev_attr_in9_max.dev_attr.attr,
- &sensor_dev_attr_in9_lcrit.dev_attr.attr,
- &sensor_dev_attr_in9_crit.dev_attr.attr,
- &sensor_dev_attr_in9_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_in10_input.dev_attr.attr,
- &sensor_dev_attr_in10_min.dev_attr.attr,
- &sensor_dev_attr_in10_max.dev_attr.attr,
- &sensor_dev_attr_in10_lcrit.dev_attr.attr,
- &sensor_dev_attr_in10_crit.dev_attr.attr,
- &sensor_dev_attr_in10_crit_alarm.dev_attr.attr,
-
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_lcrit.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
-
- NULL,
-};
-
-ATTRIBUTE_GROUPS(smm665);
-
-static const struct i2c_device_id smm665_id[];
-
-static int smm665_probe(struct i2c_client *client)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct smm665_data *data;
- struct device *hwmon_dev;
- int i, ret;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_WORD_DATA))
- return -ENODEV;
-
- if (i2c_smbus_read_byte_data(client, SMM665_ADOC_ENABLE) < 0)
- return -ENODEV;
-
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
-
- data->client = client;
- data->type = i2c_match_id(smm665_id, client)->driver_data;
- data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK)
- | SMM665_CMDREG_BASE);
- if (IS_ERR(data->cmdreg))
- return PTR_ERR(data->cmdreg);
-
- switch (data->type) {
- case smm465:
- case smm665:
- data->conversion_time = SMM665_ADC_WAIT_SMM665;
- break;
- case smm665c:
- case smm764:
- case smm766:
- data->conversion_time = SMM665_ADC_WAIT_SMM766;
- break;
- }
-
- ret = -ENODEV;
- if (i2c_smbus_read_byte_data(data->cmdreg, SMM665_MISC8_CMD_STS) < 0)
- goto out_unregister;
-
- /*
- * Read limits.
- *
- * Limit registers start with register SMM665_LIMIT_BASE.
- * Each channel uses 8 registers, providing four limit values
- * per channel. Each limit value requires two registers, with the
- * high byte in the first register and the low byte in the second
- * register. The first two limits are under limit values, followed
- * by two over limit values.
- *
- * Limit register order matches the ADC register order, so we use
- * ADC register defines throughout the code to index limit registers.
- *
- * We save the first retrieved value both as "critical" and "alarm"
- * value. The second value overwrites either the critical or the
- * alarm value, depending on its configuration. This ensures that both
- * critical and alarm values are initialized, even if both registers are
- * configured as critical or non-critical.
- */
- for (i = 0; i < SMM665_NUM_ADC; i++) {
- int val;
-
- val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8);
- if (unlikely(val < 0))
- goto out_unregister;
- data->critical_min_limit[i] = data->alarm_min_limit[i]
- = smm665_convert(val, i);
- val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 2);
- if (unlikely(val < 0))
- goto out_unregister;
- if (smm665_is_critical(val))
- data->critical_min_limit[i] = smm665_convert(val, i);
- else
- data->alarm_min_limit[i] = smm665_convert(val, i);
- val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 4);
- if (unlikely(val < 0))
- goto out_unregister;
- data->critical_max_limit[i] = data->alarm_max_limit[i]
- = smm665_convert(val, i);
- val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 6);
- if (unlikely(val < 0))
- goto out_unregister;
- if (smm665_is_critical(val))
- data->critical_max_limit[i] = smm665_convert(val, i);
- else
- data->alarm_max_limit[i] = smm665_convert(val, i);
- }
-
- hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
- client->name, data,
- smm665_groups);
- if (IS_ERR(hwmon_dev)) {
- ret = PTR_ERR(hwmon_dev);
- goto out_unregister;
- }
-
- return 0;
-
-out_unregister:
- i2c_unregister_device(data->cmdreg);
- return ret;
-}
-
-static void smm665_remove(struct i2c_client *client)
-{
- struct smm665_data *data = i2c_get_clientdata(client);
-
- i2c_unregister_device(data->cmdreg);
-}
-
-static const struct i2c_device_id smm665_id[] = {
- {"smm465", smm465},
- {"smm665", smm665},
- {"smm665c", smm665c},
- {"smm764", smm764},
- {"smm766", smm766},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, smm665_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver smm665_driver = {
- .driver = {
- .name = "smm665",
- },
- .probe = smm665_probe,
- .remove = smm665_remove,
- .id_table = smm665_id,
-};
-
-module_i2c_driver(smm665_driver);
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("SMM665 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 3cde3916ab6d..10b66c9ce045 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -20,7 +20,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/sysfs.h>
/* Addresses to scan */
diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c
index 4b79c3f4d9fe..f58ca4c6acb6 100644
--- a/drivers/hwmon/tmp464.c
+++ b/drivers/hwmon/tmp464.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c
index bff10f4b56e1..9a180b1030c9 100644
--- a/drivers/hwmon/tmp513.c
+++ b/drivers/hwmon/tmp513.c
@@ -434,7 +434,7 @@ static umode_t tmp51x_is_visible(const void *_data,
switch (type) {
case hwmon_temp:
- if (data->id == tmp512 && channel == 4)
+ if (data->id == tmp512 && channel == 3)
return 0;
switch (attr) {
case hwmon_temp_input:
@@ -720,10 +720,7 @@ static int tmp51x_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- if (client->dev.of_node)
- data->id = (enum tmp51x_ids)device_get_match_data(&client->dev);
- else
- data->id = i2c_match_id(tmp51x_id, client)->driver_data;
+ data->id = (uintptr_t)i2c_get_match_data(client);
ret = tmp51x_configure(dev, data);
if (ret < 0) {
diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c
index 8fbbb29ae11d..d33ecbac00d6 100644
--- a/drivers/hwmon/tps23861.c
+++ b/drivers/hwmon/tps23861.c
@@ -14,7 +14,7 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#define TEMPERATURE 0x2c
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index b23cff2e3d5d..3b580f229887 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -9,7 +9,8 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
diff --git a/drivers/hwmon/vexpress-hwmon.c b/drivers/hwmon/vexpress-hwmon.c
index 2ac5fb96bba4..d82a3b454d0e 100644
--- a/drivers/hwmon/vexpress-hwmon.c
+++ b/drivers/hwmon/vexpress-hwmon.c
@@ -13,7 +13,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/vexpress.h>
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 37d7374896f6..407933d6e425 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -855,16 +855,17 @@ static int via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 address, val;
+ int ret;
if (force_addr) {
address = force_addr & ~(VIA686A_EXTENT - 1);
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+ ret = pci_write_config_word(dev, VIA686A_BASE_REG, address | 1);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, VIA686A_BASE_REG, &val))
+ ret = pci_read_config_word(dev, VIA686A_BASE_REG, &val);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
address = val & ~(VIA686A_EXTENT - 1);
@@ -874,8 +875,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
return -ENODEV;
}
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+ ret = pci_read_config_word(dev, VIA686A_ENABLE_REG, &val);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
if (!(val & 0x0001)) {
if (!force_addr) {
@@ -886,9 +887,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
}
dev_warn(&dev->dev, "Enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(dev, VIA686A_ENABLE_REG,
- val | 0x0001))
+ ret = pci_write_config_word(dev, VIA686A_ENABLE_REG, val | 0x1);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index b7c6392ba673..16bc16d33cd1 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -971,13 +971,15 @@ static int vt8231_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 address, val;
+ int ret;
+
if (force_addr) {
address = force_addr & 0xff00;
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+ ret = pci_write_config_word(dev, VT8231_BASE_REG, address | 1);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
@@ -997,9 +999,8 @@ static int vt8231_pci_probe(struct pci_dev *dev,
if (!(val & 0x0001)) {
dev_warn(&dev->dev, "enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(dev, VT8231_ENABLE_REG,
- val | 0x0001))
+ ret = pci_write_config_word(dev, VT8231_ENABLE_REG, val | 0x1);
+ if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c
index 7f3615f5587c..045eea8378c2 100644
--- a/drivers/hwmon/w83773g.c
+++ b/drivers/hwmon/w83773g.c
@@ -12,7 +12,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
/* W83773 has 3 channels */
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 256c2d42e350..ea5a6a14c553 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -923,7 +923,7 @@ static struct cpuidle_state adl_l_cstates[] __initdata = {
.enter = NULL }
};
-static struct cpuidle_state adl_n_cstates[] __initdata = {
+static struct cpuidle_state gmt_cstates[] __initdata = {
{
.name = "C1",
.desc = "MWAIT 0x00",
@@ -1349,8 +1349,8 @@ static const struct idle_cpu idle_cpu_adl_l __initconst = {
.state_table = adl_l_cstates,
};
-static const struct idle_cpu idle_cpu_adl_n __initconst = {
- .state_table = adl_n_cstates,
+static const struct idle_cpu idle_cpu_gmt __initconst = {
+ .state_table = gmt_cstates,
};
static const struct idle_cpu idle_cpu_spr __initconst = {
@@ -1423,7 +1423,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &idle_cpu_icx),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &idle_cpu_adl),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &idle_cpu_adl_l),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &idle_cpu_adl_n),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &idle_cpu_gmt),
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &idle_cpu_spr),
X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &idle_cpu_spr),
X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &idle_cpu_knl),
@@ -1898,7 +1898,7 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
break;
case INTEL_FAM6_ALDERLAKE:
case INTEL_FAM6_ALDERLAKE_L:
- case INTEL_FAM6_ALDERLAKE_N:
+ case INTEL_FAM6_ATOM_GRACEMONT:
adl_idle_state_table_update();
break;
}
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 2e91d8879326..73f913cbd146 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -400,6 +400,9 @@ static void del_gid(struct ib_device *ib_dev, u32 port,
table->data_vec[ix] = NULL;
write_unlock_irq(&table->rwlock);
+ if (rdma_cap_roce_gid_table(ib_dev, port))
+ ib_dev->ops.del_gid(&entry->attr, &entry->context);
+
ndev_storage = entry->ndev_storage;
if (ndev_storage) {
entry->ndev_storage = NULL;
@@ -407,9 +410,6 @@ static void del_gid(struct ib_device *ib_dev, u32 port,
call_rcu(&ndev_storage->rcu_head, put_gid_ndev);
}
- if (rdma_cap_roce_gid_table(ib_dev, port))
- ib_dev->ops.del_gid(&entry->attr, &entry->context);
-
put_gid_entry_locked(entry);
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index b18e9f2adc82..1f8d0d2c5f17 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -82,6 +82,8 @@ static const char mlx4_ib_version[] =
static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init);
static enum rdma_link_layer mlx4_ib_port_link_layer(struct ib_device *device,
u32 port_num);
+static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
+ void *param);
static struct workqueue_struct *wq;
@@ -125,12 +127,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
u32 port_num)
{
struct mlx4_ib_dev *ibdev = to_mdev(device);
- struct net_device *dev;
+ struct net_device *dev, *ret = NULL;
rcu_read_lock();
- dev = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port_num);
+ for_each_netdev_rcu(&init_net, dev) {
+ if (dev->dev.parent != ibdev->ib_dev.dev.parent ||
+ dev->dev_port + 1 != port_num)
+ continue;
- if (dev) {
if (mlx4_is_bonded(ibdev->dev)) {
struct net_device *upper = NULL;
@@ -143,11 +147,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
dev = active;
}
}
+
+ dev_hold(dev);
+ ret = dev;
+ break;
}
- dev_hold(dev);
rcu_read_unlock();
- return dev;
+ return ret;
}
static int mlx4_ib_update_gids_v1(struct gid_entry *gids,
@@ -2319,61 +2326,53 @@ unlock:
mutex_unlock(&ibdev->qp1_proxy_lock[port - 1]);
}
-static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev,
- struct net_device *dev,
- unsigned long event)
+static void mlx4_ib_scan_netdev(struct mlx4_ib_dev *ibdev,
+ struct net_device *dev,
+ unsigned long event)
{
- struct mlx4_ib_iboe *iboe;
- int update_qps_port = -1;
- int port;
+ struct mlx4_ib_iboe *iboe = &ibdev->iboe;
ASSERT_RTNL();
- iboe = &ibdev->iboe;
+ if (dev->dev.parent != ibdev->ib_dev.dev.parent)
+ return;
spin_lock_bh(&iboe->lock);
- mlx4_foreach_ib_transport_port(port, ibdev->dev) {
-
- iboe->netdevs[port - 1] =
- mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
- if (dev == iboe->netdevs[port - 1] &&
- (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
- event == NETDEV_UP || event == NETDEV_CHANGE))
- update_qps_port = port;
+ iboe->netdevs[dev->dev_port] = event != NETDEV_UNREGISTER ? dev : NULL;
- if (dev == iboe->netdevs[port - 1] &&
- (event == NETDEV_UP || event == NETDEV_DOWN)) {
- enum ib_port_state port_state;
- struct ib_event ibev = { };
+ if (event == NETDEV_UP || event == NETDEV_DOWN) {
+ enum ib_port_state port_state;
+ struct ib_event ibev = { };
- if (ib_get_cached_port_state(&ibdev->ib_dev, port,
- &port_state))
- continue;
+ if (ib_get_cached_port_state(&ibdev->ib_dev, dev->dev_port + 1,
+ &port_state))
+ goto iboe_out;
- if (event == NETDEV_UP &&
- (port_state != IB_PORT_ACTIVE ||
- iboe->last_port_state[port - 1] != IB_PORT_DOWN))
- continue;
- if (event == NETDEV_DOWN &&
- (port_state != IB_PORT_DOWN ||
- iboe->last_port_state[port - 1] != IB_PORT_ACTIVE))
- continue;
- iboe->last_port_state[port - 1] = port_state;
-
- ibev.device = &ibdev->ib_dev;
- ibev.element.port_num = port;
- ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
- IB_EVENT_PORT_ERR;
- ib_dispatch_event(&ibev);
- }
+ if (event == NETDEV_UP &&
+ (port_state != IB_PORT_ACTIVE ||
+ iboe->last_port_state[dev->dev_port] != IB_PORT_DOWN))
+ goto iboe_out;
+ if (event == NETDEV_DOWN &&
+ (port_state != IB_PORT_DOWN ||
+ iboe->last_port_state[dev->dev_port] != IB_PORT_ACTIVE))
+ goto iboe_out;
+ iboe->last_port_state[dev->dev_port] = port_state;
+ ibev.device = &ibdev->ib_dev;
+ ibev.element.port_num = dev->dev_port + 1;
+ ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
+ IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&ibev);
}
+
+iboe_out:
spin_unlock_bh(&iboe->lock);
- if (update_qps_port > 0)
- mlx4_ib_update_qps(ibdev, dev, update_qps_port);
+ if (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
+ event == NETDEV_UP || event == NETDEV_CHANGE)
+ mlx4_ib_update_qps(ibdev, dev, dev->dev_port + 1);
}
static int mlx4_ib_netdev_event(struct notifier_block *this,
@@ -2386,7 +2385,7 @@ static int mlx4_ib_netdev_event(struct notifier_block *this,
return NOTIFY_DONE;
ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
- mlx4_ib_scan_netdevs(ibdev, dev, event);
+ mlx4_ib_scan_netdev(ibdev, dev, event);
return NOTIFY_DONE;
}
@@ -2610,8 +2609,11 @@ static const struct ib_device_ops mlx4_ib_dev_fs_ops = {
.destroy_flow = mlx4_ib_destroy_flow,
};
-static void *mlx4_ib_add(struct mlx4_dev *dev)
+static int mlx4_ib_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
+ struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
+ struct mlx4_dev *dev = madev->mdev;
struct mlx4_ib_dev *ibdev;
int num_ports = 0;
int i, j;
@@ -2631,27 +2633,31 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
/* No point in registering a device with no ports... */
if (num_ports == 0)
- return NULL;
+ return -ENODEV;
ibdev = ib_alloc_device(mlx4_ib_dev, ib_dev);
if (!ibdev) {
dev_err(&dev->persist->pdev->dev,
"Device struct alloc failed\n");
- return NULL;
+ return -ENOMEM;
}
iboe = &ibdev->iboe;
- if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
+ err = mlx4_pd_alloc(dev, &ibdev->priv_pdn);
+ if (err)
goto err_dealloc;
- if (mlx4_uar_alloc(dev, &ibdev->priv_uar))
+ err = mlx4_uar_alloc(dev, &ibdev->priv_uar);
+ if (err)
goto err_pd;
ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT,
PAGE_SIZE);
- if (!ibdev->uar_map)
+ if (!ibdev->uar_map) {
+ err = -ENOMEM;
goto err_uar;
+ }
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
ibdev->dev = dev;
@@ -2695,7 +2701,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
spin_lock_init(&iboe->lock);
- if (init_node_data(ibdev))
+ err = init_node_data(ibdev);
+ if (err)
goto err_map;
mlx4_init_sl2vl_tbl(ibdev);
@@ -2727,6 +2734,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
new_counter_index = kmalloc(sizeof(*new_counter_index),
GFP_KERNEL);
if (!new_counter_index) {
+ err = -ENOMEM;
if (allocated)
mlx4_counter_free(ibdev->dev, counter_index);
goto err_counter;
@@ -2744,8 +2752,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
new_counter_index =
kmalloc(sizeof(struct counter_index),
GFP_KERNEL);
- if (!new_counter_index)
+ if (!new_counter_index) {
+ err = -ENOMEM;
goto err_counter;
+ }
new_counter_index->index = counter_index;
new_counter_index->allocated = 0;
list_add_tail(&new_counter_index->list,
@@ -2774,8 +2784,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_uc_qpns_bitmap = bitmap_alloc(ibdev->steer_qpn_count,
GFP_KERNEL);
- if (!ibdev->ib_uc_qpns_bitmap)
+ if (!ibdev->ib_uc_qpns_bitmap) {
+ err = -ENOMEM;
goto err_steer_qp_release;
+ }
if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) {
bitmap_zero(ibdev->ib_uc_qpns_bitmap,
@@ -2795,17 +2807,21 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
atomic64_set(&iboe->mac[j - 1], ibdev->dev->caps.def_mac[j]);
- if (mlx4_ib_alloc_diag_counters(ibdev))
+ err = mlx4_ib_alloc_diag_counters(ibdev);
+ if (err)
goto err_steer_free_bitmap;
- if (ib_register_device(&ibdev->ib_dev, "mlx4_%d",
- &dev->persist->pdev->dev))
+ err = ib_register_device(&ibdev->ib_dev, "mlx4_%d",
+ &dev->persist->pdev->dev);
+ if (err)
goto err_diag_counters;
- if (mlx4_ib_mad_init(ibdev))
+ err = mlx4_ib_mad_init(ibdev);
+ if (err)
goto err_reg;
- if (mlx4_ib_init_sriov(ibdev))
+ err = mlx4_ib_init_sriov(ibdev);
+ if (err)
goto err_mad;
if (!iboe->nb.notifier_call) {
@@ -2839,7 +2855,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
do_slave_init(ibdev, j, 1);
}
}
- return ibdev;
+
+ /* register mlx4 core notifier */
+ ibdev->mlx_nb.notifier_call = mlx4_ib_event;
+ err = mlx4_register_event_notifier(dev, &ibdev->mlx_nb);
+ WARN(err, "failed to register mlx4 event notifier (%d)", err);
+
+ auxiliary_set_drvdata(adev, ibdev);
+ return 0;
err_notif:
if (ibdev->iboe.nb.notifier_call) {
@@ -2883,7 +2906,7 @@ err_pd:
err_dealloc:
ib_dealloc_device(&ibdev->ib_dev);
- return NULL;
+ return err;
}
int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn)
@@ -2950,12 +2973,16 @@ int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
return err;
}
-static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
+static void mlx4_ib_remove(struct auxiliary_device *adev)
{
- struct mlx4_ib_dev *ibdev = ibdev_ptr;
+ struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
+ struct mlx4_dev *dev = madev->mdev;
+ struct mlx4_ib_dev *ibdev = auxiliary_get_drvdata(adev);
int p;
int i;
+ mlx4_unregister_event_notifier(dev, &ibdev->mlx_nb);
+
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
ibdev->ib_active = false;
@@ -3176,11 +3203,13 @@ void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
}
}
-static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
- enum mlx4_dev_event event, unsigned long param)
+static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
+ void *param)
{
+ struct mlx4_ib_dev *ibdev =
+ container_of(this, struct mlx4_ib_dev, mlx_nb);
+ struct mlx4_dev *dev = ibdev->dev;
struct ib_event ibev;
- struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr);
struct mlx4_eqe *eqe = NULL;
struct ib_event_work *ew;
int p = 0;
@@ -3190,22 +3219,28 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
(event == MLX4_DEV_EVENT_PORT_DOWN))) {
ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
if (!ew)
- return;
+ return NOTIFY_DONE;
INIT_WORK(&ew->work, handle_bonded_port_state_event);
ew->ib_dev = ibdev;
queue_work(wq, &ew->work);
- return;
+ return NOTIFY_DONE;
}
- if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE)
+ switch (event) {
+ case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
+ break;
+ case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
eqe = (struct mlx4_eqe *)param;
- else
- p = (int) param;
+ break;
+ default:
+ p = *(int *)param;
+ break;
+ }
switch (event) {
case MLX4_DEV_EVENT_PORT_UP:
if (p > ibdev->num_ports)
- return;
+ return NOTIFY_DONE;
if (!mlx4_is_slave(dev) &&
rdma_port_get_link_layer(&ibdev->ib_dev, p) ==
IB_LINK_LAYER_INFINIBAND) {
@@ -3220,7 +3255,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_PORT_DOWN:
if (p > ibdev->num_ports)
- return;
+ return NOTIFY_DONE;
ibev.event = IB_EVENT_PORT_ERR;
break;
@@ -3233,7 +3268,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
ew = kmalloc(sizeof *ew, GFP_ATOMIC);
if (!ew)
- return;
+ return NOTIFY_DONE;
INIT_WORK(&ew->work, handle_port_mgmt_change_event);
memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
@@ -3243,7 +3278,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
queue_work(wq, &ew->work);
else
handle_port_mgmt_change_event(&ew->work);
- return;
+ return NOTIFY_DONE;
case MLX4_DEV_EVENT_SLAVE_INIT:
/* here, p is the slave id */
@@ -3259,7 +3294,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
1);
}
}
- return;
+ return NOTIFY_DONE;
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
if (mlx4_is_master(dev)) {
@@ -3275,22 +3310,33 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
}
/* here, p is the slave id */
do_slave_init(ibdev, p, 0);
- return;
+ return NOTIFY_DONE;
default:
- return;
+ return NOTIFY_DONE;
}
- ibev.device = ibdev_ptr;
+ ibev.device = &ibdev->ib_dev;
ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p;
ib_dispatch_event(&ibev);
+ return NOTIFY_DONE;
}
-static struct mlx4_interface mlx4_ib_interface = {
- .add = mlx4_ib_add,
- .remove = mlx4_ib_remove,
- .event = mlx4_ib_event,
+static const struct auxiliary_device_id mlx4_ib_id_table[] = {
+ { .name = MLX4_ADEV_NAME ".ib" },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, mlx4_ib_id_table);
+
+static struct mlx4_adrv mlx4_ib_adrv = {
+ .adrv = {
+ .name = "ib",
+ .probe = mlx4_ib_probe,
+ .remove = mlx4_ib_remove,
+ .id_table = mlx4_ib_id_table,
+ },
.protocol = MLX4_PROT_IB_IPV6,
.flags = MLX4_INTFF_BONDING
};
@@ -3315,7 +3361,7 @@ static int __init mlx4_ib_init(void)
if (err)
goto clean_cm;
- err = mlx4_register_interface(&mlx4_ib_interface);
+ err = mlx4_register_auxiliary_driver(&mlx4_ib_adrv);
if (err)
goto clean_mcg;
@@ -3337,7 +3383,7 @@ clean_qp_event:
static void __exit mlx4_ib_cleanup(void)
{
- mlx4_unregister_interface(&mlx4_ib_interface);
+ mlx4_unregister_auxiliary_driver(&mlx4_ib_adrv);
mlx4_ib_mcg_destroy();
mlx4_ib_cm_destroy();
mlx4_ib_qp_event_cleanup();
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 17fee1e73a45..41ca1114a995 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -38,6 +38,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/idr.h>
+#include <linux/notifier.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h>
@@ -644,6 +645,7 @@ struct mlx4_ib_dev {
spinlock_t reset_flow_resource_lock;
struct list_head qp_list;
struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES];
+ struct notifier_block mlx_nb;
};
struct ib_event_work {
diff --git a/drivers/infiniband/hw/mlx5/Makefile b/drivers/infiniband/hw/mlx5/Makefile
index 612ee8190a2d..72a526236c2e 100644
--- a/drivers/infiniband/hw/mlx5/Makefile
+++ b/drivers/infiniband/hw/mlx5/Makefile
@@ -28,3 +28,4 @@ mlx5_ib-$(CONFIG_INFINIBAND_USER_ACCESS) += devx.o \
fs.o \
qos.o \
std_types.o
+mlx5_ib-$(CONFIG_MLX5_MACSEC) += macsec.o
diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
index efc9e4a6df04..9773d2a3d97f 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -993,7 +993,7 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
INIT_WORK(&cq->notify_work, notify_soft_wc_handler);
}
- err = mlx5_vector2eqn(dev->mdev, vector, &eqn);
+ err = mlx5_comp_eqn_get(dev->mdev, vector, &eqn);
if (err)
goto err_cqb;
diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c
index db5fb196c728..8ba53edf2311 100644
--- a/drivers/infiniband/hw/mlx5/devx.c
+++ b/drivers/infiniband/hw/mlx5/devx.c
@@ -1002,7 +1002,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_EQN)(
return PTR_ERR(c);
dev = to_mdev(c->ibucontext.device);
- err = mlx5_vector2eqn(dev->mdev, user_vector, &dev_eqn);
+ err = mlx5_comp_eqn_get(dev->mdev, user_vector, &dev_eqn);
if (err < 0)
return err;
diff --git a/drivers/infiniband/hw/mlx5/macsec.c b/drivers/infiniband/hw/mlx5/macsec.c
new file mode 100644
index 000000000000..3c56eb5eddf3
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/macsec.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */
+
+#include "macsec.h"
+#include <linux/mlx5/macsec.h>
+
+struct mlx5_reserved_gids {
+ int macsec_index;
+ const struct ib_gid_attr *physical_gid;
+};
+
+struct mlx5_roce_gids {
+ struct list_head roce_gid_list_entry;
+ u16 gid_idx;
+ union {
+ struct sockaddr_in sockaddr_in;
+ struct sockaddr_in6 sockaddr_in6;
+ } addr;
+};
+
+struct mlx5_macsec_device {
+ struct list_head macsec_devices_list_entry;
+ void *macdev;
+ struct list_head macsec_roce_gids;
+ struct list_head tx_rules_list;
+ struct list_head rx_rules_list;
+};
+
+static void cleanup_macsec_device(struct mlx5_macsec_device *macsec_device)
+{
+ if (!list_empty(&macsec_device->tx_rules_list) ||
+ !list_empty(&macsec_device->rx_rules_list) ||
+ !list_empty(&macsec_device->macsec_roce_gids))
+ return;
+
+ list_del(&macsec_device->macsec_devices_list_entry);
+ kfree(macsec_device);
+}
+
+static struct mlx5_macsec_device *get_macsec_device(void *macdev,
+ struct list_head *macsec_devices_list)
+{
+ struct mlx5_macsec_device *iter, *macsec_device = NULL;
+
+ list_for_each_entry(iter, macsec_devices_list, macsec_devices_list_entry) {
+ if (iter->macdev == macdev) {
+ macsec_device = iter;
+ break;
+ }
+ }
+
+ if (macsec_device)
+ return macsec_device;
+
+ macsec_device = kzalloc(sizeof(*macsec_device), GFP_KERNEL);
+ if (!macsec_device)
+ return NULL;
+
+ macsec_device->macdev = macdev;
+ INIT_LIST_HEAD(&macsec_device->tx_rules_list);
+ INIT_LIST_HEAD(&macsec_device->rx_rules_list);
+ INIT_LIST_HEAD(&macsec_device->macsec_roce_gids);
+ list_add(&macsec_device->macsec_devices_list_entry, macsec_devices_list);
+
+ return macsec_device;
+}
+
+static void mlx5_macsec_del_roce_gid(struct mlx5_macsec_device *macsec_device, u16 gid_idx)
+{
+ struct mlx5_roce_gids *current_gid, *next_gid;
+
+ list_for_each_entry_safe(current_gid, next_gid, &macsec_device->macsec_roce_gids,
+ roce_gid_list_entry)
+ if (current_gid->gid_idx == gid_idx) {
+ list_del(&current_gid->roce_gid_list_entry);
+ kfree(current_gid);
+ }
+}
+
+static void mlx5_macsec_save_roce_gid(struct mlx5_macsec_device *macsec_device,
+ const struct sockaddr *addr, u16 gid_idx)
+{
+ struct mlx5_roce_gids *roce_gids;
+
+ roce_gids = kzalloc(sizeof(*roce_gids), GFP_KERNEL);
+ if (!roce_gids)
+ return;
+
+ roce_gids->gid_idx = gid_idx;
+ if (addr->sa_family == AF_INET)
+ memcpy(&roce_gids->addr.sockaddr_in, addr, sizeof(roce_gids->addr.sockaddr_in));
+ else
+ memcpy(&roce_gids->addr.sockaddr_in6, addr, sizeof(roce_gids->addr.sockaddr_in6));
+
+ list_add_tail(&roce_gids->roce_gid_list_entry, &macsec_device->macsec_roce_gids);
+}
+
+static void handle_macsec_gids(struct list_head *macsec_devices_list,
+ struct mlx5_macsec_event_data *data)
+{
+ struct mlx5_macsec_device *macsec_device;
+ struct mlx5_roce_gids *gid;
+
+ macsec_device = get_macsec_device(data->macdev, macsec_devices_list);
+ if (!macsec_device)
+ return;
+
+ list_for_each_entry(gid, &macsec_device->macsec_roce_gids, roce_gid_list_entry) {
+ mlx5_macsec_add_roce_sa_rules(data->fs_id, (struct sockaddr *)&gid->addr,
+ gid->gid_idx, &macsec_device->tx_rules_list,
+ &macsec_device->rx_rules_list, data->macsec_fs,
+ data->is_tx);
+ }
+}
+
+static void del_sa_roce_rule(struct list_head *macsec_devices_list,
+ struct mlx5_macsec_event_data *data)
+{
+ struct mlx5_macsec_device *macsec_device;
+
+ macsec_device = get_macsec_device(data->macdev, macsec_devices_list);
+ WARN_ON(!macsec_device);
+
+ mlx5_macsec_del_roce_sa_rules(data->fs_id, data->macsec_fs,
+ &macsec_device->tx_rules_list,
+ &macsec_device->rx_rules_list, data->is_tx);
+}
+
+static int macsec_event(struct notifier_block *nb, unsigned long event, void *data)
+{
+ struct mlx5_macsec *macsec = container_of(nb, struct mlx5_macsec, blocking_events_nb);
+
+ mutex_lock(&macsec->lock);
+ switch (event) {
+ case MLX5_DRIVER_EVENT_MACSEC_SA_ADDED:
+ handle_macsec_gids(&macsec->macsec_devices_list, data);
+ break;
+ case MLX5_DRIVER_EVENT_MACSEC_SA_DELETED:
+ del_sa_roce_rule(&macsec->macsec_devices_list, data);
+ break;
+ default:
+ mutex_unlock(&macsec->lock);
+ return NOTIFY_DONE;
+ }
+ mutex_unlock(&macsec->lock);
+ return NOTIFY_OK;
+}
+
+void mlx5r_macsec_event_register(struct mlx5_ib_dev *dev)
+{
+ if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+ return;
+ }
+
+ dev->macsec.blocking_events_nb.notifier_call = macsec_event;
+ blocking_notifier_chain_register(&dev->mdev->macsec_nh,
+ &dev->macsec.blocking_events_nb);
+}
+
+void mlx5r_macsec_event_unregister(struct mlx5_ib_dev *dev)
+{
+ if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+ return;
+ }
+
+ blocking_notifier_chain_unregister(&dev->mdev->macsec_nh,
+ &dev->macsec.blocking_events_nb);
+}
+
+int mlx5r_macsec_init_gids_and_devlist(struct mlx5_ib_dev *dev)
+{
+ int i, j, max_gids;
+
+ if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+ return 0;
+ }
+
+ max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);
+ for (i = 0; i < dev->num_ports; i++) {
+ dev->port[i].reserved_gids = kcalloc(max_gids,
+ sizeof(*dev->port[i].reserved_gids),
+ GFP_KERNEL);
+ if (!dev->port[i].reserved_gids)
+ goto err;
+
+ for (j = 0; j < max_gids; j++)
+ dev->port[i].reserved_gids[j].macsec_index = -1;
+ }
+
+ INIT_LIST_HEAD(&dev->macsec.macsec_devices_list);
+ mutex_init(&dev->macsec.lock);
+
+ return 0;
+err:
+ while (i >= 0) {
+ kfree(dev->port[i].reserved_gids);
+ i--;
+ }
+ return -ENOMEM;
+}
+
+void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev)
+{
+ int i;
+
+ if (!mlx5_is_macsec_roce_supported(dev->mdev))
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+
+ for (i = 0; i < dev->num_ports; i++)
+ kfree(dev->port[i].reserved_gids);
+
+ mutex_destroy(&dev->macsec.lock);
+}
+
+int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(attr->device);
+ struct mlx5_macsec_device *macsec_device;
+ const struct ib_gid_attr *physical_gid;
+ struct mlx5_reserved_gids *mgids;
+ struct net_device *ndev;
+ int ret = 0;
+ union {
+ struct sockaddr_in sockaddr_in;
+ struct sockaddr_in6 sockaddr_in6;
+ } addr;
+
+ if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
+ return 0;
+
+ if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+ return 0;
+ }
+
+ rcu_read_lock();
+ ndev = rcu_dereference(attr->ndev);
+ if (!ndev) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+
+ if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
+ rcu_read_unlock();
+ return 0;
+ }
+ dev_hold(ndev);
+ rcu_read_unlock();
+
+ mutex_lock(&dev->macsec.lock);
+ macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
+ if (!macsec_device) {
+ ret = -ENOMEM;
+ goto dev_err;
+ }
+
+ physical_gid = rdma_find_gid(attr->device, &attr->gid,
+ attr->gid_type, NULL);
+ if (!IS_ERR(physical_gid)) {
+ ret = set_roce_addr(to_mdev(physical_gid->device),
+ physical_gid->port_num,
+ physical_gid->index, NULL,
+ physical_gid);
+ if (ret)
+ goto gid_err;
+
+ mgids = &dev->port[attr->port_num - 1].reserved_gids[physical_gid->index];
+ mgids->macsec_index = attr->index;
+ mgids->physical_gid = physical_gid;
+ }
+
+ /* Proceed with adding steering rules, regardless if there was gid ambiguity or not.*/
+ rdma_gid2ip((struct sockaddr *)&addr, &attr->gid);
+ ret = mlx5_macsec_add_roce_rule(ndev, (struct sockaddr *)&addr, attr->index,
+ &macsec_device->tx_rules_list,
+ &macsec_device->rx_rules_list, dev->mdev->macsec_fs);
+ if (ret && !IS_ERR(physical_gid))
+ goto rule_err;
+
+ mlx5_macsec_save_roce_gid(macsec_device, (struct sockaddr *)&addr, attr->index);
+
+ dev_put(ndev);
+ mutex_unlock(&dev->macsec.lock);
+ return ret;
+
+rule_err:
+ set_roce_addr(to_mdev(physical_gid->device), physical_gid->port_num,
+ physical_gid->index, &physical_gid->gid, physical_gid);
+ mgids->macsec_index = -1;
+gid_err:
+ rdma_put_gid_attr(physical_gid);
+ cleanup_macsec_device(macsec_device);
+dev_err:
+ dev_put(ndev);
+ mutex_unlock(&dev->macsec.lock);
+ return ret;
+}
+
+void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr)
+{
+ struct mlx5_ib_dev *dev = to_mdev(attr->device);
+ struct mlx5_macsec_device *macsec_device;
+ struct mlx5_reserved_gids *mgids;
+ struct net_device *ndev;
+ int i, max_gids;
+
+ if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
+ return;
+
+ if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
+ mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
+ return;
+ }
+
+ mgids = &dev->port[attr->port_num - 1].reserved_gids[attr->index];
+ if (mgids->macsec_index != -1) { /* Checking if physical gid has ambiguous IP */
+ rdma_put_gid_attr(mgids->physical_gid);
+ mgids->macsec_index = -1;
+ return;
+ }
+
+ rcu_read_lock();
+ ndev = rcu_dereference(attr->ndev);
+ if (!ndev) {
+ rcu_read_unlock();
+ return;
+ }
+
+ if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
+ rcu_read_unlock();
+ return;
+ }
+ dev_hold(ndev);
+ rcu_read_unlock();
+
+ mutex_lock(&dev->macsec.lock);
+ max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);
+ for (i = 0; i < max_gids; i++) { /* Checking if macsec gid has ambiguous IP */
+ mgids = &dev->port[attr->port_num - 1].reserved_gids[i];
+ if (mgids->macsec_index == attr->index) {
+ const struct ib_gid_attr *physical_gid = mgids->physical_gid;
+
+ set_roce_addr(to_mdev(physical_gid->device),
+ physical_gid->port_num,
+ physical_gid->index,
+ &physical_gid->gid, physical_gid);
+
+ rdma_put_gid_attr(physical_gid);
+ mgids->macsec_index = -1;
+ break;
+ }
+ }
+ macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
+ mlx5_macsec_del_roce_rule(attr->index, dev->mdev->macsec_fs,
+ &macsec_device->tx_rules_list, &macsec_device->rx_rules_list);
+ mlx5_macsec_del_roce_gid(macsec_device, attr->index);
+ cleanup_macsec_device(macsec_device);
+
+ dev_put(ndev);
+ mutex_unlock(&dev->macsec.lock);
+}
diff --git a/drivers/infiniband/hw/mlx5/macsec.h b/drivers/infiniband/hw/mlx5/macsec.h
new file mode 100644
index 000000000000..9b77ba90f0f4
--- /dev/null
+++ b/drivers/infiniband/hw/mlx5/macsec.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */
+
+#ifndef __MLX5_MACSEC_H__
+#define __MLX5_MACSEC_H__
+
+#include <net/macsec.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_addr.h>
+#include "mlx5_ib.h"
+
+#ifdef CONFIG_MLX5_MACSEC
+struct mlx5_reserved_gids;
+
+int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr);
+void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr);
+int mlx5r_macsec_init_gids_and_devlist(struct mlx5_ib_dev *dev);
+void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev);
+void mlx5r_macsec_event_register(struct mlx5_ib_dev *dev);
+void mlx5r_macsec_event_unregister(struct mlx5_ib_dev *dev);
+#else
+static inline int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr) { return 0; }
+static inline void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr) {}
+static inline int mlx5r_macsec_init_gids_and_devlist(struct mlx5_ib_dev *dev) { return 0; }
+static inline void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev) {}
+static inline void mlx5r_macsec_event_register(struct mlx5_ib_dev *dev) {}
+static inline void mlx5r_macsec_event_unregister(struct mlx5_ib_dev *dev) {}
+#endif
+#endif /* __MLX5_MACSEC_H__ */
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index f0b394ed7452..aed5cdea50e6 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -46,6 +46,7 @@
#include <rdma/uverbs_ioctl.h>
#include <rdma/mlx5_user_ioctl_verbs.h>
#include <rdma/mlx5_user_ioctl_cmds.h>
+#include "macsec.h"
#define UVERBS_MODULE_NAME mlx5_ib
#include <rdma/uverbs_named_ioctl.h>
@@ -564,9 +565,9 @@ out:
return err;
}
-static int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num,
- unsigned int index, const union ib_gid *gid,
- const struct ib_gid_attr *attr)
+int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num,
+ unsigned int index, const union ib_gid *gid,
+ const struct ib_gid_attr *attr)
{
enum ib_gid_type gid_type;
u16 vlan_id = 0xffff;
@@ -607,6 +608,12 @@ static int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num,
static int mlx5_ib_add_gid(const struct ib_gid_attr *attr,
__always_unused void **context)
{
+ int ret;
+
+ ret = mlx5r_add_gid_macsec_operations(attr);
+ if (ret)
+ return ret;
+
return set_roce_addr(to_mdev(attr->device), attr->port_num,
attr->index, &attr->gid, attr);
}
@@ -614,8 +621,15 @@ static int mlx5_ib_add_gid(const struct ib_gid_attr *attr,
static int mlx5_ib_del_gid(const struct ib_gid_attr *attr,
__always_unused void **context)
{
- return set_roce_addr(to_mdev(attr->device), attr->port_num,
- attr->index, NULL, attr);
+ int ret;
+
+ ret = set_roce_addr(to_mdev(attr->device), attr->port_num,
+ attr->index, NULL, attr);
+ if (ret)
+ return ret;
+
+ mlx5r_del_gid_macsec_operations(attr);
+ return 0;
}
__be16 mlx5_get_roce_udp_sport_min(const struct mlx5_ib_dev *dev,
@@ -3644,13 +3658,13 @@ static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
mutex_destroy(&dev->cap_mask_mutex);
WARN_ON(!xa_empty(&dev->sig_mrs));
WARN_ON(!bitmap_empty(dev->dm.memic_alloc_pages, MLX5_MAX_MEMIC_PAGES));
+ mlx5r_macsec_dealloc_gids(dev);
}
static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
{
struct mlx5_core_dev *mdev = dev->mdev;
- int err;
- int i;
+ int err, i;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.local_dma_lkey = 0 /* not supported for now */;
@@ -3670,10 +3684,14 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
if (err)
return err;
- err = mlx5_ib_init_multiport_master(dev);
+ err = mlx5r_macsec_init_gids_and_devlist(dev);
if (err)
return err;
+ err = mlx5_ib_init_multiport_master(dev);
+ if (err)
+ goto err;
+
err = set_has_smi_cap(dev);
if (err)
goto err_mp;
@@ -3685,7 +3703,7 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
if (mlx5_use_mad_ifc(dev))
get_ext_port_caps(dev);
- dev->ib_dev.num_comp_vectors = mlx5_comp_vectors_count(mdev);
+ dev->ib_dev.num_comp_vectors = mlx5_comp_vectors_max(mdev);
mutex_init(&dev->cap_mask_mutex);
INIT_LIST_HEAD(&dev->qp_list);
@@ -3697,7 +3715,8 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
spin_lock_init(&dev->dm.lock);
dev->dm.dev = mdev;
return 0;
-
+err:
+ mlx5r_macsec_dealloc_gids(dev);
err_mp:
mlx5_ib_cleanup_multiport_master(dev);
return err;
@@ -4106,11 +4125,15 @@ static int mlx5_ib_stage_dev_notifier_init(struct mlx5_ib_dev *dev)
{
dev->mdev_events.notifier_call = mlx5_ib_event;
mlx5_notifier_register(dev->mdev, &dev->mdev_events);
+
+ mlx5r_macsec_event_register(dev);
+
return 0;
}
static void mlx5_ib_stage_dev_notifier_cleanup(struct mlx5_ib_dev *dev)
{
+ mlx5r_macsec_event_unregister(dev);
mlx5_notifier_unregister(dev->mdev, &dev->mdev_events);
}
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 9c33d960af3c..16713baf0d06 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -26,6 +26,7 @@
#include "srq.h"
#include "qp.h"
+#include "macsec.h"
#define mlx5_ib_dbg(_dev, format, arg...) \
dev_dbg(&(_dev)->ib_dev.dev, "%s:%d:(pid %d): " format, __func__, \
@@ -870,6 +871,9 @@ struct mlx5_ib_port {
struct mlx5_ib_dbg_cc_params *dbg_cc_params;
struct mlx5_roce roce;
struct mlx5_eswitch_rep *rep;
+#ifdef CONFIG_MLX5_MACSEC
+ struct mlx5_reserved_gids *reserved_gids;
+#endif
};
struct mlx5_ib_dbg_param {
@@ -1086,6 +1090,12 @@ struct mlx5_special_mkeys {
__be32 terminate_scatter_list_mkey;
};
+struct mlx5_macsec {
+ struct mutex lock; /* Protects mlx5_macsec internal contexts */
+ struct list_head macsec_devices_list;
+ struct notifier_block blocking_events_nb;
+};
+
struct mlx5_ib_dev {
struct ib_device ib_dev;
struct mlx5_core_dev *mdev;
@@ -1145,6 +1155,10 @@ struct mlx5_ib_dev {
u16 pkey_table_len;
u8 lag_ports;
struct mlx5_special_mkeys mkeys;
+
+#ifdef CONFIG_MLX5_MACSEC
+ struct mlx5_macsec macsec;
+#endif
};
static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -1648,4 +1662,7 @@ static inline bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev,
return access_flags & IB_ACCESS_RELAXED_ORDERING;
}
+int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num,
+ unsigned int index, const union ib_gid *gid,
+ const struct ib_gid_attr *attr);
#endif /* MLX5_IB_H */
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index a973905afd13..ed7d4b02f45a 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -64,9 +64,8 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
inode->i_uid = GLOBAL_ROOT_UID;
inode->i_gid = GLOBAL_ROOT_GID;
inode->i_blocks = 0;
- inode->i_atime = current_time(inode);
+ inode->i_atime = inode_set_ctime_current(inode);
inode->i_mtime = inode->i_atime;
- inode->i_ctime = inode->i_atime;
inode->i_private = data;
if (S_ISDIR(mode)) {
inode->i_op = &simple_dir_inode_operations;
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index c3b58a8389b9..7d7d3799199a 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3681,7 +3681,7 @@ static int amd_ir_set_affinity(struct irq_data *data,
* at the new destination. So, time to cleanup the previous
* vector allocation.
*/
- send_cleanup_vector(cfg);
+ vector_schedule_cleanup(cfg);
return IRQ_SET_MASK_OK_DONE;
}
diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index 261352a23271..2596466cd5a6 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -355,9 +355,9 @@ static struct pasid_state *mn_to_state(struct mmu_notifier *mn)
return container_of(mn, struct pasid_state, mn);
}
-static void mn_invalidate_range(struct mmu_notifier *mn,
- struct mm_struct *mm,
- unsigned long start, unsigned long end)
+static void mn_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start, unsigned long end)
{
struct pasid_state *pasid_state;
struct device_state *dev_state;
@@ -391,8 +391,8 @@ static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm)
}
static const struct mmu_notifier_ops iommu_mn = {
- .release = mn_release,
- .invalidate_range = mn_invalidate_range,
+ .release = mn_release,
+ .arch_invalidate_secondary_tlbs = mn_arch_invalidate_secondary_tlbs,
};
static void set_pri_tag_status(struct pasid_state *pasid_state,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index a5a63b1c947e..dbc812a0e57e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -186,9 +186,10 @@ static void arm_smmu_free_shared_cd(struct arm_smmu_ctx_desc *cd)
}
}
-static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
- struct mm_struct *mm,
- unsigned long start, unsigned long end)
+static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
{
struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
@@ -200,10 +201,20 @@ static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
* range. So do a simple translation here by calculating size correctly.
*/
size = end - start;
+ if (size == ULONG_MAX)
+ size = 0;
+
+ if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM)) {
+ if (!size)
+ arm_smmu_tlb_inv_asid(smmu_domain->smmu,
+ smmu_mn->cd->asid);
+ else
+ arm_smmu_tlb_inv_range_asid(start, size,
+ smmu_mn->cd->asid,
+ PAGE_SIZE, false,
+ smmu_domain);
+ }
- if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM))
- arm_smmu_tlb_inv_range_asid(start, size, smmu_mn->cd->asid,
- PAGE_SIZE, false, smmu_domain);
arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, start, size);
}
@@ -237,9 +248,9 @@ static void arm_smmu_mmu_notifier_free(struct mmu_notifier *mn)
}
static const struct mmu_notifier_ops arm_smmu_mmu_notifier_ops = {
- .invalidate_range = arm_smmu_mm_invalidate_range,
- .release = arm_smmu_mm_release,
- .free_notifier = arm_smmu_mmu_notifier_free,
+ .arch_invalidate_secondary_tlbs = arm_smmu_mm_arch_invalidate_secondary_tlbs,
+ .release = arm_smmu_mm_release,
+ .free_notifier = arm_smmu_mmu_notifier_free,
};
/* Allocate or get existing MMU notifier for this {domain, mm} pair */
diff --git a/drivers/iommu/hyperv-iommu.c b/drivers/iommu/hyperv-iommu.c
index 8302db7f783e..8a5c17b97310 100644
--- a/drivers/iommu/hyperv-iommu.c
+++ b/drivers/iommu/hyperv-iommu.c
@@ -51,7 +51,7 @@ static int hyperv_ir_set_affinity(struct irq_data *data,
if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
return ret;
- send_cleanup_vector(cfg);
+ vector_schedule_cleanup(cfg);
return 0;
}
@@ -257,7 +257,7 @@ static int hyperv_root_ir_set_affinity(struct irq_data *data,
if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
return ret;
- send_cleanup_vector(cfg);
+ vector_schedule_cleanup(cfg);
return 0;
}
diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c
index 08f56326e2f8..29b9e55dcf26 100644
--- a/drivers/iommu/intel/irq_remapping.c
+++ b/drivers/iommu/intel/irq_remapping.c
@@ -1176,7 +1176,7 @@ intel_ir_set_affinity(struct irq_data *data, const struct cpumask *mask,
* at the new destination. So, time to cleanup the previous
* vector allocation.
*/
- send_cleanup_vector(cfg);
+ vector_schedule_cleanup(cfg);
return IRQ_SET_MASK_OK_DONE;
}
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index e95b339e9cdc..8f6d68006ab6 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -219,9 +219,9 @@ static void intel_flush_svm_range(struct intel_svm *svm, unsigned long address,
}
/* Pages have been freed at this point */
-static void intel_invalidate_range(struct mmu_notifier *mn,
- struct mm_struct *mm,
- unsigned long start, unsigned long end)
+static void intel_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start, unsigned long end)
{
struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
@@ -256,7 +256,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
static const struct mmu_notifier_ops intel_mmuops = {
.release = intel_mm_release,
- .invalidate_range = intel_invalidate_range,
+ .arch_invalidate_secondary_tlbs = intel_arch_invalidate_secondary_tlbs,
};
static DEFINE_MUTEX(pasid_mutex);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 09e422da482f..4b9036c6d45b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -89,6 +89,7 @@ config ALPINE_MSI
config AL_FIC
bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
depends on OF
+ depends on HAS_IOMEM
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
help
diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c
index 6341c0167c4a..9745a119d0e6 100644
--- a/drivers/irqchip/irq-bcm6345-l1.c
+++ b/drivers/irqchip/irq-bcm6345-l1.c
@@ -60,7 +60,6 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/smp.h>
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index a62b96237b82..24ca1d656adc 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -20,7 +20,6 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/smp.h>
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index 091b0fe7e324..5559c943f03f 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c
index 3989d16f997b..a275a8071a25 100644
--- a/drivers/irqchip/irq-gic-pm.c
+++ b/drivers/irqchip/irq-gic-pm.c
@@ -4,7 +4,7 @@
*/
#include <linux/module.h>
#include <linux/clk.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_device.h>
diff --git a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
index 634263dfd7b5..8e87fc35f8aa 100644
--- a/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
@@ -9,8 +9,6 @@
#include <linux/acpi.h>
#include <linux/acpi_iort.h>
-#include <linux/of_device.h>
-#include <linux/of_address.h>
#include <linux/irq.h>
#include <linux/msi.h>
#include <linux/of.h>
diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c
index b70ce0d3c092..115bdcffab24 100644
--- a/drivers/irqchip/irq-i8259.c
+++ b/drivers/irqchip/irq-i8259.c
@@ -340,7 +340,7 @@ static void i8259_irq_dispatch(struct irq_desc *desc)
generic_handle_domain_irq(domain, hwirq);
}
-int __init i8259_of_init(struct device_node *node, struct device_node *parent)
+static int __init i8259_of_init(struct device_node *node, struct device_node *parent)
{
struct irq_domain *domain;
unsigned int parent_irq;
diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c
index 80aaea82468a..6d9a08238c9d 100644
--- a/drivers/irqchip/irq-imx-intmux.c
+++ b/drivers/irqchip/irq-imx-intmux.c
@@ -50,8 +50,9 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 96230a04ec23..bd9543314539 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -10,8 +10,9 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c
index 229039eda1b1..90d41c1407ac 100644
--- a/drivers/irqchip/irq-imx-mu-msi.c
+++ b/drivers/irqchip/irq-imx-mu-msi.c
@@ -339,8 +339,8 @@ static int __init imx_mu_of_init(struct device_node *dn,
msi_data->msiir_addr = res->start + msi_data->cfg->xTR;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENODEV;
+ if (irq < 0)
+ return irq;
platform_set_drvdata(pdev, msi_data);
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c
index ba9792e60329..a36396db4b08 100644
--- a/drivers/irqchip/irq-keystone.c
+++ b/drivers/irqchip/irq-keystone.c
@@ -15,7 +15,7 @@
#include <linux/irqdomain.h>
#include <linux/irqchip.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index 92d8aa28bdf5..1623cd779175 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -144,7 +144,7 @@ static int eiointc_router_init(unsigned int cpu)
int i, bit;
uint32_t data;
uint32_t node = cpu_to_eio_node(cpu);
- uint32_t index = eiointc_index(node);
+ int index = eiointc_index(node);
if (index < 0) {
pr_err("Error: invalid nodemap!\n");
diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c
index fc8bf1f5d41b..0bff728b25e3 100644
--- a/drivers/irqchip/irq-loongson-htvec.c
+++ b/drivers/irqchip/irq-loongson-htvec.c
@@ -15,7 +15,6 @@
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/syscore_ops.h>
/* Registers */
diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c
index 93a71f66efeb..63db8e2172e0 100644
--- a/drivers/irqchip/irq-loongson-pch-pic.c
+++ b/drivers/irqchip/irq-loongson-pch-pic.c
@@ -12,9 +12,9 @@
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/syscore_ops.h>
/* Registers */
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index f5ba3f9f8415..f31a262fe438 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -349,8 +349,7 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
+ msi_data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(msi_data->regs)) {
dev_err(&pdev->dev, "failed to initialize 'regs'\n");
return PTR_ERR(msi_data->regs);
diff --git a/drivers/irqchip/irq-madera.c b/drivers/irqchip/irq-madera.c
index 8b81271c823c..3eb1f8cdf674 100644
--- a/drivers/irqchip/irq-madera.c
+++ b/drivers/irqchip/irq-madera.c
@@ -10,12 +10,10 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/irqchip/irq-madera.h>
#include <linux/mfd/madera/core.h>
#include <linux/mfd/madera/pdata.h>
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 7da18ef95211..f88df39f4129 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -150,6 +150,10 @@ static const struct meson_gpio_irq_params s4_params = {
INIT_MESON_S4_COMMON_DATA(82)
};
+static const struct meson_gpio_irq_params c3_params = {
+ INIT_MESON_S4_COMMON_DATA(55)
+};
+
static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
@@ -160,6 +164,7 @@ static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
{ .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
{ .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params },
{ .compatible = "amlogic,meson-s4-gpio-intc", .data = &s4_params },
+ { .compatible = "amlogic,c3-gpio-intc", .data = &c3_params },
{ }
};
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 6d5ecc10a870..76253e864f23 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -557,7 +557,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
return gic_irq_domain_map(d, virq, hwirq);
}
-void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
+static void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
unsigned int nr_irqs)
{
}
diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c
index 4ecef6d83777..a48dbe91b036 100644
--- a/drivers/irqchip/irq-mvebu-sei.c
+++ b/drivers/irqchip/irq-mvebu-sei.c
@@ -377,8 +377,7 @@ static int mvebu_sei_probe(struct platform_device *pdev)
mutex_init(&sei->cp_msi_lock);
raw_spin_lock_init(&sei->mask_lock);
- sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sei->base = devm_ioremap_resource(sei->dev, sei->res);
+ sei->base = devm_platform_get_and_ioremap_resource(pdev, 0, &sei->res);
if (IS_ERR(sei->base))
return PTR_ERR(sei->base);
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index 17c2c7a07f10..4e4e874e09a8 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -57,8 +57,7 @@ static int __init orion_irq_init(struct device_node *np,
struct resource r;
/* count number of irq chips by valid reg addresses */
- while (of_address_to_resource(np, num_chips, &r) == 0)
- num_chips++;
+ num_chips = of_address_count(np);
orion_irq_domain = irq_domain_add_linear(np,
num_chips * ORION_IRQS_PER_CHIP,
diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c
index fa8d89b02ec0..0f64ecb9b1f4 100644
--- a/drivers/irqchip/irq-pruss-intc.c
+++ b/drivers/irqchip/irq-pruss-intc.c
@@ -17,7 +17,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
/*
@@ -565,8 +565,8 @@ static int pruss_intc_probe(struct platform_device *pdev)
continue;
irq = platform_get_irq_byname(pdev, irq_names[i]);
- if (irq <= 0) {
- ret = (irq == 0) ? -EINVAL : irq;
+ if (irq < 0) {
+ ret = irq;
goto fail_irq;
}
diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c
index d30614661eea..7124565234a5 100644
--- a/drivers/irqchip/irq-qcom-mpm.c
+++ b/drivers/irqchip/irq-qcom-mpm.c
@@ -14,7 +14,7 @@
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 26e4c17a7bf2..fa19585f3dee 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -17,7 +17,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c
index 819a12297b58..de71bb350d57 100644
--- a/drivers/irqchip/irq-st.c
+++ b/drivers/irqchip/irq-st.c
@@ -10,7 +10,7 @@
#include <dt-bindings/interrupt-controller/irq-st.h>
#include <linux/err.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index b5fa76ce5046..d8ba5fba7450 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -14,10 +14,11 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index 21d49791f855..e760b1278143 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -19,7 +19,6 @@
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
index 8a0e69298e83..680586354d12 100644
--- a/drivers/irqchip/irq-tb10x.c
+++ b/drivers/irqchip/irq-tb10x.c
@@ -13,7 +13,6 @@
#include <linux/irqchip.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/bitops.h>
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index 7133f9fa6fd9..b83f5cbab123 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -15,9 +15,9 @@
#include <linux/msi.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/soc/ti/ti_sci_inta_msi.h>
#include <linux/soc/ti/ti_sci_protocol.h>
diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
index 1186f1e431a3..c027cd9e4a69 100644
--- a/drivers/irqchip/irq-ti-sci-intr.c
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -12,9 +12,9 @@
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/soc/ti/ti_sci_protocol.h>
/**
diff --git a/drivers/irqchip/irq-uniphier-aidet.c b/drivers/irqchip/irq-uniphier-aidet.c
index 716b1bb88bf2..601f9343d5b3 100644
--- a/drivers/irqchip/irq-uniphier-aidet.c
+++ b/drivers/irqchip/irq-uniphier-aidet.c
@@ -12,7 +12,6 @@
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c
index ab12328be5ee..0c18d1f1e264 100644
--- a/drivers/irqchip/irq-xtensa-pic.c
+++ b/drivers/irqchip/irq-xtensa-pic.c
@@ -16,6 +16,7 @@
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/xtensa-pic.h>
#include <linux/of.h>
unsigned int cached_irq_mask;
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index 7899607fbee8..1eeb0d0156ce 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -10,7 +10,7 @@
#include <linux/acpi.h>
#include <linux/init.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
#include <linux/platform_device.h>
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index d96916cf6a41..a32c0d28d038 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/soc/qcom/irq.h>
#include <linux/spinlock.h>
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index c9bc5a91ec83..cc3261543a5e 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -406,15 +406,15 @@ static ssize_t interval_store(struct device *dev,
static DEVICE_ATTR_RW(interval);
-static ssize_t hw_control_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t offloaded_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
return sprintf(buf, "%d\n", trigger_data->hw_control);
}
-static DEVICE_ATTR_RO(hw_control);
+static DEVICE_ATTR_RO(offloaded);
static struct attribute *netdev_trig_attrs[] = {
&dev_attr_device_name.attr,
@@ -427,7 +427,7 @@ static struct attribute *netdev_trig_attrs[] = {
&dev_attr_rx.attr,
&dev_attr_tx.attr,
&dev_attr_interval.attr,
- &dev_attr_hw_control.attr,
+ &dev_attr_offloaded.attr,
NULL
};
ATTRIBUTE_GROUPS(netdev_trig);
@@ -564,15 +564,17 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
/* Check if hw control is active by default on the LED.
* Init already enabled mode in hw control.
*/
- if (supports_hw_control(led_cdev) &&
- !led_cdev->hw_control_get(led_cdev, &mode)) {
+ if (supports_hw_control(led_cdev)) {
dev = led_cdev->hw_control_get_device(led_cdev);
if (dev) {
const char *name = dev_name(dev);
set_device_name(trigger_data, name, strlen(name));
trigger_data->hw_control = true;
- trigger_data->mode = mode;
+
+ rc = led_cdev->hw_control_get(led_cdev, &mode);
+ if (!rc)
+ trigger_data->mode = mode;
}
}
@@ -593,6 +595,8 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev)
cancel_delayed_work_sync(&trigger_data->work);
+ led_set_brightness(led_cdev, LED_OFF);
+
dev_put(trigger_data->net_dev);
kfree(trigger_data);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index b0a22e99bade..2a8b081bce7d 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -15,6 +15,7 @@ if MD
config BLK_DEV_MD
tristate "RAID support"
select BLOCK_HOLDER_DEPRECATED if SYSFS
+ select BUFFER_HEAD
# BLOCK_LEGACY_AUTOLOAD requirement should be removed
# after relevant mdadm enhancements - to make "names=yes"
# the default - are widely available.
@@ -50,6 +51,16 @@ config MD_AUTODETECT
If unsure, say Y.
+config MD_BITMAP_FILE
+ bool "MD bitmap file support (deprecated)"
+ default y
+ help
+ If you say Y here, support for write intent bitmaps in files on an
+ external file system is enabled. This is an alternative to the internal
+ bitmaps near the MD superblock, and very problematic code that abuses
+ various kernel APIs and can only work with files on a file system not
+ actually sitting on the MD device.
+
config MD_LINEAR
tristate "Linear (append) mode (deprecated)"
depends on BLK_DEV_MD
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 1dc6227d353e..f2662c21a6df 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1160,7 +1160,6 @@ static int dm_crypt_integrity_io_alloc(struct dm_crypt_io *io, struct bio *bio)
tag_len = io->cc->on_disk_tag_size * (bio_sectors(bio) >> io->cc->sector_shift);
- bip->bip_iter.bi_size = tag_len;
bip->bip_iter.bi_sector = io->cc->start + io->sector;
ret = bio_integrity_add_page(bio, virt_to_page(io->integrity_metadata),
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index becdb689190e..5f9991765f27 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3723,7 +3723,6 @@ static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
if (!strcasecmp(argv[0], "idle") || !strcasecmp(argv[0], "frozen")) {
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(&mddev->sync_thread);
md_reap_sync_thread(mddev);
}
} else if (decipher_sync_action(mddev, mddev->recovery) != st_idle)
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 1ff712889a3b..6f9ff14971f9 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -139,29 +139,26 @@ static void md_bitmap_checkfree(struct bitmap_counts *bitmap, unsigned long page
*/
/* IO operations when bitmap is stored near all superblocks */
+
+/* choose a good rdev and read the page from there */
static int read_sb_page(struct mddev *mddev, loff_t offset,
- struct page *page,
- unsigned long index, int size)
+ struct page *page, unsigned long index, int size)
{
- /* choose a good rdev and read the page from there */
+ sector_t sector = mddev->bitmap_info.offset + offset +
+ index * (PAGE_SIZE / SECTOR_SIZE);
struct md_rdev *rdev;
- sector_t target;
rdev_for_each(rdev, mddev) {
- if (! test_bit(In_sync, &rdev->flags)
- || test_bit(Faulty, &rdev->flags)
- || test_bit(Bitmap_sync, &rdev->flags))
- continue;
+ u32 iosize = roundup(size, bdev_logical_block_size(rdev->bdev));
- target = offset + index * (PAGE_SIZE/512);
+ if (!test_bit(In_sync, &rdev->flags) ||
+ test_bit(Faulty, &rdev->flags) ||
+ test_bit(Bitmap_sync, &rdev->flags))
+ continue;
- if (sync_page_io(rdev, target,
- roundup(size, bdev_logical_block_size(rdev->bdev)),
- page, REQ_OP_READ, true)) {
- page->index = index;
+ if (sync_page_io(rdev, sector, iosize, page, REQ_OP_READ, true))
return 0;
- }
}
return -EIO;
}
@@ -225,18 +222,19 @@ static unsigned int bitmap_io_size(unsigned int io_size, unsigned int opt_size,
}
static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
- struct page *page)
+ unsigned long pg_index, struct page *page)
{
struct block_device *bdev;
struct mddev *mddev = bitmap->mddev;
struct bitmap_storage *store = &bitmap->storage;
loff_t sboff, offset = mddev->bitmap_info.offset;
- sector_t ps, doff;
+ sector_t ps = pg_index * PAGE_SIZE / SECTOR_SIZE;
unsigned int size = PAGE_SIZE;
unsigned int opt_size = PAGE_SIZE;
+ sector_t doff;
bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
- if (page->index == store->file_pages - 1) {
+ if (pg_index == store->file_pages - 1) {
unsigned int last_page_size = store->bytes & (PAGE_SIZE - 1);
if (last_page_size == 0)
@@ -245,7 +243,6 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
opt_size = optimal_io_size(bdev, last_page_size, size);
}
- ps = page->index * PAGE_SIZE / SECTOR_SIZE;
sboff = rdev->sb_start + offset;
doff = rdev->data_offset;
@@ -279,55 +276,41 @@ static int __write_sb_page(struct md_rdev *rdev, struct bitmap *bitmap,
return 0;
}
-static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
+static void write_sb_page(struct bitmap *bitmap, unsigned long pg_index,
+ struct page *page, bool wait)
{
- struct md_rdev *rdev;
struct mddev *mddev = bitmap->mddev;
- int ret;
do {
- rdev = NULL;
+ struct md_rdev *rdev = NULL;
+
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
- ret = __write_sb_page(rdev, bitmap, page);
- if (ret)
- return ret;
+ if (__write_sb_page(rdev, bitmap, pg_index, page) < 0) {
+ set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
+ return;
+ }
}
} while (wait && md_super_wait(mddev) < 0);
-
- return 0;
}
static void md_bitmap_file_kick(struct bitmap *bitmap);
-/*
- * write out a page to a file
- */
-static void write_page(struct bitmap *bitmap, struct page *page, int wait)
-{
- struct buffer_head *bh;
-
- if (bitmap->storage.file == NULL) {
- switch (write_sb_page(bitmap, page, wait)) {
- case -EINVAL:
- set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
- }
- } else {
-
- bh = page_buffers(page);
- while (bh && bh->b_blocknr) {
- atomic_inc(&bitmap->pending_writes);
- set_buffer_locked(bh);
- set_buffer_mapped(bh);
- submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
- bh = bh->b_this_page;
- }
+#ifdef CONFIG_MD_BITMAP_FILE
+static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
+{
+ struct buffer_head *bh = page_buffers(page);
- if (wait)
- wait_event(bitmap->write_wait,
- atomic_read(&bitmap->pending_writes)==0);
+ while (bh && bh->b_blocknr) {
+ atomic_inc(&bitmap->pending_writes);
+ set_buffer_locked(bh);
+ set_buffer_mapped(bh);
+ submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
+ bh = bh->b_this_page;
}
- if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
- md_bitmap_file_kick(bitmap);
+
+ if (wait)
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes) == 0);
}
static void end_bitmap_write(struct buffer_head *bh, int uptodate)
@@ -364,10 +347,8 @@ static void free_buffers(struct page *page)
* This usage is similar to how swap files are handled, and allows us
* to write to a file with no concerns of memory allocation failing.
*/
-static int read_page(struct file *file, unsigned long index,
- struct bitmap *bitmap,
- unsigned long count,
- struct page *page)
+static int read_file_page(struct file *file, unsigned long index,
+ struct bitmap *bitmap, unsigned long count, struct page *page)
{
int ret = 0;
struct inode *inode = file_inode(file);
@@ -415,7 +396,6 @@ static int read_page(struct file *file, unsigned long index,
blk_cur++;
bh = bh->b_this_page;
}
- page->index = index;
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
@@ -429,12 +409,46 @@ out:
ret);
return ret;
}
+#else /* CONFIG_MD_BITMAP_FILE */
+static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
+{
+}
+static int read_file_page(struct file *file, unsigned long index,
+ struct bitmap *bitmap, unsigned long count, struct page *page)
+{
+ return -EIO;
+}
+static void free_buffers(struct page *page)
+{
+ put_page(page);
+}
+#endif /* CONFIG_MD_BITMAP_FILE */
/*
* bitmap file superblock operations
*/
/*
+ * write out a page to a file
+ */
+static void filemap_write_page(struct bitmap *bitmap, unsigned long pg_index,
+ bool wait)
+{
+ struct bitmap_storage *store = &bitmap->storage;
+ struct page *page = store->filemap[pg_index];
+
+ if (mddev_is_clustered(bitmap->mddev)) {
+ pg_index += bitmap->cluster_slot *
+ DIV_ROUND_UP(store->bytes, PAGE_SIZE);
+ }
+
+ if (store->file)
+ write_file_page(bitmap, page, wait);
+ else
+ write_sb_page(bitmap, pg_index, page, wait);
+}
+
+/*
* md_bitmap_wait_writes() should be called before writing any bitmap
* blocks, to ensure previous writes, particularly from
* md_bitmap_daemon_work(), have completed.
@@ -488,7 +502,12 @@ void md_bitmap_update_sb(struct bitmap *bitmap)
sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
bitmap_info.space);
kunmap_atomic(sb);
- write_page(bitmap, bitmap->storage.sb_page, 1);
+
+ if (bitmap->storage.file)
+ write_file_page(bitmap, bitmap->storage.sb_page, 1);
+ else
+ write_sb_page(bitmap, bitmap->storage.sb_index,
+ bitmap->storage.sb_page, 1);
}
EXPORT_SYMBOL(md_bitmap_update_sb);
@@ -540,7 +559,7 @@ static int md_bitmap_new_disk_sb(struct bitmap *bitmap)
bitmap->storage.sb_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (bitmap->storage.sb_page == NULL)
return -ENOMEM;
- bitmap->storage.sb_page->index = 0;
+ bitmap->storage.sb_index = 0;
sb = kmap_atomic(bitmap->storage.sb_page);
@@ -601,7 +620,7 @@ static int md_bitmap_read_sb(struct bitmap *bitmap)
unsigned long sectors_reserved = 0;
int err = -EINVAL;
struct page *sb_page;
- loff_t offset = bitmap->mddev->bitmap_info.offset;
+ loff_t offset = 0;
if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
chunksize = 128 * 1024 * 1024;
@@ -628,7 +647,7 @@ re_read:
bm_blocks = ((bm_blocks+7) >> 3) + sizeof(bitmap_super_t);
/* to 4k blocks */
bm_blocks = DIV_ROUND_UP_SECTOR_T(bm_blocks, 4096);
- offset = bitmap->mddev->bitmap_info.offset + (bitmap->cluster_slot * (bm_blocks << 3));
+ offset = bitmap->cluster_slot * (bm_blocks << 3);
pr_debug("%s:%d bm slot: %d offset: %llu\n", __func__, __LINE__,
bitmap->cluster_slot, offset);
}
@@ -637,13 +656,11 @@ re_read:
loff_t isize = i_size_read(bitmap->storage.file->f_mapping->host);
int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize;
- err = read_page(bitmap->storage.file, 0,
+ err = read_file_page(bitmap->storage.file, 0,
bitmap, bytes, sb_page);
} else {
- err = read_sb_page(bitmap->mddev,
- offset,
- sb_page,
- 0, sizeof(bitmap_super_t));
+ err = read_sb_page(bitmap->mddev, offset, sb_page, 0,
+ sizeof(bitmap_super_t));
}
if (err)
return err;
@@ -819,7 +836,7 @@ static int md_bitmap_storage_alloc(struct bitmap_storage *store,
if (store->sb_page) {
store->filemap[0] = store->sb_page;
pnum = 1;
- store->sb_page->index = offset;
+ store->sb_index = offset;
}
for ( ; pnum < num_pages; pnum++) {
@@ -828,7 +845,6 @@ static int md_bitmap_storage_alloc(struct bitmap_storage *store,
store->file_pages = pnum;
return -ENOMEM;
}
- store->filemap[pnum]->index = pnum + offset;
}
store->file_pages = pnum;
@@ -847,14 +863,10 @@ static int md_bitmap_storage_alloc(struct bitmap_storage *store,
static void md_bitmap_file_unmap(struct bitmap_storage *store)
{
- struct page **map, *sb_page;
- int pages;
- struct file *file;
-
- file = store->file;
- map = store->filemap;
- pages = store->file_pages;
- sb_page = store->sb_page;
+ struct file *file = store->file;
+ struct page *sb_page = store->sb_page;
+ struct page **map = store->filemap;
+ int pages = store->file_pages;
while (pages--)
if (map[pages] != sb_page) /* 0 is sb_page, release it below */
@@ -879,21 +891,13 @@ static void md_bitmap_file_unmap(struct bitmap_storage *store)
*/
static void md_bitmap_file_kick(struct bitmap *bitmap)
{
- char *path, *ptr = NULL;
-
if (!test_and_set_bit(BITMAP_STALE, &bitmap->flags)) {
md_bitmap_update_sb(bitmap);
if (bitmap->storage.file) {
- path = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (path)
- ptr = file_path(bitmap->storage.file,
- path, PAGE_SIZE);
+ pr_warn("%s: kicking failed bitmap file %pD4 from array!\n",
+ bmname(bitmap), bitmap->storage.file);
- pr_warn("%s: kicking failed bitmap file %s from array!\n",
- bmname(bitmap), IS_ERR(ptr) ? "" : ptr);
-
- kfree(path);
} else
pr_warn("%s: disabling internal bitmap due to errors\n",
bmname(bitmap));
@@ -945,6 +949,7 @@ static void md_bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
void *kaddr;
unsigned long chunk = block >> bitmap->counts.chunkshift;
struct bitmap_storage *store = &bitmap->storage;
+ unsigned long index = file_page_index(store, chunk);
unsigned long node_offset = 0;
if (mddev_is_clustered(bitmap->mddev))
@@ -962,9 +967,9 @@ static void md_bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
else
set_bit_le(bit, kaddr);
kunmap_atomic(kaddr);
- pr_debug("set file bit %lu page %lu\n", bit, page->index);
+ pr_debug("set file bit %lu page %lu\n", bit, index);
/* record page number so it gets flushed to disk when unplug occurs */
- set_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_DIRTY);
+ set_page_attr(bitmap, index - node_offset, BITMAP_PAGE_DIRTY);
}
static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
@@ -974,6 +979,7 @@ static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
void *paddr;
unsigned long chunk = block >> bitmap->counts.chunkshift;
struct bitmap_storage *store = &bitmap->storage;
+ unsigned long index = file_page_index(store, chunk);
unsigned long node_offset = 0;
if (mddev_is_clustered(bitmap->mddev))
@@ -989,8 +995,8 @@ static void md_bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
else
clear_bit_le(bit, paddr);
kunmap_atomic(paddr);
- if (!test_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_NEEDWRITE)) {
- set_page_attr(bitmap, page->index - node_offset, BITMAP_PAGE_PENDING);
+ if (!test_page_attr(bitmap, index - node_offset, BITMAP_PAGE_NEEDWRITE)) {
+ set_page_attr(bitmap, index - node_offset, BITMAP_PAGE_PENDING);
bitmap->allclean = 0;
}
}
@@ -1042,7 +1048,7 @@ void md_bitmap_unplug(struct bitmap *bitmap)
"md bitmap_unplug");
}
clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
- write_page(bitmap, bitmap->storage.filemap[i], 0);
+ filemap_write_page(bitmap, i, false);
writing = 1;
}
}
@@ -1084,33 +1090,31 @@ void md_bitmap_unplug_async(struct bitmap *bitmap)
EXPORT_SYMBOL(md_bitmap_unplug_async);
static void md_bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed);
-/* * bitmap_init_from_disk -- called at bitmap_create time to initialize
- * the in-memory bitmap from the on-disk bitmap -- also, sets up the
- * memory mapping of the bitmap file
- * Special cases:
- * if there's no bitmap file, or if the bitmap file had been
- * previously kicked from the array, we mark all the bits as
- * 1's in order to cause a full resync.
+
+/*
+ * Initialize the in-memory bitmap from the on-disk bitmap and set up the memory
+ * mapping of the bitmap file.
+ *
+ * Special case: If there's no bitmap file, or if the bitmap file had been
+ * previously kicked from the array, we mark all the bits as 1's in order to
+ * cause a full resync.
*
* We ignore all bits for sectors that end earlier than 'start'.
- * This is used when reading an out-of-date bitmap...
+ * This is used when reading an out-of-date bitmap.
*/
static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{
- unsigned long i, chunks, index, oldindex, bit, node_offset = 0;
- struct page *page = NULL;
- unsigned long bit_cnt = 0;
- struct file *file;
- unsigned long offset;
- int outofdate;
- int ret = -ENOSPC;
- void *paddr;
+ bool outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
+ struct mddev *mddev = bitmap->mddev;
+ unsigned long chunks = bitmap->counts.chunks;
struct bitmap_storage *store = &bitmap->storage;
+ struct file *file = store->file;
+ unsigned long node_offset = 0;
+ unsigned long bit_cnt = 0;
+ unsigned long i;
+ int ret;
- chunks = bitmap->counts.chunks;
- file = store->file;
-
- if (!file && !bitmap->mddev->bitmap_info.offset) {
+ if (!file && !mddev->bitmap_info.offset) {
/* No permanent bitmap - fill with '1s'. */
store->filemap = NULL;
store->file_pages = 0;
@@ -1125,77 +1129,79 @@ static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
return 0;
}
- outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
- if (outofdate)
- pr_warn("%s: bitmap file is out of date, doing full recovery\n", bmname(bitmap));
-
if (file && i_size_read(file->f_mapping->host) < store->bytes) {
pr_warn("%s: bitmap file too short %lu < %lu\n",
bmname(bitmap),
(unsigned long) i_size_read(file->f_mapping->host),
store->bytes);
+ ret = -ENOSPC;
goto err;
}
- oldindex = ~0L;
- offset = 0;
- if (!bitmap->mddev->bitmap_info.external)
- offset = sizeof(bitmap_super_t);
-
- if (mddev_is_clustered(bitmap->mddev))
+ if (mddev_is_clustered(mddev))
node_offset = bitmap->cluster_slot * (DIV_ROUND_UP(store->bytes, PAGE_SIZE));
- for (i = 0; i < chunks; i++) {
- int b;
- index = file_page_index(&bitmap->storage, i);
- bit = file_page_offset(&bitmap->storage, i);
- if (index != oldindex) { /* this is a new page, read it in */
- int count;
- /* unmap the old page, we're done with it */
- if (index == store->file_pages-1)
- count = store->bytes - index * PAGE_SIZE;
- else
- count = PAGE_SIZE;
- page = store->filemap[index];
- if (file)
- ret = read_page(file, index, bitmap,
- count, page);
- else
- ret = read_sb_page(
- bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- page,
- index + node_offset, count);
+ for (i = 0; i < store->file_pages; i++) {
+ struct page *page = store->filemap[i];
+ int count;
- if (ret)
- goto err;
+ /* unmap the old page, we're done with it */
+ if (i == store->file_pages - 1)
+ count = store->bytes - i * PAGE_SIZE;
+ else
+ count = PAGE_SIZE;
- oldindex = index;
+ if (file)
+ ret = read_file_page(file, i, bitmap, count, page);
+ else
+ ret = read_sb_page(mddev, 0, page, i + node_offset,
+ count);
+ if (ret)
+ goto err;
+ }
- if (outofdate) {
- /*
- * if bitmap is out of date, dirty the
- * whole page and write it out
- */
- paddr = kmap_atomic(page);
- memset(paddr + offset, 0xff,
- PAGE_SIZE - offset);
- kunmap_atomic(paddr);
- write_page(bitmap, page, 1);
+ if (outofdate) {
+ pr_warn("%s: bitmap file is out of date, doing full recovery\n",
+ bmname(bitmap));
+ for (i = 0; i < store->file_pages; i++) {
+ struct page *page = store->filemap[i];
+ unsigned long offset = 0;
+ void *paddr;
+
+ if (i == 0 && !mddev->bitmap_info.external)
+ offset = sizeof(bitmap_super_t);
+
+ /*
+ * If the bitmap is out of date, dirty the whole page
+ * and write it out
+ */
+ paddr = kmap_atomic(page);
+ memset(paddr + offset, 0xff, PAGE_SIZE - offset);
+ kunmap_atomic(paddr);
+
+ filemap_write_page(bitmap, i, true);
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) {
ret = -EIO;
- if (test_bit(BITMAP_WRITE_ERROR,
- &bitmap->flags))
- goto err;
+ goto err;
}
}
+ }
+
+ for (i = 0; i < chunks; i++) {
+ struct page *page = filemap_get_page(&bitmap->storage, i);
+ unsigned long bit = file_page_offset(&bitmap->storage, i);
+ void *paddr;
+ bool was_set;
+
paddr = kmap_atomic(page);
if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
- b = test_bit(bit, paddr);
+ was_set = test_bit(bit, paddr);
else
- b = test_bit_le(bit, paddr);
+ was_set = test_bit_le(bit, paddr);
kunmap_atomic(paddr);
- if (b) {
+
+ if (was_set) {
/* if the disk bit is set, set the memory bit */
int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
>= start);
@@ -1204,7 +1210,6 @@ static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
needed);
bit_cnt++;
}
- offset = 0;
}
pr_debug("%s: bitmap initialized from disk: read %lu pages, set %lu of %lu bits\n",
@@ -1396,9 +1401,8 @@ void md_bitmap_daemon_work(struct mddev *mddev)
break;
if (bitmap->storage.filemap &&
test_and_clear_page_attr(bitmap, j,
- BITMAP_PAGE_NEEDWRITE)) {
- write_page(bitmap, bitmap->storage.filemap[j], 0);
- }
+ BITMAP_PAGE_NEEDWRITE))
+ filemap_write_page(bitmap, j, false);
}
done:
@@ -2542,6 +2546,10 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len)
if (backlog > COUNTER_MAX)
return -EINVAL;
+ rv = mddev_lock(mddev);
+ if (rv)
+ return rv;
+
/*
* Without write mostly device, it doesn't make sense to set
* backlog for max_write_behind.
@@ -2555,6 +2563,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len)
if (!has_write_mostly) {
pr_warn_ratelimited("%s: can't set backlog, no write mostly device available\n",
mdname(mddev));
+ mddev_unlock(mddev);
return -EINVAL;
}
@@ -2565,13 +2574,13 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len)
mddev_destroy_serial_pool(mddev, NULL, false);
} else if (backlog && !mddev->serial_info_pool) {
/* serial_info_pool is needed since backlog is not zero */
- struct md_rdev *rdev;
-
rdev_for_each(rdev, mddev)
mddev_create_serial_pool(mddev, rdev, false);
}
if (old_mwb != backlog)
md_bitmap_update_sb(mddev->bitmap);
+
+ mddev_unlock(mddev);
return len;
}
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index 8a3788c9bfef..bb9eb418780a 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -201,6 +201,7 @@ struct bitmap {
struct file *file; /* backing disk file */
struct page *sb_page; /* cached copy of the bitmap
* file superblock */
+ unsigned long sb_index;
struct page **filemap; /* list of cache pages for
* the file */
unsigned long *filemap_attr; /* attributes associated
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 3d9fd74233df..1e26eb223349 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -952,8 +952,8 @@ static int join(struct mddev *mddev, int nodes)
return 0;
err:
set_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
- md_unregister_thread(&cinfo->recovery_thread);
- md_unregister_thread(&cinfo->recv_thread);
+ md_unregister_thread(mddev, &cinfo->recovery_thread);
+ md_unregister_thread(mddev, &cinfo->recv_thread);
lockres_free(cinfo->message_lockres);
lockres_free(cinfo->token_lockres);
lockres_free(cinfo->ack_lockres);
@@ -1015,8 +1015,8 @@ static int leave(struct mddev *mddev)
resync_bitmap(mddev);
set_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state);
- md_unregister_thread(&cinfo->recovery_thread);
- md_unregister_thread(&cinfo->recv_thread);
+ md_unregister_thread(mddev, &cinfo->recovery_thread);
+ md_unregister_thread(mddev, &cinfo->recv_thread);
lockres_free(cinfo->message_lockres);
lockres_free(cinfo->token_lockres);
lockres_free(cinfo->ack_lockres);
diff --git a/drivers/md/md-faulty.c b/drivers/md/md-faulty.c
index 50ad818978a4..a039e8e20f55 100644
--- a/drivers/md/md-faulty.c
+++ b/drivers/md/md-faulty.c
@@ -204,6 +204,8 @@ static bool faulty_make_request(struct mddev *mddev, struct bio *bio)
failit = 1;
}
}
+
+ md_account_bio(mddev, &bio);
if (failit) {
struct bio *b = bio_alloc_clone(conf->rdev->bdev, bio, GFP_NOIO,
&mddev->bio_set);
diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c
index 4eb72b9dd933..71ac99646827 100644
--- a/drivers/md/md-linear.c
+++ b/drivers/md/md-linear.c
@@ -238,6 +238,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
bio = split;
}
+ md_account_bio(mddev, &bio);
bio_set_dev(bio, tmp_dev->rdev->bdev);
bio->bi_iter.bi_sector = bio->bi_iter.bi_sector -
start_sector + data_offset;
diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c
index 92c45be203d7..d22276870283 100644
--- a/drivers/md/md-multipath.c
+++ b/drivers/md/md-multipath.c
@@ -107,6 +107,7 @@ static bool multipath_make_request(struct mddev *mddev, struct bio * bio)
&& md_flush_request(mddev, bio))
return true;
+ md_account_bio(mddev, &bio);
mp_bh = mempool_alloc(&conf->pool, GFP_NOIO);
mp_bh->master_bio = bio;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 78be7811a89f..0fe7ab6e8ab9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -453,7 +453,6 @@ void mddev_suspend(struct mddev *mddev)
mddev->pers->prepare_suspend(mddev);
wait_event(mddev->sb_wait, percpu_ref_is_zero(&mddev->active_io));
- mddev->pers->quiesce(mddev, 1);
clear_bit_unlock(MD_ALLOW_SB_UPDATE, &mddev->flags);
wait_event(mddev->sb_wait, !test_bit(MD_UPDATING_SB, &mddev->flags));
@@ -465,14 +464,15 @@ EXPORT_SYMBOL_GPL(mddev_suspend);
void mddev_resume(struct mddev *mddev)
{
- /* entred the memalloc scope from mddev_suspend() */
- memalloc_noio_restore(mddev->noio_flag);
lockdep_assert_held(&mddev->reconfig_mutex);
if (--mddev->suspended)
return;
+
+ /* entred the memalloc scope from mddev_suspend() */
+ memalloc_noio_restore(mddev->noio_flag);
+
percpu_ref_resurrect(&mddev->active_io);
wake_up(&mddev->sb_wait);
- mddev->pers->quiesce(mddev, 0);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
@@ -643,6 +643,7 @@ void mddev_init(struct mddev *mddev)
{
mutex_init(&mddev->open_mutex);
mutex_init(&mddev->reconfig_mutex);
+ mutex_init(&mddev->sync_mutex);
mutex_init(&mddev->bitmap_info.mutex);
INIT_LIST_HEAD(&mddev->disks);
INIT_LIST_HEAD(&mddev->all_mddevs);
@@ -650,6 +651,7 @@ void mddev_init(struct mddev *mddev)
timer_setup(&mddev->safemode_timer, md_safemode_timeout, 0);
atomic_set(&mddev->active, 1);
atomic_set(&mddev->openers, 0);
+ atomic_set(&mddev->sync_seq, 0);
spin_lock_init(&mddev->lock);
atomic_set(&mddev->flush_pending, 0);
init_waitqueue_head(&mddev->sb_wait);
@@ -2304,7 +2306,7 @@ int md_integrity_register(struct mddev *mddev)
pr_debug("md: data integrity enabled on %s\n", mdname(mddev));
if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE) ||
(mddev->level != 1 && mddev->level != 10 &&
- bioset_integrity_create(&mddev->io_acct_set, BIO_POOL_SIZE))) {
+ bioset_integrity_create(&mddev->io_clone_set, BIO_POOL_SIZE))) {
/*
* No need to handle the failure of bioset_integrity_create,
* because the function is called by md_run() -> pers->run(),
@@ -4747,6 +4749,62 @@ action_show(struct mddev *mddev, char *page)
return sprintf(page, "%s\n", type);
}
+static void stop_sync_thread(struct mddev *mddev)
+{
+ if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ return;
+
+ if (mddev_lock(mddev))
+ return;
+
+ /*
+ * Check again in case MD_RECOVERY_RUNNING is cleared before lock is
+ * held.
+ */
+ if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
+ mddev_unlock(mddev);
+ return;
+ }
+
+ if (work_pending(&mddev->del_work))
+ flush_workqueue(md_misc_wq);
+
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ /*
+ * Thread might be blocked waiting for metadata update which will now
+ * never happen
+ */
+ md_wakeup_thread_directly(mddev->sync_thread);
+
+ mddev_unlock(mddev);
+}
+
+static void idle_sync_thread(struct mddev *mddev)
+{
+ int sync_seq = atomic_read(&mddev->sync_seq);
+
+ mutex_lock(&mddev->sync_mutex);
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+ stop_sync_thread(mddev);
+
+ wait_event(resync_wait, sync_seq != atomic_read(&mddev->sync_seq) ||
+ !test_bit(MD_RECOVERY_RUNNING, &mddev->recovery));
+
+ mutex_unlock(&mddev->sync_mutex);
+}
+
+static void frozen_sync_thread(struct mddev *mddev)
+{
+ mutex_lock(&mddev->sync_mutex);
+ set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+ stop_sync_thread(mddev);
+
+ wait_event(resync_wait, mddev->sync_thread == NULL &&
+ !test_bit(MD_RECOVERY_RUNNING, &mddev->recovery));
+
+ mutex_unlock(&mddev->sync_mutex);
+}
+
static ssize_t
action_store(struct mddev *mddev, const char *page, size_t len)
{
@@ -4754,35 +4812,11 @@ action_store(struct mddev *mddev, const char *page, size_t len)
return -EINVAL;
- if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
- if (cmd_match(page, "frozen"))
- set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
- else
- clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
- if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
- mddev_lock(mddev) == 0) {
- if (work_pending(&mddev->del_work))
- flush_workqueue(md_misc_wq);
- if (mddev->sync_thread) {
- sector_t save_rp = mddev->reshape_position;
-
- mddev_unlock(mddev);
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(&mddev->sync_thread);
- mddev_lock_nointr(mddev);
- /*
- * set RECOVERY_INTR again and restore reshape
- * position in case others changed them after
- * got lock, eg, reshape_position_store and
- * md_check_recovery.
- */
- mddev->reshape_position = save_rp;
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_reap_sync_thread(mddev);
- }
- mddev_unlock(mddev);
- }
- } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ if (cmd_match(page, "idle"))
+ idle_sync_thread(mddev);
+ else if (cmd_match(page, "frozen"))
+ frozen_sync_thread(mddev);
+ else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
else if (cmd_match(page, "resync"))
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
@@ -5842,6 +5876,13 @@ int md_run(struct mddev *mddev)
goto exit_bio_set;
}
+ if (!bioset_initialized(&mddev->io_clone_set)) {
+ err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
+ offsetof(struct md_io_clone, bio_clone), 0);
+ if (err)
+ goto exit_sync_set;
+ }
+
spin_lock(&pers_lock);
pers = find_pers(mddev->level, mddev->clevel);
if (!pers || !try_module_get(pers->owner)) {
@@ -6019,6 +6060,8 @@ bitmap_abort:
module_put(pers->owner);
md_bitmap_destroy(mddev);
abort:
+ bioset_exit(&mddev->io_clone_set);
+exit_sync_set:
bioset_exit(&mddev->sync_set);
exit_bio_set:
bioset_exit(&mddev->bio_set);
@@ -6176,7 +6219,6 @@ static void __md_stop_writes(struct mddev *mddev)
flush_workqueue(md_misc_wq);
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(&mddev->sync_thread);
md_reap_sync_thread(mddev);
}
@@ -6216,7 +6258,7 @@ static void mddev_detach(struct mddev *mddev)
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
}
- md_unregister_thread(&mddev->thread);
+ md_unregister_thread(mddev, &mddev->thread);
if (mddev->queue)
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
}
@@ -6243,6 +6285,7 @@ static void __md_stop(struct mddev *mddev)
percpu_ref_exit(&mddev->active_io);
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
+ bioset_exit(&mddev->io_clone_set);
}
void md_stop(struct mddev *mddev)
@@ -7012,6 +7055,15 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (mddev->bitmap || mddev->bitmap_info.file)
return -EEXIST; /* cannot add when bitmap is present */
+
+ if (!IS_ENABLED(CONFIG_MD_BITMAP_FILE)) {
+ pr_warn("%s: bitmap files not supported by this kernel\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ pr_warn("%s: using deprecated bitmap file support\n",
+ mdname(mddev));
+
f = fget(fd);
if (f == NULL) {
@@ -7940,9 +7992,10 @@ struct md_thread *md_register_thread(void (*run) (struct md_thread *),
}
EXPORT_SYMBOL(md_register_thread);
-void md_unregister_thread(struct md_thread __rcu **threadp)
+void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp)
{
- struct md_thread *thread = rcu_dereference_protected(*threadp, true);
+ struct md_thread *thread = rcu_dereference_protected(*threadp,
+ lockdep_is_held(&mddev->reconfig_mutex));
if (!thread)
return;
@@ -8601,62 +8654,44 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
}
EXPORT_SYMBOL_GPL(md_submit_discard_bio);
-int acct_bioset_init(struct mddev *mddev)
+static void md_end_clone_io(struct bio *bio)
{
- int err = 0;
-
- if (!bioset_initialized(&mddev->io_acct_set))
- err = bioset_init(&mddev->io_acct_set, BIO_POOL_SIZE,
- offsetof(struct md_io_acct, bio_clone), 0);
- return err;
-}
-EXPORT_SYMBOL_GPL(acct_bioset_init);
-
-void acct_bioset_exit(struct mddev *mddev)
-{
- bioset_exit(&mddev->io_acct_set);
-}
-EXPORT_SYMBOL_GPL(acct_bioset_exit);
-
-static void md_end_io_acct(struct bio *bio)
-{
- struct md_io_acct *md_io_acct = bio->bi_private;
- struct bio *orig_bio = md_io_acct->orig_bio;
- struct mddev *mddev = md_io_acct->mddev;
+ struct md_io_clone *md_io_clone = bio->bi_private;
+ struct bio *orig_bio = md_io_clone->orig_bio;
+ struct mddev *mddev = md_io_clone->mddev;
orig_bio->bi_status = bio->bi_status;
- bio_end_io_acct(orig_bio, md_io_acct->start_time);
+ if (md_io_clone->start_time)
+ bio_end_io_acct(orig_bio, md_io_clone->start_time);
+
bio_put(bio);
bio_endio(orig_bio);
-
percpu_ref_put(&mddev->active_io);
}
-/*
- * Used by personalities that don't already clone the bio and thus can't
- * easily add the timestamp to their extended bio structure.
- */
-void md_account_bio(struct mddev *mddev, struct bio **bio)
+static void md_clone_bio(struct mddev *mddev, struct bio **bio)
{
struct block_device *bdev = (*bio)->bi_bdev;
- struct md_io_acct *md_io_acct;
- struct bio *clone;
-
- if (!blk_queue_io_stat(bdev->bd_disk->queue))
- return;
+ struct md_io_clone *md_io_clone;
+ struct bio *clone =
+ bio_alloc_clone(bdev, *bio, GFP_NOIO, &mddev->io_clone_set);
+
+ md_io_clone = container_of(clone, struct md_io_clone, bio_clone);
+ md_io_clone->orig_bio = *bio;
+ md_io_clone->mddev = mddev;
+ if (blk_queue_io_stat(bdev->bd_disk->queue))
+ md_io_clone->start_time = bio_start_io_acct(*bio);
+
+ clone->bi_end_io = md_end_clone_io;
+ clone->bi_private = md_io_clone;
+ *bio = clone;
+}
+void md_account_bio(struct mddev *mddev, struct bio **bio)
+{
percpu_ref_get(&mddev->active_io);
-
- clone = bio_alloc_clone(bdev, *bio, GFP_NOIO, &mddev->io_acct_set);
- md_io_acct = container_of(clone, struct md_io_acct, bio_clone);
- md_io_acct->orig_bio = *bio;
- md_io_acct->start_time = bio_start_io_acct(*bio);
- md_io_acct->mddev = mddev;
-
- clone->bi_end_io = md_end_io_acct;
- clone->bi_private = md_io_acct;
- *bio = clone;
+ md_clone_bio(mddev, bio);
}
EXPORT_SYMBOL_GPL(md_account_bio);
@@ -9329,7 +9364,6 @@ void md_check_recovery(struct mddev *mddev)
* ->spare_active and clear saved_raid_disk
*/
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_unregister_thread(&mddev->sync_thread);
md_reap_sync_thread(mddev);
clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -9358,17 +9392,24 @@ void md_check_recovery(struct mddev *mddev)
if (mddev->sb_flags)
md_update_sb(mddev, 0);
- if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
- /* resync/recovery still happening */
- clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- goto unlock;
- }
- if (mddev->sync_thread) {
- md_unregister_thread(&mddev->sync_thread);
+ /*
+ * Never start a new sync thread if MD_RECOVERY_RUNNING is
+ * still set.
+ */
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
+ if (!test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
+ /* resync/recovery still happening */
+ clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ goto unlock;
+ }
+
+ if (WARN_ON_ONCE(!mddev->sync_thread))
+ goto unlock;
+
md_reap_sync_thread(mddev);
goto unlock;
}
+
/* Set RUNNING before clearing NEEDED to avoid
* any transients in the value of "sync_action".
*/
@@ -9445,7 +9486,10 @@ void md_reap_sync_thread(struct mddev *mddev)
sector_t old_dev_sectors = mddev->dev_sectors;
bool is_reshaped = false;
- /* sync_thread should be unregistered, collect result */
+ /* resync has finished, collect result */
+ md_unregister_thread(mddev, &mddev->sync_thread);
+ atomic_inc(&mddev->sync_seq);
+
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
mddev->degraded != mddev->raid_disks) {
@@ -9490,7 +9534,6 @@ void md_reap_sync_thread(struct mddev *mddev)
if (mddev_is_clustered(mddev) && is_reshaped
&& !test_bit(MD_CLOSING, &mddev->flags))
md_cluster_ops->update_size(mddev, old_dev_sectors);
- wake_up(&resync_wait);
/* flag recovery needed just to double check */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
sysfs_notify_dirent_safe(mddev->sysfs_completed);
@@ -9498,6 +9541,7 @@ void md_reap_sync_thread(struct mddev *mddev)
md_new_event();
if (mddev->event_work.func)
queue_work(md_misc_wq, &mddev->event_work);
+ wake_up(&resync_wait);
}
EXPORT_SYMBOL(md_reap_sync_thread);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1aef86bf3fc3..9bcb77bca963 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -510,7 +510,7 @@ struct mddev {
struct bio_set sync_set; /* for sync operations like
* metadata and bitmap writes
*/
- struct bio_set io_acct_set; /* for raid0 and raid5 io accounting */
+ struct bio_set io_clone_set;
/* Generic flush handling.
* The last to finish preflush schedules a worker to submit
@@ -535,6 +535,11 @@ struct mddev {
*/
struct list_head deleting;
+ /* Used to synchronize idle and frozen for action_store() */
+ struct mutex sync_mutex;
+ /* The sequence number for sync thread */
+ atomic_t sync_seq;
+
bool has_superblocks:1;
bool fail_last_dev:1;
bool serialize_policy:1;
@@ -731,7 +736,7 @@ struct md_thread {
void *private;
};
-struct md_io_acct {
+struct md_io_clone {
struct mddev *mddev;
struct bio *orig_bio;
unsigned long start_time;
@@ -756,7 +761,7 @@ extern struct md_thread *md_register_thread(
void (*run)(struct md_thread *thread),
struct mddev *mddev,
const char *name);
-extern void md_unregister_thread(struct md_thread __rcu **threadp);
+extern void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp);
extern void md_wakeup_thread(struct md_thread __rcu *thread);
extern void md_check_recovery(struct mddev *mddev);
extern void md_reap_sync_thread(struct mddev *mddev);
@@ -769,8 +774,6 @@ extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
extern void md_finish_reshape(struct mddev *mddev);
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size);
-int acct_bioset_init(struct mddev *mddev);
-void acct_bioset_exit(struct mddev *mddev);
void md_account_bio(struct mddev *mddev, struct bio **bio);
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index d1ac73fcd852..c50a7abda744 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -377,7 +377,6 @@ static void raid0_free(struct mddev *mddev, void *priv)
struct r0conf *conf = priv;
free_conf(mddev, conf);
- acct_bioset_exit(mddev);
}
static int raid0_run(struct mddev *mddev)
@@ -392,16 +391,11 @@ static int raid0_run(struct mddev *mddev)
if (md_check_no_bitmap(mddev))
return -EINVAL;
- if (acct_bioset_init(mddev)) {
- pr_err("md/raid0:%s: alloc acct bioset failed.\n", mdname(mddev));
- return -ENOMEM;
- }
-
/* if private is not null, we are here after takeover */
if (mddev->private == NULL) {
ret = create_strip_zones(mddev, &conf);
if (ret < 0)
- goto exit_acct_set;
+ return ret;
mddev->private = conf;
}
conf = mddev->private;
@@ -432,15 +426,9 @@ static int raid0_run(struct mddev *mddev)
ret = md_integrity_register(mddev);
if (ret)
- goto free;
+ free_conf(mddev, conf);
return ret;
-
-free:
- free_conf(mddev, conf);
-exit_acct_set:
- acct_bioset_exit(mddev);
- return ret;
}
/*
@@ -557,54 +545,20 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
bio_endio(bio);
}
-static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
+static void raid0_map_submit_bio(struct mddev *mddev, struct bio *bio)
{
struct r0conf *conf = mddev->private;
struct strip_zone *zone;
struct md_rdev *tmp_dev;
- sector_t bio_sector;
- sector_t sector;
- sector_t orig_sector;
- unsigned chunk_sects;
- unsigned sectors;
-
- if (unlikely(bio->bi_opf & REQ_PREFLUSH)
- && md_flush_request(mddev, bio))
- return true;
-
- if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
- raid0_handle_discard(mddev, bio);
- return true;
- }
-
- bio_sector = bio->bi_iter.bi_sector;
- sector = bio_sector;
- chunk_sects = mddev->chunk_sectors;
-
- sectors = chunk_sects -
- (likely(is_power_of_2(chunk_sects))
- ? (sector & (chunk_sects-1))
- : sector_div(sector, chunk_sects));
-
- /* Restore due to sector_div */
- sector = bio_sector;
-
- if (sectors < bio_sectors(bio)) {
- struct bio *split = bio_split(bio, sectors, GFP_NOIO,
- &mddev->bio_set);
- bio_chain(split, bio);
- submit_bio_noacct(bio);
- bio = split;
- }
+ sector_t bio_sector = bio->bi_iter.bi_sector;
+ sector_t sector = bio_sector;
- if (bio->bi_pool != &mddev->bio_set)
- md_account_bio(mddev, &bio);
+ md_account_bio(mddev, &bio);
- orig_sector = sector;
zone = find_zone(mddev->private, &sector);
switch (conf->layout) {
case RAID0_ORIG_LAYOUT:
- tmp_dev = map_sector(mddev, zone, orig_sector, &sector);
+ tmp_dev = map_sector(mddev, zone, bio_sector, &sector);
break;
case RAID0_ALT_MULTIZONE_LAYOUT:
tmp_dev = map_sector(mddev, zone, sector, &sector);
@@ -612,13 +566,13 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
default:
WARN(1, "md/raid0:%s: Invalid layout\n", mdname(mddev));
bio_io_error(bio);
- return true;
+ return;
}
if (unlikely(is_rdev_broken(tmp_dev))) {
bio_io_error(bio);
md_error(mddev, tmp_dev);
- return true;
+ return;
}
bio_set_dev(bio, tmp_dev->bdev);
@@ -630,6 +584,40 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
bio_sector);
mddev_check_write_zeroes(mddev, bio);
submit_bio_noacct(bio);
+}
+
+static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
+{
+ sector_t sector;
+ unsigned chunk_sects;
+ unsigned sectors;
+
+ if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+ && md_flush_request(mddev, bio))
+ return true;
+
+ if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
+ raid0_handle_discard(mddev, bio);
+ return true;
+ }
+
+ sector = bio->bi_iter.bi_sector;
+ chunk_sects = mddev->chunk_sectors;
+
+ sectors = chunk_sects -
+ (likely(is_power_of_2(chunk_sects))
+ ? (sector & (chunk_sects-1))
+ : sector_div(sector, chunk_sects));
+
+ if (sectors < bio_sectors(bio)) {
+ struct bio *split = bio_split(bio, sectors, GFP_NOIO,
+ &mddev->bio_set);
+ bio_chain(split, bio);
+ raid0_map_submit_bio(mddev, bio);
+ bio = split;
+ }
+
+ raid0_map_submit_bio(mddev, bio);
return true;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index dd25832eb045..4b30a1742162 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -304,8 +304,6 @@ static void call_bio_endio(struct r1bio *r1_bio)
if (!test_bit(R1BIO_Uptodate, &r1_bio->state))
bio->bi_status = BLK_STS_IOERR;
- if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
- bio_end_io_acct(bio, r1_bio->start_time);
bio_endio(bio);
}
@@ -313,6 +311,7 @@ static void raid_end_bio_io(struct r1bio *r1_bio)
{
struct bio *bio = r1_bio->master_bio;
struct r1conf *conf = r1_bio->mddev->private;
+ sector_t sector = r1_bio->sector;
/* if nobody has done the final endio yet, do it now */
if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
@@ -323,13 +322,13 @@ static void raid_end_bio_io(struct r1bio *r1_bio)
call_bio_endio(r1_bio);
}
+
+ free_r1bio(r1_bio);
/*
* Wake up any possible resync thread that waits for the device
* to go idle. All I/Os, even write-behind writes, are done.
*/
- allow_barrier(conf, r1_bio->sector);
-
- free_r1bio(r1_bio);
+ allow_barrier(conf, sector);
}
/*
@@ -791,11 +790,17 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
return best_disk;
}
+static void wake_up_barrier(struct r1conf *conf)
+{
+ if (wq_has_sleeper(&conf->wait_barrier))
+ wake_up(&conf->wait_barrier);
+}
+
static void flush_bio_list(struct r1conf *conf, struct bio *bio)
{
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
raid1_prepare_flush_writes(conf->mddev->bitmap);
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
while (bio) { /* submit pending writes */
struct bio *next = bio->bi_next;
@@ -972,7 +977,7 @@ static bool _wait_barrier(struct r1conf *conf, int idx, bool nowait)
* In case freeze_array() is waiting for
* get_unqueued_pending() == extra
*/
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
/* Wait for the barrier in same barrier unit bucket to drop. */
/* Return false when nowait flag is set */
@@ -1015,7 +1020,7 @@ static bool wait_read_barrier(struct r1conf *conf, sector_t sector_nr, bool nowa
* In case freeze_array() is waiting for
* get_unqueued_pending() == extra
*/
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
/* Wait for array to be unfrozen */
/* Return false when nowait flag is set */
@@ -1044,7 +1049,7 @@ static bool wait_barrier(struct r1conf *conf, sector_t sector_nr, bool nowait)
static void _allow_barrier(struct r1conf *conf, int idx)
{
atomic_dec(&conf->nr_pending[idx]);
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
}
static void allow_barrier(struct r1conf *conf, sector_t sector_nr)
@@ -1173,7 +1178,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
spin_unlock_irq(&conf->device_lock);
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
md_wakeup_thread(mddev->thread);
kfree(plug);
return;
@@ -1303,10 +1308,10 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
}
r1_bio->read_disk = rdisk;
-
- if (!r1bio_existed && blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
- r1_bio->start_time = bio_start_io_acct(bio);
-
+ if (!r1bio_existed) {
+ md_account_bio(mddev, &bio);
+ r1_bio->master_bio = bio;
+ }
read_bio = bio_alloc_clone(mirror->rdev->bdev, bio, gfp,
&mddev->bio_set);
@@ -1373,6 +1378,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
return;
}
+ retry_write:
r1_bio = alloc_r1bio(mddev, bio);
r1_bio->sectors = max_write_sectors;
@@ -1388,7 +1394,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
*/
disks = conf->raid_disks * 2;
- retry_write:
blocked_rdev = NULL;
rcu_read_lock();
max_sectors = r1_bio->sectors;
@@ -1468,7 +1473,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
for (j = 0; j < i; j++)
if (r1_bio->bios[j])
rdev_dec_pending(conf->mirrors[j].rdev, mddev);
- r1_bio->state = 0;
+ free_r1bio(r1_bio);
allow_barrier(conf, bio->bi_iter.bi_sector);
if (bio->bi_opf & REQ_NOWAIT) {
@@ -1500,8 +1505,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio->sectors = max_sectors;
}
- if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
- r1_bio->start_time = bio_start_io_acct(bio);
+ md_account_bio(mddev, &bio);
+ r1_bio->master_bio = bio;
atomic_set(&r1_bio->remaining, 1);
atomic_set(&r1_bio->behind_remaining, 0);
@@ -1518,8 +1523,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
* Not if there are too many, or cannot
* allocate memory, or a reader on WriteMostly
* is waiting for behind writes to flush */
- if (bitmap &&
- test_bit(WriteMostly, &rdev->flags) &&
+ if (bitmap && write_behind &&
(atomic_read(&bitmap->behind_writes)
< mddev->bitmap_info.max_write_behind) &&
!waitqueue_active(&bitmap->behind_wait)) {
@@ -1576,7 +1580,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio_write_done(r1_bio);
/* In case raid1d snuck in to freeze_array */
- wake_up(&conf->wait_barrier);
+ wake_up_barrier(conf);
}
static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
@@ -1766,7 +1770,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
{
struct r1conf *conf = mddev->private;
int err = -EEXIST;
- int mirror = 0;
+ int mirror = 0, repl_slot = -1;
struct raid1_info *p;
int first = 0;
int last = conf->raid_disks - 1;
@@ -1809,17 +1813,21 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
break;
}
if (test_bit(WantReplacement, &p->rdev->flags) &&
- p[conf->raid_disks].rdev == NULL) {
- /* Add this device as a replacement */
- clear_bit(In_sync, &rdev->flags);
- set_bit(Replacement, &rdev->flags);
- rdev->raid_disk = mirror;
- err = 0;
- conf->fullsync = 1;
- rcu_assign_pointer(p[conf->raid_disks].rdev, rdev);
- break;
- }
+ p[conf->raid_disks].rdev == NULL && repl_slot < 0)
+ repl_slot = mirror;
}
+
+ if (err && repl_slot >= 0) {
+ /* Add this device as a replacement */
+ p = conf->mirrors + repl_slot;
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Replacement, &rdev->flags);
+ rdev->raid_disk = repl_slot;
+ err = 0;
+ conf->fullsync = 1;
+ rcu_assign_pointer(p[conf->raid_disks].rdev, rdev);
+ }
+
print_conf(conf);
return err;
}
@@ -1829,6 +1837,10 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
struct r1conf *conf = mddev->private;
int err = 0;
int number = rdev->raid_disk;
+
+ if (unlikely(number >= conf->raid_disks))
+ goto abort;
+
struct raid1_info *p = conf->mirrors + number;
if (rdev != p->rdev)
@@ -2299,7 +2311,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
d++;
if (d == conf->raid_disks * 2)
d = 0;
- } while (!success && d != read_disk);
+ } while (d != read_disk);
if (!success) {
/* Cannot read from anywhere - mark it bad */
@@ -2498,6 +2510,7 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
struct mddev *mddev = conf->mddev;
struct bio *bio;
struct md_rdev *rdev;
+ sector_t sector;
clear_bit(R1BIO_ReadError, &r1_bio->state);
/* we got a read error. Maybe the drive is bad. Maybe just
@@ -2527,12 +2540,13 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
}
rdev_dec_pending(rdev, conf->mddev);
- allow_barrier(conf, r1_bio->sector);
+ sector = r1_bio->sector;
bio = r1_bio->master_bio;
/* Reuse the old r1_bio so that the IO_BLOCKED settings are preserved */
r1_bio->state = 0;
raid1_read_request(mddev, bio, r1_bio->sectors, r1_bio);
+ allow_barrier(conf, sector);
}
static void raid1d(struct md_thread *thread)
@@ -3144,7 +3158,7 @@ static int raid1_run(struct mddev *mddev)
* RAID1 needs at least one disk in active
*/
if (conf->raid_disks - mddev->degraded < 1) {
- md_unregister_thread(&conf->thread);
+ md_unregister_thread(mddev, &conf->thread);
ret = -EINVAL;
goto abort;
}
@@ -3171,7 +3185,7 @@ static int raid1_run(struct mddev *mddev)
ret = md_integrity_register(mddev);
if (ret) {
- md_unregister_thread(&mddev->thread);
+ md_unregister_thread(mddev, &mddev->thread);
goto abort;
}
return 0;
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index 468f189da7a0..14d4211a123a 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -157,7 +157,6 @@ struct r1bio {
sector_t sector;
int sectors;
unsigned long state;
- unsigned long start_time;
struct mddev *mddev;
/*
* original bio going to /dev/mdx
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5051149e27bb..023413120851 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -325,8 +325,6 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
bio->bi_status = BLK_STS_IOERR;
- if (r10_bio->start_time)
- bio_end_io_acct(bio, r10_bio->start_time);
bio_endio(bio);
/*
* Wake up any possible resync thread that waits for the device
@@ -1172,7 +1170,7 @@ static bool regular_request_wait(struct mddev *mddev, struct r10conf *conf,
}
static void raid10_read_request(struct mddev *mddev, struct bio *bio,
- struct r10bio *r10_bio)
+ struct r10bio *r10_bio, bool io_accounting)
{
struct r10conf *conf = mddev->private;
struct bio *read_bio;
@@ -1243,9 +1241,10 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
}
slot = r10_bio->read_slot;
- if (!r10_bio->start_time &&
- blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
- r10_bio->start_time = bio_start_io_acct(bio);
+ if (io_accounting) {
+ md_account_bio(mddev, &bio);
+ r10_bio->master_bio = bio;
+ }
read_bio = bio_alloc_clone(rdev->bdev, bio, gfp, &mddev->bio_set);
r10_bio->devs[slot].bio = read_bio;
@@ -1322,6 +1321,25 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
}
}
+static struct md_rdev *dereference_rdev_and_rrdev(struct raid10_info *mirror,
+ struct md_rdev **prrdev)
+{
+ struct md_rdev *rdev, *rrdev;
+
+ rrdev = rcu_dereference(mirror->replacement);
+ /*
+ * Read replacement first to prevent reading both rdev and
+ * replacement as NULL during replacement replace rdev.
+ */
+ smp_mb();
+ rdev = rcu_dereference(mirror->rdev);
+ if (rdev == rrdev)
+ rrdev = NULL;
+
+ *prrdev = rrdev;
+ return rdev;
+}
+
static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
{
int i;
@@ -1332,11 +1350,9 @@ retry_wait:
blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
- struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
- struct md_rdev *rrdev = rcu_dereference(
- conf->mirrors[i].replacement);
- if (rdev == rrdev)
- rrdev = NULL;
+ struct md_rdev *rdev, *rrdev;
+
+ rdev = dereference_rdev_and_rrdev(&conf->mirrors[i], &rrdev);
if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
atomic_inc(&rdev->nr_pending);
blocked_rdev = rdev;
@@ -1465,15 +1481,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
int d = r10_bio->devs[i].devnum;
struct md_rdev *rdev, *rrdev;
- rrdev = rcu_dereference(conf->mirrors[d].replacement);
- /*
- * Read replacement first to prevent reading both rdev and
- * replacement as NULL during replacement replace rdev.
- */
- smp_mb();
- rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev == rrdev)
- rrdev = NULL;
+ rdev = dereference_rdev_and_rrdev(&conf->mirrors[d], &rrdev);
if (rdev && (test_bit(Faulty, &rdev->flags)))
rdev = NULL;
if (rrdev && (test_bit(Faulty, &rrdev->flags)))
@@ -1543,8 +1551,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
r10_bio->master_bio = bio;
}
- if (blk_queue_io_stat(bio->bi_bdev->bd_disk->queue))
- r10_bio->start_time = bio_start_io_acct(bio);
+ md_account_bio(mddev, &bio);
+ r10_bio->master_bio = bio;
atomic_set(&r10_bio->remaining, 1);
md_bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0);
@@ -1571,12 +1579,11 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
r10_bio->sector = bio->bi_iter.bi_sector;
r10_bio->state = 0;
r10_bio->read_slot = -1;
- r10_bio->start_time = 0;
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
conf->geo.raid_disks);
if (bio_data_dir(bio) == READ)
- raid10_read_request(mddev, bio, r10_bio);
+ raid10_read_request(mddev, bio, r10_bio, true);
else
raid10_write_request(mddev, bio, r10_bio);
}
@@ -1780,10 +1787,9 @@ retry_discard:
*/
rcu_read_lock();
for (disk = 0; disk < geo->raid_disks; disk++) {
- struct md_rdev *rdev = rcu_dereference(conf->mirrors[disk].rdev);
- struct md_rdev *rrdev = rcu_dereference(
- conf->mirrors[disk].replacement);
+ struct md_rdev *rdev, *rrdev;
+ rdev = dereference_rdev_and_rrdev(&conf->mirrors[disk], &rrdev);
r10_bio->devs[disk].bio = NULL;
r10_bio->devs[disk].repl_bio = NULL;
@@ -2720,10 +2726,10 @@ static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10bio *r10_bio)
{
int sect = 0; /* Offset from r10_bio->sector */
- int sectors = r10_bio->sectors;
+ int sectors = r10_bio->sectors, slot = r10_bio->read_slot;
struct md_rdev *rdev;
int max_read_errors = atomic_read(&mddev->max_corr_read_errors);
- int d = r10_bio->devs[r10_bio->read_slot].devnum;
+ int d = r10_bio->devs[slot].devnum;
/* still own a reference to this rdev, so it cannot
* have been cleared recently.
@@ -2744,13 +2750,13 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
pr_notice("md/raid10:%s: %pg: Failing raid device\n",
mdname(mddev), rdev->bdev);
md_error(mddev, rdev);
- r10_bio->devs[r10_bio->read_slot].bio = IO_BLOCKED;
+ r10_bio->devs[slot].bio = IO_BLOCKED;
return;
}
while(sectors) {
int s = sectors;
- int sl = r10_bio->read_slot;
+ int sl = slot;
int success = 0;
int start;
@@ -2785,7 +2791,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
sl++;
if (sl == conf->copies)
sl = 0;
- } while (!success && sl != r10_bio->read_slot);
+ } while (sl != slot);
rcu_read_unlock();
if (!success) {
@@ -2793,16 +2799,16 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
* as bad on the first device to discourage future
* reads.
*/
- int dn = r10_bio->devs[r10_bio->read_slot].devnum;
+ int dn = r10_bio->devs[slot].devnum;
rdev = conf->mirrors[dn].rdev;
if (!rdev_set_badblocks(
rdev,
- r10_bio->devs[r10_bio->read_slot].addr
+ r10_bio->devs[slot].addr
+ sect,
s, 0)) {
md_error(mddev, rdev);
- r10_bio->devs[r10_bio->read_slot].bio
+ r10_bio->devs[slot].bio
= IO_BLOCKED;
}
break;
@@ -2811,7 +2817,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
start = sl;
/* write it back and re-read */
rcu_read_lock();
- while (sl != r10_bio->read_slot) {
+ while (sl != slot) {
if (sl==0)
sl = conf->copies;
sl--;
@@ -2845,7 +2851,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
rcu_read_lock();
}
sl = start;
- while (sl != r10_bio->read_slot) {
+ while (sl != slot) {
if (sl==0)
sl = conf->copies;
sl--;
@@ -2985,7 +2991,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
rdev_dec_pending(rdev, mddev);
r10_bio->state = 0;
- raid10_read_request(mddev, r10_bio->master_bio, r10_bio);
+ raid10_read_request(mddev, r10_bio->master_bio, r10_bio, false);
/*
* allow_barrier after re-submit to ensure no sync io
* can be issued while regular io pending.
@@ -4314,7 +4320,7 @@ static int raid10_run(struct mddev *mddev)
return 0;
out_free_conf:
- md_unregister_thread(&mddev->thread);
+ md_unregister_thread(mddev, &mddev->thread);
raid10_free_conf(conf);
mddev->private = NULL;
out:
@@ -4411,7 +4417,6 @@ static void *raid10_takeover_raid0(struct mddev *mddev, sector_t size, int devs)
rdev->new_raid_disk = rdev->raid_disk * 2;
rdev->sectors = size;
}
- WRITE_ONCE(conf->barrier, 1);
}
return conf;
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 63e48b11b552..2e75e88d0802 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -123,7 +123,6 @@ struct r10bio {
sector_t sector; /* virtual sector number */
int sectors;
unsigned long state;
- unsigned long start_time;
struct mddev *mddev;
/*
* original bio going to /dev/mdx
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
index 47ba7d9e81e1..518b7cfa78b9 100644
--- a/drivers/md/raid5-cache.c
+++ b/drivers/md/raid5-cache.c
@@ -1260,14 +1260,13 @@ static void r5l_log_flush_endio(struct bio *bio)
if (bio->bi_status)
md_error(log->rdev->mddev, log->rdev);
+ bio_uninit(bio);
spin_lock_irqsave(&log->io_list_lock, flags);
list_for_each_entry(io, &log->flushing_ios, log_sibling)
r5l_io_run_stripes(io);
list_splice_tail_init(&log->flushing_ios, &log->finished_ios);
spin_unlock_irqrestore(&log->io_list_lock, flags);
-
- bio_uninit(bio);
}
/*
@@ -3168,12 +3167,15 @@ void r5l_exit_log(struct r5conf *conf)
{
struct r5l_log *log = conf->log;
- /* Ensure disable_writeback_work wakes up and exits */
- wake_up(&conf->mddev->sb_wait);
- flush_work(&log->disable_writeback_work);
- md_unregister_thread(&log->reclaim_thread);
+ md_unregister_thread(conf->mddev, &log->reclaim_thread);
+ /*
+ * 'reconfig_mutex' is held by caller, set 'confg->log' to NULL to
+ * ensure disable_writeback_work wakes up and exits.
+ */
conf->log = NULL;
+ wake_up(&conf->mddev->sb_wait);
+ flush_work(&log->disable_writeback_work);
mempool_exit(&log->meta_pool);
bioset_exit(&log->bs);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 85b3004594e0..4cb9c608ee19 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5468,26 +5468,17 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf,
*/
static void raid5_align_endio(struct bio *bi)
{
- struct md_io_acct *md_io_acct = bi->bi_private;
- struct bio *raid_bi = md_io_acct->orig_bio;
- struct mddev *mddev;
- struct r5conf *conf;
- struct md_rdev *rdev;
+ struct bio *raid_bi = bi->bi_private;
+ struct md_rdev *rdev = (void *)raid_bi->bi_next;
+ struct mddev *mddev = rdev->mddev;
+ struct r5conf *conf = mddev->private;
blk_status_t error = bi->bi_status;
- unsigned long start_time = md_io_acct->start_time;
bio_put(bi);
-
- rdev = (void*)raid_bi->bi_next;
raid_bi->bi_next = NULL;
- mddev = rdev->mddev;
- conf = mddev->private;
-
rdev_dec_pending(rdev, conf->mddev);
if (!error) {
- if (blk_queue_io_stat(raid_bi->bi_bdev->bd_disk->queue))
- bio_end_io_acct(raid_bi, start_time);
bio_endio(raid_bi);
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_quiescent);
@@ -5506,7 +5497,6 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
struct md_rdev *rdev;
sector_t sector, end_sector, first_bad;
int bad_sectors, dd_idx;
- struct md_io_acct *md_io_acct;
bool did_inc;
if (!in_chunk_boundary(mddev, raid_bio)) {
@@ -5543,16 +5533,13 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
return 0;
}
- align_bio = bio_alloc_clone(rdev->bdev, raid_bio, GFP_NOIO,
- &mddev->io_acct_set);
- md_io_acct = container_of(align_bio, struct md_io_acct, bio_clone);
+ md_account_bio(mddev, &raid_bio);
raid_bio->bi_next = (void *)rdev;
- if (blk_queue_io_stat(raid_bio->bi_bdev->bd_disk->queue))
- md_io_acct->start_time = bio_start_io_acct(raid_bio);
- md_io_acct->orig_bio = raid_bio;
+ align_bio = bio_alloc_clone(rdev->bdev, raid_bio, GFP_NOIO,
+ &mddev->bio_set);
align_bio->bi_end_io = raid5_align_endio;
- align_bio->bi_private = md_io_acct;
+ align_bio->bi_private = raid_bio;
align_bio->bi_iter.bi_sector = sector;
/* No reshape active, so we can trust rdev->data_offset */
@@ -7787,19 +7774,12 @@ static int raid5_run(struct mddev *mddev)
struct md_rdev *rdev;
struct md_rdev *journal_dev = NULL;
sector_t reshape_offset = 0;
- int i, ret = 0;
+ int i;
long long min_offset_diff = 0;
int first = 1;
- if (acct_bioset_init(mddev)) {
- pr_err("md/raid456:%s: alloc acct bioset failed.\n", mdname(mddev));
+ if (mddev_init_writes_pending(mddev) < 0)
return -ENOMEM;
- }
-
- if (mddev_init_writes_pending(mddev) < 0) {
- ret = -ENOMEM;
- goto exit_acct_set;
- }
if (mddev->recovery_cp != MaxSector)
pr_notice("md/raid:%s: not clean -- starting background reconstruction\n",
@@ -7830,8 +7810,7 @@ static int raid5_run(struct mddev *mddev)
(mddev->bitmap_info.offset || mddev->bitmap_info.file)) {
pr_notice("md/raid:%s: array cannot have both journal and bitmap\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
if (mddev->reshape_position != MaxSector) {
@@ -7856,15 +7835,13 @@ static int raid5_run(struct mddev *mddev)
if (journal_dev) {
pr_warn("md/raid:%s: don't support reshape with journal - aborting.\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
if (mddev->new_level != mddev->level) {
pr_warn("md/raid:%s: unsupported reshape required - aborting.\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
old_disks = mddev->raid_disks - mddev->delta_disks;
/* reshape_position must be on a new-stripe boundary, and one
@@ -7880,8 +7857,7 @@ static int raid5_run(struct mddev *mddev)
if (sector_div(here_new, chunk_sectors * new_data_disks)) {
pr_warn("md/raid:%s: reshape_position not on a stripe boundary\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
reshape_offset = here_new * chunk_sectors;
/* here_new is the stripe we will write to */
@@ -7903,8 +7879,7 @@ static int raid5_run(struct mddev *mddev)
else if (mddev->ro == 0) {
pr_warn("md/raid:%s: in-place reshape must be started in read-only mode - aborting\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
} else if (mddev->reshape_backwards
? (here_new * chunk_sectors + min_offset_diff <=
@@ -7914,8 +7889,7 @@ static int raid5_run(struct mddev *mddev)
/* Reading from the same stripe as writing to - bad */
pr_warn("md/raid:%s: reshape_position too early for auto-recovery - aborting.\n",
mdname(mddev));
- ret = -EINVAL;
- goto exit_acct_set;
+ return -EINVAL;
}
pr_debug("md/raid:%s: reshape will continue\n", mdname(mddev));
/* OK, we should be able to continue; */
@@ -7939,10 +7913,8 @@ static int raid5_run(struct mddev *mddev)
else
conf = mddev->private;
- if (IS_ERR(conf)) {
- ret = PTR_ERR(conf);
- goto exit_acct_set;
- }
+ if (IS_ERR(conf))
+ return PTR_ERR(conf);
if (test_bit(MD_HAS_JOURNAL, &mddev->flags)) {
if (!journal_dev) {
@@ -8135,15 +8107,12 @@ static int raid5_run(struct mddev *mddev)
return 0;
abort:
- md_unregister_thread(&mddev->thread);
+ md_unregister_thread(mddev, &mddev->thread);
print_raid5_conf(conf);
free_conf(conf);
mddev->private = NULL;
pr_warn("md/raid:%s: failed to run raid set.\n", mdname(mddev));
- ret = -EIO;
-exit_acct_set:
- acct_bioset_exit(mddev);
- return ret;
+ return -EIO;
}
static void raid5_free(struct mddev *mddev, void *priv)
@@ -8151,7 +8120,6 @@ static void raid5_free(struct mddev *mddev, void *priv)
struct r5conf *conf = priv;
free_conf(conf);
- acct_bioset_exit(mddev);
mddev->to_remove = &raid5_attrs_group;
}
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
index 9ff439a50f53..315e97a2450e 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
@@ -821,6 +821,8 @@ static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
return -EINVAL;
if (*nplanes) {
+ if (*nplanes != q_data->fmt->num_planes)
+ return -EINVAL;
for (i = 0; i < *nplanes; i++)
if (sizes[i] < q_data->sizeimage[i])
return -EINVAL;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6f5b259a6d6a..85be64579fc9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -237,6 +237,29 @@ config MFD_CROS_EC_DEV
To compile this driver as a module, choose M here: the module will be
called cros-ec-dev.
+config MFD_CS42L43
+ tristate
+ select MFD_CORE
+ select REGMAP
+
+config MFD_CS42L43_I2C
+ tristate "Cirrus Logic CS42L43 (I2C)"
+ depends on I2C
+ select REGMAP_I2C
+ select MFD_CS42L43
+ help
+ Select this to support the Cirrus Logic CS42L43 PC CODEC with
+ headphone and class D speaker drivers over I2C.
+
+config MFD_CS42L43_SDW
+ tristate "Cirrus Logic CS42L43 (SoundWire)"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+ select MFD_CS42L43
+ help
+ Select this to support the Cirrus Logic CS42L43 PC CODEC with
+ headphone and class D speaker drivers over SoundWire.
+
config MFD_MADERA
tristate "Cirrus Logic Madera codecs"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f3d1f1dc73b5..c66f07edcd0e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,9 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
+obj-$(CONFIG_MFD_CS42L43) += cs42l43.o
+obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o
+obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o
obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o
diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c
new file mode 100644
index 000000000000..4922211680c9
--- /dev/null
+++ b/drivers/mfd/cs42l43-i2c.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS42L43 I2C driver
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+
+#include "cs42l43.h"
+
+static const struct regmap_config cs42l43_i2c_regmap = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+
+ .max_register = CS42L43_MCU_RAM_MAX,
+ .readable_reg = cs42l43_readable_register,
+ .volatile_reg = cs42l43_volatile_register,
+ .precious_reg = cs42l43_precious_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs42l43_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default),
+};
+
+static int cs42l43_i2c_probe(struct i2c_client *i2c)
+{
+ struct cs42l43 *cs42l43;
+ int ret;
+
+ cs42l43 = devm_kzalloc(&i2c->dev, sizeof(*cs42l43), GFP_KERNEL);
+ if (!cs42l43)
+ return -ENOMEM;
+
+ cs42l43->dev = &i2c->dev;
+ cs42l43->irq = i2c->irq;
+ /* A device on an I2C is always attached by definition. */
+ cs42l43->attached = true;
+
+ cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap);
+ if (IS_ERR(cs42l43->regmap)) {
+ ret = PTR_ERR(cs42l43->regmap);
+ dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ return cs42l43_dev_probe(cs42l43);
+}
+
+static void cs42l43_i2c_remove(struct i2c_client *i2c)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev);
+
+ cs42l43_dev_remove(cs42l43);
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id cs42l43_of_match[] = {
+ { .compatible = "cirrus,cs42l43", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cs42l43_of_match);
+#endif
+
+#if IS_ENABLED(CONFIG_ACPI)
+static const struct acpi_device_id cs42l43_acpi_match[] = {
+ { "CSC4243", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
+#endif
+
+static struct i2c_driver cs42l43_i2c_driver = {
+ .driver = {
+ .name = "cs42l43",
+ .pm = pm_ptr(&cs42l43_pm_ops),
+ .of_match_table = of_match_ptr(cs42l43_of_match),
+ .acpi_match_table = ACPI_PTR(cs42l43_acpi_match),
+ },
+
+ .probe = cs42l43_i2c_probe,
+ .remove = cs42l43_i2c_remove,
+};
+module_i2c_driver(cs42l43_i2c_driver);
+
+MODULE_IMPORT_NS(MFD_CS42L43);
+
+MODULE_DESCRIPTION("CS42L43 I2C Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c
new file mode 100644
index 000000000000..7392b3d2e6b9
--- /dev/null
+++ b/drivers/mfd/cs42l43-sdw.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS42L43 SoundWire driver
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+
+#include "cs42l43.h"
+
+enum cs42l43_sdw_ports {
+ CS42L43_DMIC_DEC_ASP_PORT = 1,
+ CS42L43_SPK_TX_PORT,
+ CS42L43_SPDIF_HP_PORT,
+ CS42L43_SPK_RX_PORT,
+ CS42L43_ASP_PORT,
+};
+
+static const struct regmap_config cs42l43_sdw_regmap = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+
+ .max_register = CS42L43_MCU_RAM_MAX,
+ .readable_reg = cs42l43_readable_register,
+ .volatile_reg = cs42l43_volatile_register,
+ .precious_reg = cs42l43_precious_register,
+
+ .cache_type = REGCACHE_MAPLE,
+ .reg_defaults = cs42l43_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default),
+};
+
+static int cs42l43_read_prop(struct sdw_slave *sdw)
+{
+ struct sdw_slave_prop *prop = &sdw->prop;
+ struct device *dev = &sdw->dev;
+ struct sdw_dpn_prop *dpn;
+ unsigned long addr;
+ int nval;
+ int i;
+ u32 bit;
+
+ prop->use_domain_irq = true;
+ prop->paging_support = true;
+ prop->wake_capable = true;
+ prop->source_ports = BIT(CS42L43_DMIC_DEC_ASP_PORT) | BIT(CS42L43_SPK_TX_PORT);
+ prop->sink_ports = BIT(CS42L43_SPDIF_HP_PORT) |
+ BIT(CS42L43_SPK_RX_PORT) | BIT(CS42L43_ASP_PORT);
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
+ SDW_SCP_INT1_IMPL_DEF;
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->src_dpn_prop),
+ GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].max_ch = 2;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].max_word = 24;
+ i++;
+ }
+ /*
+ * All ports are 2 channels max, except the first one,
+ * CS42L43_DMIC_DEC_ASP_PORT.
+ */
+ dpn[CS42L43_DMIC_DEC_ASP_PORT].max_ch = 4;
+
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->sink_dpn_prop),
+ GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].max_ch = 2;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].max_word = 24;
+ i++;
+ }
+
+ return 0;
+}
+
+static int cs42l43_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
+
+ switch (status) {
+ case SDW_SLAVE_ATTACHED:
+ dev_dbg(cs42l43->dev, "Device attach\n");
+
+ sdw_write_no_pm(sdw, CS42L43_GEN_INT_MASK_1,
+ CS42L43_INT_STAT_GEN1_MASK);
+
+ cs42l43->attached = true;
+
+ complete(&cs42l43->device_attach);
+ break;
+ case SDW_SLAVE_UNATTACHED:
+ dev_dbg(cs42l43->dev, "Device detach\n");
+
+ cs42l43->attached = false;
+
+ reinit_completion(&cs42l43->device_attach);
+ complete(&cs42l43->device_detach);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l43_sdw_interrupt(struct sdw_slave *sdw,
+ struct sdw_slave_intr_status *status)
+{
+ /*
+ * The IRQ itself was handled through the regmap_irq handler, this is
+ * just clearing up the additional Cirrus SoundWire registers that are
+ * not covered by the SoundWire framework or the IRQ handler itself.
+ * There is only a single bit in GEN_INT_STAT_1 and it doesn't clear if
+ * IRQs are still pending so doing a read/write here after handling the
+ * IRQ is fine.
+ */
+ sdw_read_no_pm(sdw, CS42L43_GEN_INT_STAT_1);
+ sdw_write_no_pm(sdw, CS42L43_GEN_INT_STAT_1, CS42L43_INT_STAT_GEN1_MASK);
+
+ return 0;
+}
+
+static int cs42l43_sdw_bus_config(struct sdw_slave *sdw,
+ struct sdw_bus_params *params)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
+ int ret = 0;
+
+ mutex_lock(&cs42l43->pll_lock);
+
+ if (cs42l43->sdw_freq != params->curr_dr_freq / 2) {
+ if (cs42l43->sdw_pll_active) {
+ dev_err(cs42l43->dev,
+ "PLL active can't change SoundWire bus clock\n");
+ ret = -EBUSY;
+ } else {
+ cs42l43->sdw_freq = params->curr_dr_freq / 2;
+ }
+ }
+
+ mutex_unlock(&cs42l43->pll_lock);
+
+ return ret;
+}
+
+static const struct sdw_slave_ops cs42l43_sdw_ops = {
+ .read_prop = cs42l43_read_prop,
+ .update_status = cs42l43_sdw_update_status,
+ .interrupt_callback = cs42l43_sdw_interrupt,
+ .bus_config = cs42l43_sdw_bus_config,
+};
+
+static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)
+{
+ struct cs42l43 *cs42l43;
+ struct device *dev = &sdw->dev;
+ int ret;
+
+ cs42l43 = devm_kzalloc(dev, sizeof(*cs42l43), GFP_KERNEL);
+ if (!cs42l43)
+ return -ENOMEM;
+
+ cs42l43->dev = dev;
+ cs42l43->sdw = sdw;
+
+ cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap);
+ if (IS_ERR(cs42l43->regmap)) {
+ ret = PTR_ERR(cs42l43->regmap);
+ dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ return cs42l43_dev_probe(cs42l43);
+}
+
+static int cs42l43_sdw_remove(struct sdw_slave *sdw)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
+
+ cs42l43_dev_remove(cs42l43);
+
+ return 0;
+}
+
+static const struct sdw_device_id cs42l43_sdw_id[] = {
+ SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
+ {}
+};
+MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
+
+static struct sdw_driver cs42l43_sdw_driver = {
+ .driver = {
+ .name = "cs42l43",
+ .pm = pm_ptr(&cs42l43_pm_ops),
+ },
+
+ .probe = cs42l43_sdw_probe,
+ .remove = cs42l43_sdw_remove,
+ .id_table = cs42l43_sdw_id,
+ .ops = &cs42l43_sdw_ops,
+};
+module_sdw_driver(cs42l43_sdw_driver);
+
+MODULE_IMPORT_NS(MFD_CS42L43);
+
+MODULE_DESCRIPTION("CS42L43 SoundWire Driver");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c
new file mode 100644
index 000000000000..37b23e9bae82
--- /dev/null
+++ b/drivers/mfd/cs42l43.c
@@ -0,0 +1,1188 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS42L43 core driver
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/build_bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw.h>
+
+#include "cs42l43.h"
+
+#define CS42L43_RESET_DELAY 20
+
+#define CS42L43_SDW_ATTACH_TIMEOUT 500
+#define CS42L43_SDW_DETACH_TIMEOUT 100
+
+#define CS42L43_MCU_BOOT_STAGE1 1
+#define CS42L43_MCU_BOOT_STAGE2 2
+#define CS42L43_MCU_BOOT_STAGE3 3
+#define CS42L43_MCU_BOOT_STAGE4 4
+#define CS42L43_MCU_POLL 5000
+#define CS42L43_MCU_CMD_TIMEOUT 20000
+#define CS42L43_MCU_UPDATE_FORMAT 3
+#define CS42L43_MCU_UPDATE_OFFSET 0x100000
+#define CS42L43_MCU_UPDATE_TIMEOUT 500000
+#define CS42L43_MCU_UPDATE_RETRIES 5
+
+#define CS42L43_MCU_SUPPORTED_REV 0x2105
+#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200
+#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001
+
+#define CS42L43_VDDP_DELAY 50
+#define CS42L43_VDDD_DELAY 1000
+
+#define CS42L43_AUTOSUSPEND_TIME 250
+
+struct cs42l43_patch_header {
+ __le16 version;
+ __le16 size;
+ u8 reserved;
+ u8 secure;
+ __le16 bss_size;
+ __le32 apply_addr;
+ __le32 checksum;
+ __le32 sha;
+ __le16 swrev;
+ __le16 patchid;
+ __le16 ipxid;
+ __le16 romver;
+ __le32 load_addr;
+} __packed;
+
+static const struct reg_sequence cs42l43_reva_patch[] = {
+ { 0x4000, 0x00000055 },
+ { 0x4000, 0x000000AA },
+ { 0x10084, 0x00000000 },
+ { 0x1741C, 0x00CD2000 },
+ { 0x1718C, 0x00000003 },
+ { 0x4000, 0x00000000 },
+ { CS42L43_CCM_BLK_CLK_CONTROL, 0x00000002 },
+ { CS42L43_HPPATHVOL, 0x011B011B },
+ { CS42L43_OSC_DIV_SEL, 0x00000001 },
+ { CS42L43_DACCNFG2, 0x00000005 },
+ { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 },
+ { CS42L43_RELID, 0x0000000F },
+};
+
+const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
+ { CS42L43_DRV_CTRL1, 0x000186C0 },
+ { CS42L43_DRV_CTRL3, 0x286DB018 },
+ { CS42L43_DRV_CTRL4, 0x000006D8 },
+ { CS42L43_DRV_CTRL_5, 0x136C00C0 },
+ { CS42L43_GPIO_CTRL1, 0x00000707 },
+ { CS42L43_GPIO_CTRL2, 0x00000000 },
+ { CS42L43_GPIO_FN_SEL, 0x00000000 },
+ { CS42L43_MCLK_SRC_SEL, 0x00000000 },
+ { CS42L43_SAMPLE_RATE1, 0x00000003 },
+ { CS42L43_SAMPLE_RATE2, 0x00000003 },
+ { CS42L43_SAMPLE_RATE3, 0x00000003 },
+ { CS42L43_SAMPLE_RATE4, 0x00000003 },
+ { CS42L43_PLL_CONTROL, 0x00000000 },
+ { CS42L43_FS_SELECT1, 0x00000000 },
+ { CS42L43_FS_SELECT2, 0x00000000 },
+ { CS42L43_FS_SELECT3, 0x00000000 },
+ { CS42L43_FS_SELECT4, 0x00000000 },
+ { CS42L43_PDM_CONTROL, 0x00000000 },
+ { CS42L43_ASP_CLK_CONFIG1, 0x00010001 },
+ { CS42L43_ASP_CLK_CONFIG2, 0x00000000 },
+ { CS42L43_OSC_DIV_SEL, 0x00000001 },
+ { CS42L43_ADC_B_CTRL1, 0x00000000 },
+ { CS42L43_ADC_B_CTRL2, 0x00000000 },
+ { CS42L43_DECIM_HPF_WNF_CTRL1, 0x00000001 },
+ { CS42L43_DECIM_HPF_WNF_CTRL2, 0x00000001 },
+ { CS42L43_DECIM_HPF_WNF_CTRL3, 0x00000001 },
+ { CS42L43_DECIM_HPF_WNF_CTRL4, 0x00000001 },
+ { CS42L43_DMIC_PDM_CTRL, 0x00000000 },
+ { CS42L43_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 },
+ { CS42L43_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 },
+ { CS42L43_INTP_VOLUME_CTRL1, 0x00000180 },
+ { CS42L43_INTP_VOLUME_CTRL2, 0x00000180 },
+ { CS42L43_AMP1_2_VOL_RAMP, 0x00000022 },
+ { CS42L43_ASP_CTRL, 0x00000004 },
+ { CS42L43_ASP_FSYNC_CTRL1, 0x000000FA },
+ { CS42L43_ASP_FSYNC_CTRL2, 0x00000001 },
+ { CS42L43_ASP_FSYNC_CTRL3, 0x00000000 },
+ { CS42L43_ASP_FSYNC_CTRL4, 0x000001F4 },
+ { CS42L43_ASP_DATA_CTRL, 0x0000003A },
+ { CS42L43_ASP_RX_EN, 0x00000000 },
+ { CS42L43_ASP_TX_EN, 0x00000000 },
+ { CS42L43_ASP_RX_CH1_CTRL, 0x00170001 },
+ { CS42L43_ASP_RX_CH2_CTRL, 0x00170031 },
+ { CS42L43_ASP_RX_CH3_CTRL, 0x00170061 },
+ { CS42L43_ASP_RX_CH4_CTRL, 0x00170091 },
+ { CS42L43_ASP_RX_CH5_CTRL, 0x001700C1 },
+ { CS42L43_ASP_RX_CH6_CTRL, 0x001700F1 },
+ { CS42L43_ASP_TX_CH1_CTRL, 0x00170001 },
+ { CS42L43_ASP_TX_CH2_CTRL, 0x00170031 },
+ { CS42L43_ASP_TX_CH3_CTRL, 0x00170061 },
+ { CS42L43_ASP_TX_CH4_CTRL, 0x00170091 },
+ { CS42L43_ASP_TX_CH5_CTRL, 0x001700C1 },
+ { CS42L43_ASP_TX_CH6_CTRL, 0x001700F1 },
+ { CS42L43_ASPTX1_INPUT, 0x00800000 },
+ { CS42L43_ASPTX2_INPUT, 0x00800000 },
+ { CS42L43_ASPTX3_INPUT, 0x00800000 },
+ { CS42L43_ASPTX4_INPUT, 0x00800000 },
+ { CS42L43_ASPTX5_INPUT, 0x00800000 },
+ { CS42L43_ASPTX6_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00800000 },
+ { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00800000 },
+ { CS42L43_ASRC_INT1_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_INT2_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_INT3_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_INT4_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_DEC1_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_DEC2_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_DEC3_INPUT1, 0x00800000 },
+ { CS42L43_ASRC_DEC4_INPUT1, 0x00800000 },
+ { CS42L43_ISRC1INT1_INPUT1, 0x00800000 },
+ { CS42L43_ISRC1INT2_INPUT1, 0x00800000 },
+ { CS42L43_ISRC1DEC1_INPUT1, 0x00800000 },
+ { CS42L43_ISRC1DEC2_INPUT1, 0x00800000 },
+ { CS42L43_ISRC2INT1_INPUT1, 0x00800000 },
+ { CS42L43_ISRC2INT2_INPUT1, 0x00800000 },
+ { CS42L43_ISRC2DEC1_INPUT1, 0x00800000 },
+ { CS42L43_ISRC2DEC2_INPUT1, 0x00800000 },
+ { CS42L43_EQ1MIX_INPUT1, 0x00800000 },
+ { CS42L43_EQ1MIX_INPUT2, 0x00800000 },
+ { CS42L43_EQ1MIX_INPUT3, 0x00800000 },
+ { CS42L43_EQ1MIX_INPUT4, 0x00800000 },
+ { CS42L43_EQ2MIX_INPUT1, 0x00800000 },
+ { CS42L43_EQ2MIX_INPUT2, 0x00800000 },
+ { CS42L43_EQ2MIX_INPUT3, 0x00800000 },
+ { CS42L43_EQ2MIX_INPUT4, 0x00800000 },
+ { CS42L43_SPDIF1_INPUT1, 0x00800000 },
+ { CS42L43_SPDIF2_INPUT1, 0x00800000 },
+ { CS42L43_AMP1MIX_INPUT1, 0x00800000 },
+ { CS42L43_AMP1MIX_INPUT2, 0x00800000 },
+ { CS42L43_AMP1MIX_INPUT3, 0x00800000 },
+ { CS42L43_AMP1MIX_INPUT4, 0x00800000 },
+ { CS42L43_AMP2MIX_INPUT1, 0x00800000 },
+ { CS42L43_AMP2MIX_INPUT2, 0x00800000 },
+ { CS42L43_AMP2MIX_INPUT3, 0x00800000 },
+ { CS42L43_AMP2MIX_INPUT4, 0x00800000 },
+ { CS42L43_AMP3MIX_INPUT1, 0x00800000 },
+ { CS42L43_AMP3MIX_INPUT2, 0x00800000 },
+ { CS42L43_AMP3MIX_INPUT3, 0x00800000 },
+ { CS42L43_AMP3MIX_INPUT4, 0x00800000 },
+ { CS42L43_AMP4MIX_INPUT1, 0x00800000 },
+ { CS42L43_AMP4MIX_INPUT2, 0x00800000 },
+ { CS42L43_AMP4MIX_INPUT3, 0x00800000 },
+ { CS42L43_AMP4MIX_INPUT4, 0x00800000 },
+ { CS42L43_ASRC_INT_ENABLES, 0x00000100 },
+ { CS42L43_ASRC_DEC_ENABLES, 0x00000100 },
+ { CS42L43_PDNCNTL, 0x00000000 },
+ { CS42L43_RINGSENSE_DEB_CTRL, 0x0000001B },
+ { CS42L43_TIPSENSE_DEB_CTRL, 0x0000001B },
+ { CS42L43_HS2, 0x050106F3 },
+ { CS42L43_STEREO_MIC_CTRL, 0x00000000 },
+ { CS42L43_STEREO_MIC_CLAMP_CTRL, 0x00000001 },
+ { CS42L43_BLOCK_EN2, 0x00000000 },
+ { CS42L43_BLOCK_EN3, 0x00000000 },
+ { CS42L43_BLOCK_EN4, 0x00000000 },
+ { CS42L43_BLOCK_EN5, 0x00000000 },
+ { CS42L43_BLOCK_EN6, 0x00000000 },
+ { CS42L43_BLOCK_EN7, 0x00000000 },
+ { CS42L43_BLOCK_EN8, 0x00000000 },
+ { CS42L43_BLOCK_EN9, 0x00000000 },
+ { CS42L43_BLOCK_EN10, 0x00000000 },
+ { CS42L43_BLOCK_EN11, 0x00000000 },
+ { CS42L43_TONE_CH1_CTRL, 0x00000000 },
+ { CS42L43_TONE_CH2_CTRL, 0x00000000 },
+ { CS42L43_MIC_DETECT_CONTROL_1, 0x00000003 },
+ { CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, 0x02000003 },
+ { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 },
+ { CS42L43_ISRC1_CTRL, 0x00000000 },
+ { CS42L43_ISRC2_CTRL, 0x00000000 },
+ { CS42L43_CTRL_REG, 0x00000006 },
+ { CS42L43_FDIV_FRAC, 0x40000000 },
+ { CS42L43_CAL_RATIO, 0x00000080 },
+ { CS42L43_SPI_CLK_CONFIG1, 0x00000000 },
+ { CS42L43_SPI_CONFIG1, 0x00000000 },
+ { CS42L43_SPI_CONFIG2, 0x00000000 },
+ { CS42L43_SPI_CONFIG3, 0x00000001 },
+ { CS42L43_SPI_CONFIG4, 0x00000000 },
+ { CS42L43_TRAN_CONFIG3, 0x00000000 },
+ { CS42L43_TRAN_CONFIG4, 0x00000000 },
+ { CS42L43_TRAN_CONFIG5, 0x00000000 },
+ { CS42L43_TRAN_CONFIG6, 0x00000000 },
+ { CS42L43_TRAN_CONFIG7, 0x00000000 },
+ { CS42L43_TRAN_CONFIG8, 0x00000000 },
+ { CS42L43_DACCNFG1, 0x00000008 },
+ { CS42L43_DACCNFG2, 0x00000005 },
+ { CS42L43_HPPATHVOL, 0x011B011B },
+ { CS42L43_PGAVOL, 0x00003470 },
+ { CS42L43_LOADDETENA, 0x00000000 },
+ { CS42L43_CTRL, 0x00000037 },
+ { CS42L43_COEFF_DATA_IN0, 0x00000000 },
+ { CS42L43_COEFF_RD_WR0, 0x00000000 },
+ { CS42L43_START_EQZ0, 0x00000000 },
+ { CS42L43_MUTE_EQ_IN0, 0x00000000 },
+ { CS42L43_DECIM_MASK, 0x0000000F },
+ { CS42L43_EQ_MIX_MASK, 0x0000000F },
+ { CS42L43_ASP_MASK, 0x000000FF },
+ { CS42L43_PLL_MASK, 0x00000003 },
+ { CS42L43_SOFT_MASK, 0x0000FFFF },
+ { CS42L43_SWIRE_MASK, 0x00007FFF },
+ { CS42L43_MSM_MASK, 0x00000FFF },
+ { CS42L43_ACC_DET_MASK, 0x00000FFF },
+ { CS42L43_I2C_TGT_MASK, 0x00000003 },
+ { CS42L43_SPI_MSTR_MASK, 0x00000007 },
+ { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0x00000001 },
+ { CS42L43_OTP_MASK, 0x00000007 },
+ { CS42L43_CLASS_D_AMP_MASK, 0x00003FFF },
+ { CS42L43_GPIO_INT_MASK, 0x0000003F },
+ { CS42L43_ASRC_MASK, 0x0000000F },
+ { CS42L43_HPOUT_MASK, 0x00000003 },
+};
+EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43);
+
+bool cs42l43_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L43_DEVID:
+ case CS42L43_REVID:
+ case CS42L43_RELID:
+ case CS42L43_SFT_RESET:
+ case CS42L43_DRV_CTRL1:
+ case CS42L43_DRV_CTRL3:
+ case CS42L43_DRV_CTRL4:
+ case CS42L43_DRV_CTRL_5:
+ case CS42L43_GPIO_CTRL1:
+ case CS42L43_GPIO_CTRL2:
+ case CS42L43_GPIO_STS:
+ case CS42L43_GPIO_FN_SEL:
+ case CS42L43_MCLK_SRC_SEL:
+ case CS42L43_SAMPLE_RATE1 ... CS42L43_SAMPLE_RATE4:
+ case CS42L43_PLL_CONTROL:
+ case CS42L43_FS_SELECT1 ... CS42L43_FS_SELECT4:
+ case CS42L43_PDM_CONTROL:
+ case CS42L43_ASP_CLK_CONFIG1 ... CS42L43_ASP_CLK_CONFIG2:
+ case CS42L43_OSC_DIV_SEL:
+ case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2:
+ case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4:
+ case CS42L43_DMIC_PDM_CTRL:
+ case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
+ case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2:
+ case CS42L43_AMP1_2_VOL_RAMP:
+ case CS42L43_ASP_CTRL:
+ case CS42L43_ASP_FSYNC_CTRL1 ... CS42L43_ASP_FSYNC_CTRL4:
+ case CS42L43_ASP_DATA_CTRL:
+ case CS42L43_ASP_RX_EN ... CS42L43_ASP_TX_EN:
+ case CS42L43_ASP_RX_CH1_CTRL ... CS42L43_ASP_RX_CH6_CTRL:
+ case CS42L43_ASP_TX_CH1_CTRL ... CS42L43_ASP_TX_CH6_CTRL:
+ case CS42L43_OTP_REVISION_ID:
+ case CS42L43_ASPTX1_INPUT:
+ case CS42L43_ASPTX2_INPUT:
+ case CS42L43_ASPTX3_INPUT:
+ case CS42L43_ASPTX4_INPUT:
+ case CS42L43_ASPTX5_INPUT:
+ case CS42L43_ASPTX6_INPUT:
+ case CS42L43_SWIRE_DP1_CH1_INPUT:
+ case CS42L43_SWIRE_DP1_CH2_INPUT:
+ case CS42L43_SWIRE_DP1_CH3_INPUT:
+ case CS42L43_SWIRE_DP1_CH4_INPUT:
+ case CS42L43_SWIRE_DP2_CH1_INPUT:
+ case CS42L43_SWIRE_DP2_CH2_INPUT:
+ case CS42L43_SWIRE_DP3_CH1_INPUT:
+ case CS42L43_SWIRE_DP3_CH2_INPUT:
+ case CS42L43_SWIRE_DP4_CH1_INPUT:
+ case CS42L43_SWIRE_DP4_CH2_INPUT:
+ case CS42L43_ASRC_INT1_INPUT1:
+ case CS42L43_ASRC_INT2_INPUT1:
+ case CS42L43_ASRC_INT3_INPUT1:
+ case CS42L43_ASRC_INT4_INPUT1:
+ case CS42L43_ASRC_DEC1_INPUT1:
+ case CS42L43_ASRC_DEC2_INPUT1:
+ case CS42L43_ASRC_DEC3_INPUT1:
+ case CS42L43_ASRC_DEC4_INPUT1:
+ case CS42L43_ISRC1INT1_INPUT1:
+ case CS42L43_ISRC1INT2_INPUT1:
+ case CS42L43_ISRC1DEC1_INPUT1:
+ case CS42L43_ISRC1DEC2_INPUT1:
+ case CS42L43_ISRC2INT1_INPUT1:
+ case CS42L43_ISRC2INT2_INPUT1:
+ case CS42L43_ISRC2DEC1_INPUT1:
+ case CS42L43_ISRC2DEC2_INPUT1:
+ case CS42L43_EQ1MIX_INPUT1 ... CS42L43_EQ1MIX_INPUT4:
+ case CS42L43_EQ2MIX_INPUT1 ... CS42L43_EQ2MIX_INPUT4:
+ case CS42L43_SPDIF1_INPUT1:
+ case CS42L43_SPDIF2_INPUT1:
+ case CS42L43_AMP1MIX_INPUT1 ... CS42L43_AMP1MIX_INPUT4:
+ case CS42L43_AMP2MIX_INPUT1 ... CS42L43_AMP2MIX_INPUT4:
+ case CS42L43_AMP3MIX_INPUT1 ... CS42L43_AMP3MIX_INPUT4:
+ case CS42L43_AMP4MIX_INPUT1 ... CS42L43_AMP4MIX_INPUT4:
+ case CS42L43_ASRC_INT_ENABLES ... CS42L43_ASRC_DEC_ENABLES:
+ case CS42L43_PDNCNTL:
+ case CS42L43_RINGSENSE_DEB_CTRL:
+ case CS42L43_TIPSENSE_DEB_CTRL:
+ case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS:
+ case CS42L43_HS2:
+ case CS42L43_HS_STAT:
+ case CS42L43_MCU_SW_INTERRUPT:
+ case CS42L43_STEREO_MIC_CTRL:
+ case CS42L43_STEREO_MIC_CLAMP_CTRL:
+ case CS42L43_BLOCK_EN2 ... CS42L43_BLOCK_EN11:
+ case CS42L43_TONE_CH1_CTRL ... CS42L43_TONE_CH2_CTRL:
+ case CS42L43_MIC_DETECT_CONTROL_1:
+ case CS42L43_DETECT_STATUS_1:
+ case CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL:
+ case CS42L43_MIC_DETECT_CONTROL_ANDROID:
+ case CS42L43_ISRC1_CTRL:
+ case CS42L43_ISRC2_CTRL:
+ case CS42L43_CTRL_REG:
+ case CS42L43_FDIV_FRAC:
+ case CS42L43_CAL_RATIO:
+ case CS42L43_SPI_CLK_CONFIG1:
+ case CS42L43_SPI_CONFIG1 ... CS42L43_SPI_CONFIG4:
+ case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2:
+ case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG8:
+ case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3:
+ case CS42L43_TX_DATA:
+ case CS42L43_RX_DATA:
+ case CS42L43_DACCNFG1 ... CS42L43_DACCNFG2:
+ case CS42L43_HPPATHVOL:
+ case CS42L43_PGAVOL:
+ case CS42L43_LOADDETRESULTS:
+ case CS42L43_LOADDETENA:
+ case CS42L43_CTRL:
+ case CS42L43_COEFF_DATA_IN0:
+ case CS42L43_COEFF_RD_WR0:
+ case CS42L43_INIT_DONE0:
+ case CS42L43_START_EQZ0:
+ case CS42L43_MUTE_EQ_IN0:
+ case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT:
+ case CS42L43_DECIM_MASK ... CS42L43_HPOUT_MASK:
+ case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW:
+ case CS42L43_BOOT_CONTROL:
+ case CS42L43_BLOCK_EN:
+ case CS42L43_SHUTTER_CONTROL:
+ case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43);
+
+bool cs42l43_precious_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L43_SFT_RESET:
+ case CS42L43_TX_DATA:
+ case CS42L43_RX_DATA:
+ case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT:
+ case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43);
+
+bool cs42l43_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L43_DEVID:
+ case CS42L43_REVID:
+ case CS42L43_RELID:
+ case CS42L43_GPIO_STS:
+ case CS42L43_OTP_REVISION_ID:
+ case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS:
+ case CS42L43_HS_STAT:
+ case CS42L43_MCU_SW_INTERRUPT:
+ case CS42L43_DETECT_STATUS_1:
+ case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2:
+ case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG2:
+ case CS42L43_TRAN_CONFIG8:
+ case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3:
+ case CS42L43_LOADDETRESULTS:
+ case CS42L43_INIT_DONE0:
+ case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW:
+ case CS42L43_BOOT_CONTROL:
+ case CS42L43_BLOCK_EN:
+ return true;
+ default:
+ return cs42l43_precious_register(dev, reg);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43);
+
+#define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
+
+#define CS42L43_IRQ_REG(name, reg) REGMAP_IRQ_REG(CS42L43_##name, \
+ CS42L43_IRQ_OFFSET(reg), \
+ CS42L43_##name##_INT_MASK)
+
+static const struct regmap_irq cs42l43_regmap_irqs[] = {
+ CS42L43_IRQ_REG(PLL_LOST_LOCK, PLL),
+ CS42L43_IRQ_REG(PLL_READY, PLL),
+
+ CS42L43_IRQ_REG(HP_STARTUP_DONE, MSM),
+ CS42L43_IRQ_REG(HP_SHUTDOWN_DONE, MSM),
+ CS42L43_IRQ_REG(HSDET_DONE, MSM),
+ CS42L43_IRQ_REG(TIPSENSE_UNPLUG_DB, MSM),
+ CS42L43_IRQ_REG(TIPSENSE_PLUG_DB, MSM),
+ CS42L43_IRQ_REG(RINGSENSE_UNPLUG_DB, MSM),
+ CS42L43_IRQ_REG(RINGSENSE_PLUG_DB, MSM),
+ CS42L43_IRQ_REG(TIPSENSE_UNPLUG_PDET, MSM),
+ CS42L43_IRQ_REG(TIPSENSE_PLUG_PDET, MSM),
+ CS42L43_IRQ_REG(RINGSENSE_UNPLUG_PDET, MSM),
+ CS42L43_IRQ_REG(RINGSENSE_PLUG_PDET, MSM),
+
+ CS42L43_IRQ_REG(HS2_BIAS_SENSE, ACC_DET),
+ CS42L43_IRQ_REG(HS1_BIAS_SENSE, ACC_DET),
+ CS42L43_IRQ_REG(DC_DETECT1_FALSE, ACC_DET),
+ CS42L43_IRQ_REG(DC_DETECT1_TRUE, ACC_DET),
+ CS42L43_IRQ_REG(HSBIAS_CLAMPED, ACC_DET),
+ CS42L43_IRQ_REG(HS3_4_BIAS_SENSE, ACC_DET),
+
+ CS42L43_IRQ_REG(AMP2_CLK_STOP_FAULT, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_CLK_STOP_FAULT, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_VDDSPK_FAULT, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_VDDSPK_FAULT, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_SHUTDOWN_DONE, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_SHUTDOWN_DONE, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_STARTUP_DONE, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_STARTUP_DONE, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_THERM_SHDN, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_THERM_SHDN, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_THERM_WARN, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_THERM_WARN, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP2_SCDET, CLASS_D_AMP),
+ CS42L43_IRQ_REG(AMP1_SCDET, CLASS_D_AMP),
+
+ CS42L43_IRQ_REG(GPIO3_FALL, GPIO),
+ CS42L43_IRQ_REG(GPIO3_RISE, GPIO),
+ CS42L43_IRQ_REG(GPIO2_FALL, GPIO),
+ CS42L43_IRQ_REG(GPIO2_RISE, GPIO),
+ CS42L43_IRQ_REG(GPIO1_FALL, GPIO),
+ CS42L43_IRQ_REG(GPIO1_RISE, GPIO),
+
+ CS42L43_IRQ_REG(HP_ILIMIT, HPOUT),
+ CS42L43_IRQ_REG(HP_LOADDET_DONE, HPOUT),
+};
+
+static const struct regmap_irq_chip cs42l43_irq_chip = {
+ .name = "cs42l43",
+
+ .status_base = CS42L43_DECIM_INT,
+ .mask_base = CS42L43_DECIM_MASK,
+ .num_regs = 16,
+
+ .irqs = cs42l43_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(cs42l43_regmap_irqs),
+
+ .runtime_pm = true,
+};
+
+static const char * const cs42l43_core_supplies[] = {
+ "vdd-a", "vdd-io", "vdd-cp",
+};
+
+static const char * const cs42l43_parent_supplies[] = { "vdd-amp" };
+
+static const struct mfd_cell cs42l43_devs[] = {
+ { .name = "cs42l43-pinctrl", },
+ { .name = "cs42l43-spi", },
+ {
+ .name = "cs42l43-codec",
+ .parent_supplies = cs42l43_parent_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs42l43_parent_supplies),
+ },
+};
+
+/*
+ * If the device is connected over Soundwire, as well as soft resetting the
+ * device, this function will also way for the device to detach from the bus
+ * before returning.
+ */
+static int cs42l43_soft_reset(struct cs42l43 *cs42l43)
+{
+ static const struct reg_sequence reset[] = {
+ { CS42L43_SFT_RESET, CS42L43_SFT_RESET_VAL },
+ };
+
+ reinit_completion(&cs42l43->device_detach);
+
+ /*
+ * Apply cache only because the soft reset will cause the device to
+ * detach from the soundwire bus.
+ */
+ regcache_cache_only(cs42l43->regmap, true);
+ regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset));
+
+ msleep(CS42L43_RESET_DELAY);
+
+ if (cs42l43->sdw) {
+ unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT);
+ unsigned long time;
+
+ time = wait_for_completion_timeout(&cs42l43->device_detach, timeout);
+ if (!time) {
+ dev_err(cs42l43->dev, "Timed out waiting for device detach\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return -EAGAIN;
+}
+
+/*
+ * This function is essentially a no-op on I2C, but will wait for the device to
+ * attach when the device is used on a SoundWire bus.
+ */
+static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43)
+{
+ if (!cs42l43->attached) {
+ unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT);
+ unsigned long time;
+
+ time = wait_for_completion_timeout(&cs42l43->device_attach, timeout);
+ if (!time) {
+ dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ regcache_cache_only(cs42l43->regmap, false);
+
+ /* The hardware requires enabling OSC_DIV before doing any SoundWire reads. */
+ if (cs42l43->sdw)
+ regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL,
+ CS42L43_OSC_DIV2_EN_MASK);
+
+ return 0;
+}
+
+/*
+ * This function will advance the firmware into boot stage 3 from boot stage 2.
+ * Boot stage 3 is required to send commands to the firmware. This is achieved
+ * by setting the firmware NEED configuration register to zero, this indicates
+ * no configuration is required forcing the firmware to advance to boot stage 3.
+ *
+ * Later revisions of the firmware require the use of an alternative register
+ * for this purpose, which is indicated through the shadow flag.
+ */
+static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow)
+{
+ unsigned int need_reg = CS42L43_NEED_CONFIGS;
+ unsigned int val;
+ int ret;
+
+ if (shadow)
+ need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
+
+ regmap_write(cs42l43->regmap, need_reg, 0);
+
+ ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS,
+ val, (val == CS42L43_MCU_BOOT_STAGE3),
+ CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val);
+ return ret;
+ }
+
+ return -EAGAIN;
+}
+
+/*
+ * This function will return the firmware to boot stage 2 from boot stage 3.
+ * Boot stage 2 is required to apply updates to the firmware. This is achieved
+ * by setting the firmware NEED configuration register to FW_PATCH_NEED_CFG,
+ * setting the HAVE configuration register to 0, and soft resetting. The
+ * firmware will see it is missing a patch configuration and will pause in boot
+ * stage 2.
+ *
+ * Note: Unlike cs42l43_mcu_stage_2_3 there is no need to consider the shadow
+ * register here as the driver will only return to boot stage 2 if the firmware
+ * requires update which means the revision does not include shadow register
+ * support.
+ */
+static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43)
+{
+ regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS,
+ CS42L43_FW_PATCH_NEED_CFG_MASK);
+ regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0);
+
+ return cs42l43_soft_reset(cs42l43);
+}
+
+/*
+ * Disable the firmware running on the device such that the driver can access
+ * the registers without fear of the MCU changing them under it.
+ */
+static int cs42l43_mcu_disable(struct cs42l43 *cs42l43)
+{
+ unsigned int val;
+ int ret;
+
+ regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG,
+ CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
+ regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION,
+ CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
+ regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK);
+ regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0);
+
+ ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val,
+ (val & CS42L43_CONTROL_APPLIED_INT_MASK),
+ CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val);
+ return ret;
+ }
+
+ /* Soft reset to clear any register state the firmware left behind. */
+ return cs42l43_soft_reset(cs42l43);
+}
+
+/*
+ * Callback to load firmware updates.
+ */
+static void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *context)
+{
+ struct cs42l43 *cs42l43 = context;
+ const struct cs42l43_patch_header *hdr;
+ unsigned int loadaddr, val;
+ int ret;
+
+ if (!firmware) {
+ dev_err(cs42l43->dev, "Failed to load firmware\n");
+ cs42l43->firmware_error = -ENODEV;
+ goto err;
+ }
+
+ hdr = (const struct cs42l43_patch_header *)&firmware->data[0];
+ loadaddr = le32_to_cpu(hdr->load_addr);
+
+ if (le16_to_cpu(hdr->version) != CS42L43_MCU_UPDATE_FORMAT) {
+ dev_err(cs42l43->dev, "Bad firmware file format: %d\n", hdr->version);
+ cs42l43->firmware_error = -EINVAL;
+ goto err_release;
+ }
+
+ regmap_write(cs42l43->regmap, CS42L43_PATCH_START_ADDR, loadaddr);
+ regmap_bulk_write(cs42l43->regmap, loadaddr + CS42L43_MCU_UPDATE_OFFSET,
+ &firmware->data[0], firmware->size / sizeof(u32));
+
+ regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_PATCH_IND_MASK);
+ regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0);
+
+ ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val,
+ (val & CS42L43_PATCH_APPLIED_INT_MASK),
+ CS42L43_MCU_POLL, CS42L43_MCU_UPDATE_TIMEOUT);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val);
+ cs42l43->firmware_error = ret;
+ goto err_release;
+ }
+
+err_release:
+ release_firmware(firmware);
+err:
+ complete(&cs42l43->firmware_download);
+}
+
+/*
+ * The process of updating the firmware is split into a series of steps, at the
+ * end of each step a soft reset of the device might be required which will
+ * require the driver to wait for the device to re-attach on the SoundWire bus,
+ * if that control bus is being used.
+ */
+static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
+{
+ unsigned int mcu_rev, bios_rev, boot_status, secure_cfg;
+ bool patched, shadow;
+ int ret;
+
+ /* Clear any stale software interrupt bits. */
+ regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev);
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret);
+ return ret;
+ }
+
+ bios_rev = (((mcu_rev & CS42L43_BIOS_MAJOR_REV_MASK) << 12) |
+ ((mcu_rev & CS42L43_BIOS_MINOR_REV_MASK) << 4) |
+ ((mcu_rev & CS42L43_BIOS_SUBMINOR_REV_MASK) >> 8)) >>
+ CS42L43_BIOS_MAJOR_REV_SHIFT;
+ mcu_rev = ((mcu_rev & CS42L43_FW_MAJOR_REV_MASK) << 12) |
+ ((mcu_rev & CS42L43_FW_MINOR_REV_MASK) << 4) |
+ ((mcu_rev & CS42L43_FW_SUBMINOR_REV_MASK) >> 8);
+
+ /*
+ * The firmware has two revision numbers bringing either of them up to a
+ * supported version will provide the features the driver requires.
+ */
+ patched = mcu_rev >= CS42L43_MCU_SUPPORTED_REV ||
+ bios_rev >= CS42L43_MCU_SUPPORTED_BIOS_REV;
+ /*
+ * Later versions of the firmwware require the driver to access some
+ * features through a set of shadow registers.
+ */
+ shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV;
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret);
+ return ret;
+ }
+
+ cs42l43->hw_lock = secure_cfg & CS42L43_LOCK_HW_STS_MASK;
+
+ if (!patched && cs42l43->hw_lock) {
+ dev_err(cs42l43->dev, "Unpatched secure device\n");
+ return -EPERM;
+ }
+
+ dev_dbg(cs42l43->dev, "Firmware(0x%x, 0x%x) in boot stage %d\n",
+ mcu_rev, bios_rev, boot_status);
+
+ switch (boot_status) {
+ case CS42L43_MCU_BOOT_STAGE2:
+ if (!patched) {
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
+ "cs42l43.bin", cs42l43->dev,
+ GFP_KERNEL, cs42l43,
+ cs42l43_mcu_load_firmware);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to request firmware: %d\n", ret);
+ return ret;
+ }
+
+ wait_for_completion(&cs42l43->firmware_download);
+
+ if (cs42l43->firmware_error)
+ return cs42l43->firmware_error;
+
+ return -EAGAIN;
+ } else {
+ return cs42l43_mcu_stage_2_3(cs42l43, shadow);
+ }
+ case CS42L43_MCU_BOOT_STAGE3:
+ if (patched)
+ return cs42l43_mcu_disable(cs42l43);
+ else
+ return cs42l43_mcu_stage_3_2(cs42l43);
+ case CS42L43_MCU_BOOT_STAGE4:
+ return 0;
+ default:
+ dev_err(cs42l43->dev, "Invalid boot status: %d\n", boot_status);
+ return -EINVAL;
+ }
+}
+
+/*
+ * Update the firmware running on the device.
+ */
+static int cs42l43_mcu_update(struct cs42l43 *cs42l43)
+{
+ int i, ret;
+
+ for (i = 0; i < CS42L43_MCU_UPDATE_RETRIES; i++) {
+ ret = cs42l43_mcu_update_step(cs42l43);
+ if (ret != -EAGAIN)
+ return ret;
+
+ ret = cs42l43_wait_for_attach(cs42l43);
+ if (ret)
+ return ret;
+ }
+
+ dev_err(cs42l43->dev, "Failed retrying update\n");
+ return -ETIMEDOUT;
+}
+
+static int cs42l43_irq_config(struct cs42l43 *cs42l43)
+{
+ struct irq_data *irq_data;
+ unsigned long irq_flags;
+ int ret;
+
+ if (cs42l43->sdw)
+ cs42l43->irq = cs42l43->sdw->irq;
+
+ cs42l43->irq_chip = cs42l43_irq_chip;
+ cs42l43->irq_chip.irq_drv_data = cs42l43;
+
+ irq_data = irq_get_irq_data(cs42l43->irq);
+ if (!irq_data) {
+ dev_err(cs42l43->dev, "Invalid IRQ: %d\n", cs42l43->irq);
+ return -EINVAL;
+ }
+
+ irq_flags = irqd_get_trigger_type(irq_data);
+ switch (irq_flags) {
+ case IRQF_TRIGGER_LOW:
+ case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
+ case IRQF_TRIGGER_FALLING:
+ break;
+ case IRQ_TYPE_NONE:
+ default:
+ irq_flags = IRQF_TRIGGER_LOW;
+ break;
+ }
+
+ irq_flags |= IRQF_ONESHOT;
+
+ ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap,
+ cs42l43->irq, irq_flags, 0,
+ &cs42l43->irq_chip, &cs42l43->irq_data);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n",
+ cs42l43->irq, irq_flags);
+
+ return 0;
+}
+
+static void cs42l43_boot_work(struct work_struct *work)
+{
+ struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work);
+ unsigned int devid, revid, otp;
+ int ret;
+
+ ret = cs42l43_wait_for_attach(cs42l43);
+ if (ret)
+ goto err;
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_DEVID, &devid);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read devid: %d\n", ret);
+ goto err;
+ }
+
+ switch (devid) {
+ case CS42L43_DEVID_VAL:
+ break;
+ default:
+ dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid);
+ goto err;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_OTP_REVISION_ID, &otp);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to read otp rev: %d\n", ret);
+ goto err;
+ }
+
+ dev_info(cs42l43->dev,
+ "devid: 0x%06x, rev: 0x%02x, otp: 0x%02x\n", devid, revid, otp);
+
+ ret = cs42l43_mcu_update(cs42l43);
+ if (ret)
+ goto err;
+
+ ret = regmap_register_patch(cs42l43->regmap, cs42l43_reva_patch,
+ ARRAY_SIZE(cs42l43_reva_patch));
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to apply register patch: %d\n", ret);
+ goto err;
+ }
+
+ ret = cs42l43_irq_config(cs42l43);
+ if (ret)
+ goto err;
+
+ ret = devm_mfd_add_devices(cs42l43->dev, PLATFORM_DEVID_NONE,
+ cs42l43_devs, ARRAY_SIZE(cs42l43_devs),
+ NULL, 0, NULL);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to add subdevices: %d\n", ret);
+ goto err;
+ }
+
+ pm_runtime_mark_last_busy(cs42l43->dev);
+ pm_runtime_put_autosuspend(cs42l43->dev);
+
+ return;
+
+err:
+ pm_runtime_put_sync(cs42l43->dev);
+ cs42l43_dev_remove(cs42l43);
+}
+
+static int cs42l43_power_up(struct cs42l43 *cs42l43)
+{
+ int ret;
+
+ ret = regulator_enable(cs42l43->vdd_p);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to enable vdd-p: %d\n", ret);
+ return ret;
+ }
+
+ /* vdd-p must be on for 50uS before any other supply */
+ usleep_range(CS42L43_VDDP_DELAY, 2 * CS42L43_VDDP_DELAY);
+
+ gpiod_set_value_cansleep(cs42l43->reset, 1);
+
+ ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to enable core supplies: %d\n", ret);
+ goto err_reset;
+ }
+
+ ret = regulator_enable(cs42l43->vdd_d);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to enable vdd-d: %d\n", ret);
+ goto err_core_supplies;
+ }
+
+ usleep_range(CS42L43_VDDD_DELAY, 2 * CS42L43_VDDD_DELAY);
+
+ return 0;
+
+err_core_supplies:
+ regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
+err_reset:
+ gpiod_set_value_cansleep(cs42l43->reset, 0);
+ regulator_disable(cs42l43->vdd_p);
+
+ return ret;
+}
+
+static int cs42l43_power_down(struct cs42l43 *cs42l43)
+{
+ int ret;
+
+ ret = regulator_disable(cs42l43->vdd_d);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to disable vdd-d: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to disable core supplies: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(cs42l43->reset, 0);
+
+ ret = regulator_disable(cs42l43->vdd_p);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to disable vdd-p: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int cs42l43_dev_probe(struct cs42l43 *cs42l43)
+{
+ int i, ret;
+
+ dev_set_drvdata(cs42l43->dev, cs42l43);
+
+ mutex_init(&cs42l43->pll_lock);
+ init_completion(&cs42l43->device_attach);
+ init_completion(&cs42l43->device_detach);
+ init_completion(&cs42l43->firmware_download);
+ INIT_WORK(&cs42l43->boot_work, cs42l43_boot_work);
+
+ regcache_cache_only(cs42l43->regmap, true);
+
+ cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs42l43->reset))
+ return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset),
+ "Failed to get reset\n");
+
+ cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p");
+ if (IS_ERR(cs42l43->vdd_p))
+ return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p),
+ "Failed to get vdd-p\n");
+
+ cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d");
+ if (IS_ERR(cs42l43->vdd_d))
+ return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d),
+ "Failed to get vdd-d\n");
+
+ BUILD_BUG_ON(ARRAY_SIZE(cs42l43_core_supplies) != CS42L43_N_SUPPLIES);
+
+ for (i = 0; i < CS42L43_N_SUPPLIES; i++)
+ cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i];
+
+ ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES,
+ cs42l43->core_supplies);
+ if (ret)
+ return dev_err_probe(cs42l43->dev, ret,
+ "Failed to get core supplies\n");
+
+ ret = cs42l43_power_up(cs42l43);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME);
+ pm_runtime_use_autosuspend(cs42l43->dev);
+ pm_runtime_set_active(cs42l43->dev);
+ /*
+ * The device is already powered up, but keep it from suspending until
+ * the boot work runs.
+ */
+ pm_runtime_get_noresume(cs42l43->dev);
+ devm_pm_runtime_enable(cs42l43->dev);
+
+ queue_work(system_long_wq, &cs42l43->boot_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43);
+
+void cs42l43_dev_remove(struct cs42l43 *cs42l43)
+{
+ cs42l43_power_down(cs42l43);
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43);
+
+static int cs42l43_suspend(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+ int ret;
+
+ /*
+ * Don't care about being resumed here, but the driver does want
+ * force_resume to always trigger an actual resume, so that register
+ * state for the MCU/GPIOs is returned as soon as possible after system
+ * resume. force_resume will resume if the reference count is resumed on
+ * suspend hence the get_noresume.
+ */
+ pm_runtime_get_noresume(dev);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret);
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
+ pm_runtime_put_noidle(dev);
+
+ ret = cs42l43_power_down(cs42l43);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int cs42l43_resume(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = cs42l43_power_up(cs42l43);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cs42l43_runtime_suspend(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
+ /*
+ * Whilst the driver doesn't power the chip down here, going into runtime
+ * suspend lets the SoundWire bus power down, which means the driver
+ * can't communicate with the device any more.
+ */
+ regcache_cache_only(cs42l43->regmap, true);
+
+ return 0;
+}
+
+static int cs42l43_runtime_resume(struct device *dev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+ unsigned int reset_canary;
+ int ret;
+
+ ret = cs42l43_wait_for_attach(cs42l43);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret);
+ goto err;
+ }
+
+ if (!reset_canary) {
+ /*
+ * If the canary has cleared the chip has reset, re-handle the
+ * MCU and mark the cache as dirty to indicate the chip reset.
+ */
+ ret = cs42l43_mcu_update(cs42l43);
+ if (ret)
+ goto err;
+
+ regcache_mark_dirty(cs42l43->regmap);
+ }
+
+ ret = regcache_sync(cs42l43->regmap);
+ if (ret) {
+ dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regcache_cache_only(cs42l43->regmap, true);
+
+ return ret;
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = {
+ SET_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume)
+ SET_RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL)
+};
+
+MODULE_DESCRIPTION("CS42L43 Core Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("cs42l43.bin");
diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h
new file mode 100644
index 000000000000..eb4caf393833
--- /dev/null
+++ b/drivers/mfd/cs42l43.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS42L43 core driver internal data
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/mfd/cs42l43.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#ifndef CS42L43_CORE_INT_H
+#define CS42L43_CORE_INT_H
+
+#define CS42L43_N_DEFAULTS 176
+
+extern const struct dev_pm_ops cs42l43_pm_ops;
+extern const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS];
+
+bool cs42l43_readable_register(struct device *dev, unsigned int reg);
+bool cs42l43_precious_register(struct device *dev, unsigned int reg);
+bool cs42l43_volatile_register(struct device *dev, unsigned int reg);
+
+int cs42l43_dev_probe(struct cs42l43 *cs42l43);
+void cs42l43_dev_remove(struct cs42l43 *cs42l43);
+
+#endif /* CS42L43_CORE_INT_H */
diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c
index 6a21000aad4a..9bb7d7d8dcfc 100644
--- a/drivers/mfd/tps65086.c
+++ b/drivers/mfd/tps65086.c
@@ -81,16 +81,23 @@ static int tps65086_probe(struct i2c_client *client)
return PTR_ERR(tps->regmap);
}
- ret = regmap_read(tps->regmap, TPS65086_DEVICEID, &version);
+ /* Store device ID to load regulator configuration that fit to IC variant */
+ ret = regmap_read(tps->regmap, TPS65086_DEVICEID1, &tps->chip_id);
if (ret) {
- dev_err(tps->dev, "Failed to read revision register\n");
+ dev_err(tps->dev, "Failed to read revision register 1\n");
+ return ret;
+ }
+
+ ret = regmap_read(tps->regmap, TPS65086_DEVICEID2, &version);
+ if (ret) {
+ dev_err(tps->dev, "Failed to read revision register 2\n");
return ret;
}
dev_info(tps->dev, "Device: TPS65086%01lX, OTP: %c, Rev: %ld\n",
- (version & TPS65086_DEVICEID_PART_MASK),
- (char)((version & TPS65086_DEVICEID_OTP_MASK) >> 4) + 'A',
- (version & TPS65086_DEVICEID_REV_MASK) >> 6);
+ (version & TPS65086_DEVICEID2_PART_MASK),
+ (char)((version & TPS65086_DEVICEID2_OTP_MASK) >> 4) + 'A',
+ (version & TPS65086_DEVICEID2_REV_MASK) >> 6);
if (tps->irq > 0) {
ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0,
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 35fec1bf1b3d..5867af9f592c 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -139,7 +139,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_ino = get_next_ino();
ret->i_mode = mode;
- ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
+ ret->i_atime = ret->i_mtime = inode_set_ctime_current(ret);
}
return ret;
}
diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c
index cbaf6d35e854..2101eb12bcba 100644
--- a/drivers/misc/ibmvmc.c
+++ b/drivers/misc/ibmvmc.c
@@ -1124,7 +1124,7 @@ static ssize_t ibmvmc_write(struct file *file, const char *buffer,
goto out;
inode = file_inode(file);
- inode->i_mtime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
mark_inode_dirty(inode);
dev_dbg(adapter->dev, "write: file = 0x%lx, count = 0x%lx\n",
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 3c95600ab2f7..c66cc05a68c4 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -273,8 +273,8 @@ static void lkdtm_HUNG_TASK(void)
schedule();
}
-volatile unsigned int huge = INT_MAX - 2;
-volatile unsigned int ignored;
+static volatile unsigned int huge = INT_MAX - 2;
+static volatile unsigned int ignored;
static void lkdtm_OVERFLOW_SIGNED(void)
{
@@ -305,7 +305,7 @@ static void lkdtm_OVERFLOW_UNSIGNED(void)
ignored = value;
}
-/* Intentionally using old-style flex array definition of 1 byte. */
+/* Intentionally using unannotated flex array definition. */
struct array_bounds_flex_array {
int one;
int two;
@@ -357,6 +357,46 @@ static void lkdtm_ARRAY_BOUNDS(void)
pr_expected_config(CONFIG_UBSAN_BOUNDS);
}
+struct lkdtm_annotated {
+ unsigned long flags;
+ int count;
+ int array[] __counted_by(count);
+};
+
+static volatile int fam_count = 4;
+
+static void lkdtm_FAM_BOUNDS(void)
+{
+ struct lkdtm_annotated *inst;
+
+ inst = kzalloc(struct_size(inst, array, fam_count + 1), GFP_KERNEL);
+ if (!inst) {
+ pr_err("FAIL: could not allocate test struct!\n");
+ return;
+ }
+
+ inst->count = fam_count;
+ pr_info("Array access within bounds ...\n");
+ inst->array[1] = fam_count;
+ ignored = inst->array[1];
+
+ pr_info("Array access beyond bounds ...\n");
+ inst->array[fam_count] = fam_count;
+ ignored = inst->array[fam_count];
+
+ kfree(inst);
+
+ pr_err("FAIL: survived access of invalid flexible array member index!\n");
+
+ if (!__has_attribute(__counted_by__))
+ pr_warn("This is expected since this %s was built a compiler supporting __counted_by\n",
+ lkdtm_kernel_info);
+ else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))
+ pr_expected_config(CONFIG_UBSAN_TRAP);
+ else
+ pr_expected_config(CONFIG_UBSAN_BOUNDS);
+}
+
static void lkdtm_CORRUPT_LIST_ADD(void)
{
/*
@@ -393,7 +433,7 @@ static void lkdtm_CORRUPT_LIST_ADD(void)
pr_err("Overwrite did not happen, but no BUG?!\n");
else {
pr_err("list_add() corruption not detected!\n");
- pr_expected_config(CONFIG_DEBUG_LIST);
+ pr_expected_config(CONFIG_LIST_HARDENED);
}
}
@@ -420,7 +460,7 @@ static void lkdtm_CORRUPT_LIST_DEL(void)
pr_err("Overwrite did not happen, but no BUG?!\n");
else {
pr_err("list_del() corruption not detected!\n");
- pr_expected_config(CONFIG_DEBUG_LIST);
+ pr_expected_config(CONFIG_LIST_HARDENED);
}
}
@@ -616,6 +656,7 @@ static struct crashtype crashtypes[] = {
CRASHTYPE(OVERFLOW_SIGNED),
CRASHTYPE(OVERFLOW_UNSIGNED),
CRASHTYPE(ARRAY_BOUNDS),
+ CRASHTYPE(FAM_BOUNDS),
CRASHTYPE(CORRUPT_LIST_ADD),
CRASHTYPE(CORRUPT_LIST_DEL),
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c
index 4cf4c55a5f00..c06c699c0e7b 100644
--- a/drivers/misc/ocxl/link.c
+++ b/drivers/misc/ocxl/link.c
@@ -491,9 +491,9 @@ void ocxl_link_release(struct pci_dev *dev, void *link_handle)
}
EXPORT_SYMBOL_GPL(ocxl_link_release);
-static void invalidate_range(struct mmu_notifier *mn,
- struct mm_struct *mm,
- unsigned long start, unsigned long end)
+static void arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start, unsigned long end)
{
struct pe_data *pe_data = container_of(mn, struct pe_data, mmu_notifier);
struct ocxl_link *link = pe_data->link;
@@ -509,7 +509,7 @@ static void invalidate_range(struct mmu_notifier *mn,
}
static const struct mmu_notifier_ops ocxl_mmu_notifier_ops = {
- .invalidate_range = invalidate_range,
+ .arch_invalidate_secondary_tlbs = arch_invalidate_secondary_tlbs,
};
static u64 calculate_cfg_state(bool kernel)
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index b6f4be25b31b..b5b414a71e0b 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -918,17 +918,9 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
struct scatterlist sg;
- cmd.opcode = MMC_APP_CMD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_app_cmd(card->host, card);
if (err)
return err;
- if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
- return -EIO;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
@@ -3026,7 +3018,6 @@ static void mmc_blk_remove(struct mmc_card *card)
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
- dev_set_drvdata(&card->dev, NULL);
destroy_workqueue(card->complete_wq);
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 2c3074a605fc..0af96548e7da 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -310,6 +310,9 @@ int mmc_add_card(struct mmc_card *card)
dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
+ dev_set_removable(&card->dev,
+ mmc_card_is_removable(card->host) ?
+ DEVICE_REMOVABLE : DEVICE_FIXED);
switch (card->type) {
case MMC_TYPE_MMC:
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 09ffbc00908b..92d4194c7893 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -32,7 +32,6 @@ int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
u32 args, void *buf, unsigned len);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
-int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
index f6dde9edd7a3..3b6d69cefb4e 100644
--- a/drivers/mmc/core/pwrseq_emmc.c
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -90,14 +90,12 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
+static void mmc_pwrseq_emmc_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev);
unregister_restart_handler(&pwrseq->reset_nb);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static const struct of_device_id mmc_pwrseq_emmc_of_match[] = {
@@ -109,7 +107,7 @@ MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
static struct platform_driver mmc_pwrseq_emmc_driver = {
.probe = mmc_pwrseq_emmc_probe,
- .remove = mmc_pwrseq_emmc_remove,
+ .remove_new = mmc_pwrseq_emmc_remove,
.driver = {
.name = "pwrseq_emmc",
.of_match_table = mmc_pwrseq_emmc_of_match,
diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c
index 0c5f5e371e1f..0c5808fc3206 100644
--- a/drivers/mmc/core/pwrseq_sd8787.c
+++ b/drivers/mmc/core/pwrseq_sd8787.c
@@ -113,18 +113,16 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
+static void mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_sd8787 *pwrseq = platform_get_drvdata(pdev);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static struct platform_driver mmc_pwrseq_sd8787_driver = {
.probe = mmc_pwrseq_sd8787_probe,
- .remove = mmc_pwrseq_sd8787_remove,
+ .remove_new = mmc_pwrseq_sd8787_remove,
.driver = {
.name = "pwrseq_sd8787",
.of_match_table = mmc_pwrseq_sd8787_of_match,
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index 3bac1e71411b..df9588503ad0 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -142,18 +142,16 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
+static void mmc_pwrseq_simple_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static struct platform_driver mmc_pwrseq_simple_driver = {
.probe = mmc_pwrseq_simple_probe,
- .remove = mmc_pwrseq_simple_remove,
+ .remove_new = mmc_pwrseq_simple_remove,
.driver = {
.name = "pwrseq_simple",
.of_match_table = mmc_pwrseq_simple_of_match,
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 246ce027ae0a..c3e554344c99 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1518,6 +1518,13 @@ retry:
*/
mmc_set_clock(host, mmc_sd_get_max_clock(card));
+ if (host->ios.timing == MMC_TIMING_SD_HS &&
+ host->ops->prepare_sd_hs_tuning) {
+ err = host->ops->prepare_sd_hs_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
+
/*
* Switch to wider bus (if supported).
*/
@@ -1529,6 +1536,13 @@ retry:
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
}
+
+ if (host->ios.timing == MMC_TIMING_SD_HS &&
+ host->ops->execute_sd_hs_tuning) {
+ err = host->ops->execute_sd_hs_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
}
cont:
if (!oldcard) {
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index ef8d1dce5af1..a59cd592f06e 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -323,6 +323,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
64);
}
+EXPORT_SYMBOL_GPL(mmc_sd_switch);
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 3ba7b3cf4652..7667fc223b74 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -19,8 +19,6 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card);
-int mmc_sd_switch(struct mmc_card *card, int mode, int group,
- u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 159a3e9490ae..554e67103c1a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -526,11 +526,12 @@ config MMC_ALCOR
of Alcor Micro PCI-E card reader
config MMC_AU1X
- tristate "Alchemy AU1XX0 MMC Card Interface support"
+ bool "Alchemy AU1XX0 MMC Card Interface support"
depends on MIPS_ALCHEMY
+ depends on MMC=y
help
This selects the AMD Alchemy(R) Multimedia card interface.
- If you have a Alchemy platform with a MMC slot, say Y or M here.
+ If you have a Alchemy platform with a MMC slot, say Y here.
If unsure, say N.
diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c
index d01df01d4b4d..42aa43740ba8 100644
--- a/drivers/mmc/host/alcor.c
+++ b/drivers/mmc/host/alcor.c
@@ -1125,7 +1125,7 @@ free_host:
return ret;
}
-static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
+static void alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
{
struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev);
struct mmc_host *mmc = mmc_from_priv(host);
@@ -1136,8 +1136,6 @@ static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
alcor_hw_uninit(host);
mmc_remove_host(mmc);
mmc_free_host(mmc);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1177,7 +1175,7 @@ MODULE_DEVICE_TABLE(platform, alcor_pci_sdmmc_ids);
static struct platform_driver alcor_pci_sdmmc_driver = {
.probe = alcor_pci_sdmmc_drv_probe,
- .remove = alcor_pci_sdmmc_drv_remove,
+ .remove_new = alcor_pci_sdmmc_drv_remove,
.id_table = alcor_pci_sdmmc_ids,
.driver = {
.name = DRV_NAME_ALCOR_PCI_SDMMC,
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index dd18440a90c5..535783c43105 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -11,15 +11,14 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
@@ -30,7 +29,6 @@
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
-#include <linux/atmel-mci.h>
#include <linux/atmel_pdc.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -40,6 +38,8 @@
#include <asm/io.h>
#include <asm/unaligned.h>
+#define ATMCI_MAX_NR_SLOTS 2
+
/*
* Superset of MCI IP registers integrated in Atmel AT91 Processor
* Registers and bitfields marked with [2] are only available in MCI2
@@ -201,6 +201,40 @@ enum atmci_pdc_buf {
PDC_SECOND_BUF,
};
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ * @non_removable: The slot is not removable, only detect once
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+ unsigned int bus_width;
+ struct gpio_desc *detect_pin;
+ struct gpio_desc *wp_pin;
+ bool non_removable;
+};
+
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+ void *dma_slave;
+ dma_filter_fn dma_filter;
+ struct mci_slot_pdata slot[ATMCI_MAX_NR_SLOTS];
+};
+
struct atmel_mci_caps {
bool has_dma_conf_reg;
bool has_pdc;
@@ -369,7 +403,6 @@ struct atmel_mci {
* available.
* @wp_pin: GPIO pin used for card write protect sending, or negative
* if not available.
- * @detect_is_active_high: The state of the detect pin when it is active.
* @detect_timer: Timer used for debouncing @detect_pin interrupts.
*/
struct atmel_mci_slot {
@@ -388,9 +421,8 @@ struct atmel_mci_slot {
#define ATMCI_CARD_NEED_INIT 1
#define ATMCI_SHUTDOWN 2
- int detect_pin;
- int wp_pin;
- bool detect_is_active_high;
+ struct gpio_desc *detect_pin;
+ struct gpio_desc *wp_pin;
struct timer_list detect_timer;
};
@@ -608,6 +640,7 @@ atmci_of_init(struct platform_device *pdev)
struct device_node *cnp;
struct mci_platform_data *pdata;
u32 slot_id;
+ int err;
if (!np) {
dev_err(&pdev->dev, "device node not found\n");
@@ -637,16 +670,27 @@ atmci_of_init(struct platform_device *pdev)
pdata->slot[slot_id].bus_width = 1;
pdata->slot[slot_id].detect_pin =
- of_get_named_gpio(cnp, "cd-gpios", 0);
-
- pdata->slot[slot_id].detect_is_active_high =
- of_property_read_bool(cnp, "cd-inverted");
+ devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp),
+ "cd", GPIOD_IN, "cd-gpios");
+ err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin);
+ if (err) {
+ if (err != -ENOENT)
+ return ERR_PTR(err);
+ pdata->slot[slot_id].detect_pin = NULL;
+ }
pdata->slot[slot_id].non_removable =
of_property_read_bool(cnp, "non-removable");
pdata->slot[slot_id].wp_pin =
- of_get_named_gpio(cnp, "wp-gpios", 0);
+ devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp),
+ "wp", GPIOD_IN, "wp-gpios");
+ err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin);
+ if (err) {
+ if (err != -ENOENT)
+ return ERR_PTR(err);
+ pdata->slot[slot_id].wp_pin = NULL;
+ }
}
return pdata;
@@ -1509,8 +1553,8 @@ static int atmci_get_ro(struct mmc_host *mmc)
int read_only = -ENOSYS;
struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(slot->wp_pin)) {
- read_only = gpio_get_value(slot->wp_pin);
+ if (slot->wp_pin) {
+ read_only = gpiod_get_value(slot->wp_pin);
dev_dbg(&mmc->class_dev, "card is %s\n",
read_only ? "read-only" : "read-write");
}
@@ -1523,9 +1567,8 @@ static int atmci_get_cd(struct mmc_host *mmc)
int present = -ENOSYS;
struct atmel_mci_slot *slot = mmc_priv(mmc);
- if (gpio_is_valid(slot->detect_pin)) {
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
+ if (slot->detect_pin) {
+ present = gpiod_get_value_cansleep(slot->detect_pin);
dev_dbg(&mmc->class_dev, "card is %spresent\n",
present ? "" : "not ");
}
@@ -1637,9 +1680,8 @@ static void atmci_detect_change(struct timer_list *t)
if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
return;
- enable_irq(gpio_to_irq(slot->detect_pin));
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
+ enable_irq(gpiod_to_irq(slot->detect_pin));
+ present = gpiod_get_value_cansleep(slot->detect_pin);
present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
@@ -2230,16 +2272,15 @@ static int atmci_init_slot(struct atmel_mci *host,
slot->host = host;
slot->detect_pin = slot_data->detect_pin;
slot->wp_pin = slot_data->wp_pin;
- slot->detect_is_active_high = slot_data->detect_is_active_high;
slot->sdc_reg = sdc_reg;
slot->sdio_irq = sdio_irq;
dev_dbg(&mmc->class_dev,
"slot[%u]: bus_width=%u, detect_pin=%d, "
"detect_is_active_high=%s, wp_pin=%d\n",
- id, slot_data->bus_width, slot_data->detect_pin,
- slot_data->detect_is_active_high ? "true" : "false",
- slot_data->wp_pin);
+ id, slot_data->bus_width, desc_to_gpio(slot_data->detect_pin),
+ !gpiod_is_active_low(slot_data->detect_pin) ? "true" : "false",
+ desc_to_gpio(slot_data->wp_pin));
mmc->ops = &atmci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
@@ -2275,31 +2316,22 @@ static int atmci_init_slot(struct atmel_mci *host,
/* Assume card is present initially */
set_bit(ATMCI_CARD_PRESENT, &slot->flags);
- if (gpio_is_valid(slot->detect_pin)) {
- if (devm_gpio_request(&host->pdev->dev, slot->detect_pin,
- "mmc_detect")) {
- dev_dbg(&mmc->class_dev, "no detect pin available\n");
- slot->detect_pin = -EBUSY;
- } else if (gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high) {
+ if (slot->detect_pin) {
+ if (!gpiod_get_value_cansleep(slot->detect_pin))
clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
- }
+ } else {
+ dev_dbg(&mmc->class_dev, "no detect pin available\n");
}
- if (!gpio_is_valid(slot->detect_pin)) {
+ if (!slot->detect_pin) {
if (slot_data->non_removable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
else
mmc->caps |= MMC_CAP_NEEDS_POLL;
}
- if (gpio_is_valid(slot->wp_pin)) {
- if (devm_gpio_request(&host->pdev->dev, slot->wp_pin,
- "mmc_wp")) {
- dev_dbg(&mmc->class_dev, "no WP pin available\n");
- slot->wp_pin = -EBUSY;
- }
- }
+ if (!slot->wp_pin)
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
host->slot[id] = slot;
mmc_regulator_get_supply(mmc);
@@ -2309,18 +2341,18 @@ static int atmci_init_slot(struct atmel_mci *host,
return ret;
}
- if (gpio_is_valid(slot->detect_pin)) {
+ if (slot->detect_pin) {
timer_setup(&slot->detect_timer, atmci_detect_change, 0);
- ret = request_irq(gpio_to_irq(slot->detect_pin),
- atmci_detect_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mmc-detect", slot);
+ ret = request_irq(gpiod_to_irq(slot->detect_pin),
+ atmci_detect_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "mmc-detect", slot);
if (ret) {
dev_dbg(&mmc->class_dev,
"could not request IRQ %d for detect pin\n",
- gpio_to_irq(slot->detect_pin));
- slot->detect_pin = -EBUSY;
+ gpiod_to_irq(slot->detect_pin));
+ slot->detect_pin = NULL;
}
}
@@ -2339,10 +2371,8 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_remove_host(slot->mmc);
- if (gpio_is_valid(slot->detect_pin)) {
- int pin = slot->detect_pin;
-
- free_irq(gpio_to_irq(pin), slot);
+ if (slot->detect_pin) {
+ free_irq(gpiod_to_irq(slot->detect_pin), slot);
del_timer_sync(&slot->detect_timer);
}
@@ -2600,7 +2630,7 @@ err_dma_probe_defer:
return ret;
}
-static int atmci_remove(struct platform_device *pdev)
+static void atmci_remove(struct platform_device *pdev)
{
struct atmel_mci *host = platform_get_drvdata(pdev);
unsigned int i;
@@ -2630,8 +2660,6 @@ static int atmci_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -2664,7 +2692,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = {
static struct platform_driver atmci_driver = {
.probe = atmci_probe,
- .remove = atmci_remove,
+ .remove_new = atmci_remove,
.driver = {
.name = "atmel_mci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 82dd0ae40305..b5a5c6a2fe8b 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1114,7 +1114,7 @@ out0:
return ret;
}
-static int au1xmmc_remove(struct platform_device *pdev)
+static void au1xmmc_remove(struct platform_device *pdev)
{
struct au1xmmc_host *host = platform_get_drvdata(pdev);
@@ -1153,7 +1153,6 @@ static int au1xmmc_remove(struct platform_device *pdev)
mmc_free_host(host->mmc);
}
- return 0;
}
#ifdef CONFIG_PM
@@ -1185,7 +1184,7 @@ static int au1xmmc_resume(struct platform_device *pdev)
static struct platform_driver au1xmmc_driver = {
.probe = au1xmmc_probe,
- .remove = au1xmmc_remove,
+ .remove_new = au1xmmc_remove,
.suspend = au1xmmc_suspend,
.resume = au1xmmc_resume,
.driver = {
diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c
index eea208856ce0..35d8fdea668b 100644
--- a/drivers/mmc/host/bcm2835.c
+++ b/drivers/mmc/host/bcm2835.c
@@ -1431,7 +1431,7 @@ err:
return ret;
}
-static int bcm2835_remove(struct platform_device *pdev)
+static void bcm2835_remove(struct platform_device *pdev)
{
struct bcm2835_host *host = platform_get_drvdata(pdev);
struct mmc_host *mmc = mmc_from_priv(host);
@@ -1449,8 +1449,6 @@ static int bcm2835_remove(struct platform_device *pdev)
dma_release_channel(host->dma_chan_rxtx);
mmc_free_host(mmc);
-
- return 0;
}
static const struct of_device_id bcm2835_match[] = {
@@ -1461,7 +1459,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_match);
static struct platform_driver bcm2835_driver = {
.probe = bcm2835_probe,
- .remove = bcm2835_remove,
+ .remove_new = bcm2835_remove,
.driver = {
.name = "sdhost-bcm2835",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c
index 12dca91a8ef6..060ec4f4800f 100644
--- a/drivers/mmc/host/cavium-octeon.c
+++ b/drivers/mmc/host/cavium-octeon.c
@@ -13,7 +13,9 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <asm/octeon/octeon.h>
#include "cavium.h"
@@ -294,7 +296,7 @@ error:
return ret;
}
-static int octeon_mmc_remove(struct platform_device *pdev)
+static void octeon_mmc_remove(struct platform_device *pdev)
{
struct cvm_mmc_host *host = platform_get_drvdata(pdev);
u64 dma_cfg;
@@ -309,7 +311,6 @@ static int octeon_mmc_remove(struct platform_device *pdev)
writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host));
octeon_mmc_set_shared_power(host, 0);
- return 0;
}
static const struct of_device_id octeon_mmc_match[] = {
@@ -325,7 +326,7 @@ MODULE_DEVICE_TABLE(of, octeon_mmc_match);
static struct platform_driver octeon_mmc_driver = {
.probe = octeon_mmc_probe,
- .remove = octeon_mmc_remove,
+ .remove_new = octeon_mmc_remove,
.driver = {
.name = KBUILD_MODNAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c
index 202b1d6da678..2e2ff984f0b3 100644
--- a/drivers/mmc/host/cavium-thunderx.c
+++ b/drivers/mmc/host/cavium-thunderx.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pci.h>
#include "cavium.h"
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
index 6d623b2681c3..0aec33b88bef 100644
--- a/drivers/mmc/host/cb710-mmc.c
+++ b/drivers/mmc/host/cb710-mmc.c
@@ -745,7 +745,7 @@ err_free_mmc:
return err;
}
-static int cb710_mmc_exit(struct platform_device *pdev)
+static void cb710_mmc_exit(struct platform_device *pdev)
{
struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
struct mmc_host *mmc = cb710_slot_to_mmc(slot);
@@ -766,13 +766,12 @@ static int cb710_mmc_exit(struct platform_device *pdev)
tasklet_kill(&reader->finish_req_tasklet);
mmc_free_host(mmc);
- return 0;
}
static struct platform_driver cb710_mmc_driver = {
.driver.name = "cb710-mmc",
.probe = cb710_mmc_init,
- .remove = cb710_mmc_exit,
+ .remove_new = cb710_mmc_exit,
#ifdef CONFIG_PM
.suspend = cb710_mmc_suspend,
.resume = cb710_mmc_resume,
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 7138dfa065bf..ee3b1a4e0848 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -21,7 +21,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/interrupt.h>
@@ -1257,7 +1256,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev)
host->use_dma = use_dma;
host->mmc_irq = irq;
- host->sdio_irq = platform_get_irq(pdev, 1);
+ host->sdio_irq = platform_get_irq_optional(pdev, 1);
if (host->use_dma) {
ret = davinci_acquire_dma_channels(host);
@@ -1345,7 +1344,7 @@ ioremap_fail:
return ret;
}
-static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
+static void __exit davinci_mmcsd_remove(struct platform_device *pdev)
{
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
@@ -1354,8 +1353,6 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
davinci_release_dma_channels(host);
clk_disable_unprepare(host->clk);
mmc_free_host(host->mmc);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1402,7 +1399,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.of_match_table = davinci_mmc_dt_ids,
},
.probe = davinci_mmcsd_probe,
- .remove = __exit_p(davinci_mmcsd_remove),
+ .remove_new = __exit_p(davinci_mmcsd_remove),
.id_table = davinci_mmc_devtype,
};
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 9f20ac524c8b..698408e8bad0 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -664,15 +664,13 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
return 0;
}
-static int dw_mci_exynos_remove(struct platform_device *pdev)
+static void dw_mci_exynos_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
dw_mci_pltfm_remove(pdev);
-
- return 0;
}
static const struct dev_pm_ops dw_mci_exynos_pmops = {
@@ -685,7 +683,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = {
static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe,
- .remove = dw_mci_exynos_remove,
+ .remove_new = dw_mci_exynos_remove,
.driver = {
.name = "dwmmc_exynos",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c
index 6f22fe054087..e9470c50a348 100644
--- a/drivers/mmc/host/dw_mmc-hi3798cv200.c
+++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c
@@ -171,7 +171,7 @@ static int dw_mci_hi3798cv200_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, &hi3798cv200_data);
}
-static int dw_mci_hi3798cv200_remove(struct platform_device *pdev)
+static void dw_mci_hi3798cv200_remove(struct platform_device *pdev)
{
struct dw_mci *host = platform_get_drvdata(pdev);
struct hi3798cv200_priv *priv = host->priv;
@@ -180,8 +180,6 @@ static int dw_mci_hi3798cv200_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->sample_clk);
dw_mci_pltfm_remove(pdev);
-
- return 0;
}
static const struct of_device_id dw_mci_hi3798cv200_match[] = {
@@ -192,7 +190,7 @@ static const struct of_device_id dw_mci_hi3798cv200_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match);
static struct platform_driver dw_mci_hi3798cv200_driver = {
.probe = dw_mci_hi3798cv200_probe,
- .remove = dw_mci_hi3798cv200_remove,
+ .remove_new = dw_mci_hi3798cv200_remove,
.driver = {
.name = "dwmmc_hi3798cv200",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 2a99f15f527f..b07190ba4b7a 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -371,15 +371,13 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev)
return 0;
}
-static int dw_mci_rockchip_remove(struct platform_device *pdev)
+static void dw_mci_rockchip_remove(struct platform_device *pdev)
{
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
dw_mci_pltfm_remove(pdev);
-
- return 0;
}
static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
@@ -392,7 +390,7 @@ static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.probe = dw_mci_rockchip_probe,
- .remove = dw_mci_rockchip_remove,
+ .remove_new = dw_mci_rockchip_remove,
.driver = {
.name = "dwmmc_rockchip",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 1846a05210e3..f379ce5b582d 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -1163,7 +1163,7 @@ err_free_host:
return ret;
}
-static int jz4740_mmc_remove(struct platform_device *pdev)
+static void jz4740_mmc_remove(struct platform_device *pdev)
{
struct jz4740_mmc_host *host = platform_get_drvdata(pdev);
@@ -1179,8 +1179,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
jz4740_mmc_release_dma_channels(host);
mmc_free_host(host->mmc);
-
- return 0;
}
static int jz4740_mmc_suspend(struct device *dev)
@@ -1198,7 +1196,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
static struct platform_driver jz4740_mmc_driver = {
.probe = jz4740_mmc_probe,
- .remove = jz4740_mmc_remove,
+ .remove_new = jz4740_mmc_remove,
.driver = {
.name = "jz4740-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c
index 9af6b0902efe..4ec8072dc60b 100644
--- a/drivers/mmc/host/litex_mmc.c
+++ b/drivers/mmc/host/litex_mmc.c
@@ -629,12 +629,11 @@ static int litex_mmc_probe(struct platform_device *pdev)
return 0;
}
-static int litex_mmc_remove(struct platform_device *pdev)
+static void litex_mmc_remove(struct platform_device *pdev)
{
struct litex_mmc_host *host = platform_get_drvdata(pdev);
mmc_remove_host(host->mmc);
- return 0;
}
static const struct of_device_id litex_match[] = {
@@ -645,7 +644,7 @@ MODULE_DEVICE_TABLE(of, litex_match);
static struct platform_driver litex_mmc_driver = {
.probe = litex_mmc_probe,
- .remove = litex_mmc_remove,
+ .remove_new = litex_mmc_remove,
.driver = {
.name = "litex-mmc",
.of_match_table = litex_match,
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index ee9a25b900ae..9837dab096e6 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -11,7 +11,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iopoll.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/dma-mapping.h>
@@ -948,9 +948,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
return IRQ_NONE;
}
- if (WARN_ON(!host))
- return IRQ_NONE;
-
/* ack all raised interrupts */
writel(status, host->regs + SD_EMMC_STATUS);
@@ -1297,7 +1294,7 @@ err_init_clk:
return ret;
}
-static int meson_mmc_remove(struct platform_device *pdev)
+static void meson_mmc_remove(struct platform_device *pdev)
{
struct meson_host *host = dev_get_drvdata(&pdev->dev);
@@ -1308,8 +1305,6 @@ static int meson_mmc_remove(struct platform_device *pdev)
free_irq(host->irq, host);
clk_disable_unprepare(host->mmc_clk);
-
- return 0;
}
static const struct meson_mmc_data meson_gx_data = {
@@ -1340,7 +1335,7 @@ MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
static struct platform_driver meson_mmc_driver = {
.probe = meson_mmc_probe,
- .remove = meson_mmc_remove,
+ .remove_new = meson_mmc_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c
index 97168cdfa8e9..528ec8166e7c 100644
--- a/drivers/mmc/host/meson-mx-sdhc-mmc.c
+++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c
@@ -880,7 +880,7 @@ err_disable_pclk:
return ret;
}
-static int meson_mx_sdhc_remove(struct platform_device *pdev)
+static void meson_mx_sdhc_remove(struct platform_device *pdev)
{
struct meson_mx_sdhc_host *host = platform_get_drvdata(pdev);
@@ -889,8 +889,6 @@ static int meson_mx_sdhc_remove(struct platform_device *pdev)
meson_mx_sdhc_disable_clks(host->mmc);
clk_disable_unprepare(host->pclk);
-
- return 0;
}
static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8 = {
@@ -925,7 +923,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match);
static struct platform_driver meson_mx_sdhc_driver = {
.probe = meson_mx_sdhc_probe,
- .remove = meson_mx_sdhc_remove,
+ .remove_new = meson_mx_sdhc_remove,
.driver = {
.name = "meson-mx-sdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
index 3a19a05ef55a..a11577f2ee69 100644
--- a/drivers/mmc/host/meson-mx-sdio.c
+++ b/drivers/mmc/host/meson-mx-sdio.c
@@ -728,7 +728,7 @@ error_unregister_slot_pdev:
return ret;
}
-static int meson_mx_mmc_remove(struct platform_device *pdev)
+static void meson_mx_mmc_remove(struct platform_device *pdev)
{
struct meson_mx_mmc_host *host = platform_get_drvdata(pdev);
struct device *slot_dev = mmc_dev(host->mmc);
@@ -743,8 +743,6 @@ static int meson_mx_mmc_remove(struct platform_device *pdev)
clk_disable_unprepare(host->core_clk);
mmc_free_host(host->mmc);
-
- return 0;
}
static const struct of_device_id meson_mx_mmc_of_match[] = {
@@ -756,7 +754,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match);
static struct platform_driver meson_mx_mmc_driver = {
.probe = meson_mx_mmc_probe,
- .remove = meson_mx_mmc_remove,
+ .remove_new = meson_mx_mmc_remove,
.driver = {
.name = "meson-mx-sdio",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 769b34afa835..dda756a56379 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -764,7 +764,8 @@ static bool ux500_busy_complete(struct mmci_host *host, struct mmc_command *cmd,
}
retries--;
}
- dev_dbg(mmc_dev(host->mmc), "no busy signalling in time\n");
+ dev_dbg(mmc_dev(host->mmc),
+ "no busy signalling in time CMD%02x\n", cmd->opcode);
ux500_busy_clear_mask_done(host);
break;
@@ -786,7 +787,8 @@ static bool ux500_busy_complete(struct mmci_host *host, struct mmc_command *cmd,
host->busy_state = MMCI_BUSY_WAITING_FOR_END_IRQ;
} else {
dev_dbg(mmc_dev(host->mmc),
- "lost busy status when waiting for busy start IRQ\n");
+ "lost busy status when waiting for busy start IRQ CMD%02x\n",
+ cmd->opcode);
cancel_delayed_work(&host->ux500_busy_timeout_work);
ux500_busy_clear_mask_done(host);
}
@@ -800,13 +802,14 @@ static bool ux500_busy_complete(struct mmci_host *host, struct mmc_command *cmd,
ux500_busy_clear_mask_done(host);
} else {
dev_dbg(mmc_dev(host->mmc),
- "busy status still asserted when handling busy end IRQ - will keep waiting\n");
+ "busy status still asserted when handling busy end IRQ - will keep waiting CMD%02x\n",
+ cmd->opcode);
}
break;
default:
- dev_dbg(mmc_dev(host->mmc), "fell through on state %d\n",
- host->busy_state);
+ dev_dbg(mmc_dev(host->mmc), "fell through on state %d, CMD%02x\n",
+ host->busy_state, cmd->opcode);
break;
}
@@ -1533,6 +1536,20 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
}
}
+static char *ux500_state_str(struct mmci_host *host)
+{
+ switch (host->busy_state) {
+ case MMCI_BUSY_WAITING_FOR_START_IRQ:
+ return "waiting for start IRQ";
+ case MMCI_BUSY_WAITING_FOR_END_IRQ:
+ return "waiting for end IRQ";
+ case MMCI_BUSY_DONE:
+ return "not waiting for IRQs";
+ default:
+ return "unknown";
+ }
+}
+
/*
* This busy timeout worker is used to "kick" the command IRQ if a
* busy detect IRQ fails to appear in reasonable time. Only used on
@@ -1548,12 +1565,18 @@ static void ux500_busy_timeout_work(struct work_struct *work)
spin_lock_irqsave(&host->lock, flags);
if (host->cmd) {
- dev_dbg(mmc_dev(host->mmc), "timeout waiting for busy IRQ\n");
-
/* If we are still busy let's tag on a cmd-timeout error. */
status = readl(host->base + MMCISTATUS);
- if (status & host->variant->busy_detect_flag)
+ if (status & host->variant->busy_detect_flag) {
status |= MCI_CMDTIMEOUT;
+ dev_err(mmc_dev(host->mmc),
+ "timeout in state %s still busy with CMD%02x\n",
+ ux500_state_str(host), host->cmd->opcode);
+ } else {
+ dev_err(mmc_dev(host->mmc),
+ "timeout in state %s waiting for busy CMD%02x\n",
+ ux500_state_str(host), host->cmd->opcode);
+ }
mmci_cmd_irq(host, host->cmd, status);
}
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index d0d6ffcf78d4..5cfdd3a86e54 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -687,13 +687,11 @@ out_mmc:
return ret;
}
-static int moxart_remove(struct platform_device *pdev)
+static void moxart_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
struct moxart_host *host = mmc_priv(mmc);
- dev_set_drvdata(&pdev->dev, NULL);
-
if (!IS_ERR_OR_NULL(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx);
if (!IS_ERR_OR_NULL(host->dma_chan_rx))
@@ -705,8 +703,6 @@ static int moxart_remove(struct platform_device *pdev)
writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
host->base + REG_CLOCK_CONTROL);
mmc_free_host(mmc);
-
- return 0;
}
static const struct of_device_id moxart_mmc_match[] = {
@@ -718,7 +714,7 @@ MODULE_DEVICE_TABLE(of, moxart_mmc_match);
static struct platform_driver moxart_mmc_driver = {
.probe = moxart_probe,
- .remove = moxart_remove,
+ .remove_new = moxart_remove,
.driver = {
.name = "mmc-moxart",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 02403ff99e0d..5392200cfdf7 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -12,9 +12,7 @@
#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irq.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -2887,7 +2885,7 @@ host_free:
return ret;
}
-static int msdc_drv_remove(struct platform_device *pdev)
+static void msdc_drv_remove(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct msdc_host *host;
@@ -2911,8 +2909,6 @@ static int msdc_drv_remove(struct platform_device *pdev)
host->dma.bd, host->dma.bd_addr);
mmc_free_host(mmc);
-
- return 0;
}
static void msdc_save_reg(struct msdc_host *host)
@@ -3054,7 +3050,7 @@ static const struct dev_pm_ops msdc_dev_pm_ops = {
static struct platform_driver mt_msdc_driver = {
.probe = msdc_drv_probe,
- .remove = msdc_drv_remove,
+ .remove_new = msdc_drv_remove,
.driver = {
.name = "mtk-msdc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index b4f6a0a2fcb5..ca01b7d204ba 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -796,7 +796,7 @@ out:
return ret;
}
-static int mvsd_remove(struct platform_device *pdev)
+static void mvsd_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
@@ -809,8 +809,6 @@ static int mvsd_remove(struct platform_device *pdev)
if (!IS_ERR(host->clk))
clk_disable_unprepare(host->clk);
mmc_free_host(mmc);
-
- return 0;
}
static const struct of_device_id mvsdio_dt_ids[] = {
@@ -821,7 +819,7 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
static struct platform_driver mvsd_driver = {
.probe = mvsd_probe,
- .remove = mvsd_remove,
+ .remove_new = mvsd_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 668f865f3efb..5b3ab0e20505 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -31,7 +31,6 @@
#include <linux/dmaengine.h>
#include <linux/types.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/mmc/slot-gpio.h>
@@ -989,7 +988,6 @@ static int mxcmci_probe(struct platform_device *pdev)
pr_info("i.MX/MPC512x SDHC driver\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1000,7 +998,7 @@ static int mxcmci_probe(struct platform_device *pdev)
host = mmc_priv(mmc);
- host->base = devm_ioremap_resource(&pdev->dev, res);
+ host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out_free;
@@ -1164,7 +1162,7 @@ out_free:
return ret;
}
-static int mxcmci_remove(struct platform_device *pdev)
+static void mxcmci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct mxcmci_host *host = mmc_priv(mmc);
@@ -1181,8 +1179,6 @@ static int mxcmci_remove(struct platform_device *pdev)
clk_disable_unprepare(host->clk_ipg);
mmc_free_host(mmc);
-
- return 0;
}
static int mxcmci_suspend(struct device *dev)
@@ -1216,7 +1212,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe,
- .remove = mxcmci_remove,
+ .remove_new = mxcmci_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 8c3655d3be96..6751da9b60f9 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -674,7 +673,7 @@ out_mmc_free:
return ret;
}
-static int mxs_mmc_remove(struct platform_device *pdev)
+static void mxs_mmc_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct mxs_mmc_host *host = mmc_priv(mmc);
@@ -688,8 +687,6 @@ static int mxs_mmc_remove(struct platform_device *pdev)
clk_disable_unprepare(ssp->clk);
mmc_free_host(mmc);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -717,7 +714,7 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe,
- .remove = mxs_mmc_remove,
+ .remove_new = mxs_mmc_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 6a259563690d..9fb8995b43a1 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1506,7 +1506,7 @@ err_free_iclk:
return ret;
}
-static int mmc_omap_remove(struct platform_device *pdev)
+static void mmc_omap_remove(struct platform_device *pdev)
{
struct mmc_omap_host *host = platform_get_drvdata(pdev);
int i;
@@ -1532,8 +1532,6 @@ static int mmc_omap_remove(struct platform_device *pdev)
dma_release_channel(host->dma_rx);
destroy_workqueue(host->mmc_omap_wq);
-
- return 0;
}
#if IS_BUILTIN(CONFIG_OF)
@@ -1546,7 +1544,7 @@ MODULE_DEVICE_TABLE(of, mmc_omap_match);
static struct platform_driver mmc_omap_driver = {
.probe = mmc_omap_probe,
- .remove = mmc_omap_remove,
+ .remove_new = mmc_omap_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 1e0f2d7774bd..e120aeb869b8 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1790,14 +1790,11 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return -ENXIO;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -1982,7 +1979,7 @@ err:
return ret;
}
-static int omap_hsmmc_remove(struct platform_device *pdev)
+static void omap_hsmmc_remove(struct platform_device *pdev)
{
struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
@@ -2000,8 +1997,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
clk_disable_unprepare(host->dbclk);
mmc_free_host(host->mmc);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -2126,7 +2121,7 @@ static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
static struct platform_driver omap_hsmmc_driver = {
.probe = omap_hsmmc_probe,
- .remove = omap_hsmmc_remove,
+ .remove_new = omap_hsmmc_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c
index 1bf22b08b373..fc08f25c34eb 100644
--- a/drivers/mmc/host/owl-mmc.c
+++ b/drivers/mmc/host/owl-mmc.c
@@ -16,8 +16,9 @@
#include <linux/interrupt.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
@@ -667,7 +668,7 @@ err_free_host:
return ret;
}
-static int owl_mmc_remove(struct platform_device *pdev)
+static void owl_mmc_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct owl_mmc_host *owl_host = mmc_priv(mmc);
@@ -676,8 +677,6 @@ static int owl_mmc_remove(struct platform_device *pdev)
disable_irq(owl_host->irq);
dma_release_channel(owl_host->dma);
mmc_free_host(mmc);
-
- return 0;
}
static const struct of_device_id owl_mmc_of_match[] = {
@@ -693,7 +692,7 @@ static struct platform_driver owl_mmc_driver = {
.of_match_table = owl_mmc_of_match,
},
.probe = owl_mmc_probe,
- .remove = owl_mmc_remove,
+ .remove_new = owl_mmc_remove,
};
module_platform_driver(owl_mmc_driver);
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 2a988f942b6c..fae3192c3a14 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -30,7 +30,6 @@
#include <linux/gpio/consumer.h>
#include <linux/gfp.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/soc/pxa/cpu.h>
#include <linux/sizes.h>
@@ -612,7 +611,6 @@ static int pxamci_probe(struct platform_device *pdev)
struct resource *r;
int ret, irq;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -685,14 +683,14 @@ static int pxamci_probe(struct platform_device *pdev)
}
spin_lock_init(&host->lock);
- host->res = r;
host->imask = MMC_I_MASK_ALL;
- host->base = devm_ioremap_resource(dev, r);
+ host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out;
}
+ host->res = r;
/*
* Ensure that the host controller is shut down, and setup
@@ -784,7 +782,7 @@ out:
return ret;
}
-static int pxamci_remove(struct platform_device *pdev)
+static void pxamci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
@@ -808,13 +806,11 @@ static int pxamci_remove(struct platform_device *pdev)
mmc_free_host(mmc);
}
-
- return 0;
}
static struct platform_driver pxamci_driver = {
.probe = pxamci_probe,
- .remove = pxamci_remove,
+ .remove_new = pxamci_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 68da3da9e2e5..c1fb9740eab0 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -101,5 +101,5 @@ int renesas_sdhi_probe(struct platform_device *pdev,
const struct tmio_mmc_dma_ops *dma_ops,
const struct renesas_sdhi_of_data *of_data,
const struct renesas_sdhi_quirks *quirks);
-int renesas_sdhi_remove(struct platform_device *pdev);
+void renesas_sdhi_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 345934e4f59e..c675dec587ef 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -983,12 +983,12 @@ int renesas_sdhi_probe(struct platform_device *pdev,
}
- host->write16_hook = renesas_sdhi_write16_hook;
- host->clk_enable = renesas_sdhi_clk_enable;
- host->clk_disable = renesas_sdhi_clk_disable;
- host->set_clock = renesas_sdhi_set_clock;
- host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
- host->dma_ops = dma_ops;
+ host->write16_hook = renesas_sdhi_write16_hook;
+ host->clk_enable = renesas_sdhi_clk_enable;
+ host->clk_disable = renesas_sdhi_clk_disable;
+ host->set_clock = renesas_sdhi_set_clock;
+ host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
+ host->dma_ops = dma_ops;
if (sdhi_has_quirk(priv, hs400_disabled))
host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
@@ -1006,6 +1006,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
host->sdcard_irq_mask_all = TMIO_MASK_ALL_RCAR2;
host->reset = renesas_sdhi_reset;
+ } else {
+ host->sdcard_irq_mask_all = TMIO_MASK_ALL;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -1100,9 +1102,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.hs400_complete = renesas_sdhi_hs400_complete;
}
- ret = tmio_mmc_host_probe(host);
- if (ret < 0)
- goto edisclk;
+ sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all);
num_irqs = platform_irq_count(pdev);
if (num_irqs < 0) {
@@ -1129,6 +1129,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
goto eirq;
}
+ ret = tmio_mmc_host_probe(host);
+ if (ret < 0)
+ goto edisclk;
+
dev_info(&pdev->dev, "%s base at %pa, max clock rate %u MHz\n",
mmc_hostname(host->mmc), &res->start, host->mmc->f_max / 1000000);
@@ -1145,15 +1149,13 @@ efree:
}
EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
-int renesas_sdhi_remove(struct platform_device *pdev)
+void renesas_sdhi_remove(struct platform_device *pdev)
{
struct tmio_mmc_host *host = platform_get_drvdata(pdev);
tmio_mmc_host_remove(host);
renesas_sdhi_clk_disable(host);
tmio_mmc_host_free(host);
-
- return 0;
}
EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 9ab813903b2c..53d34c3eddce 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -15,7 +15,8 @@
#include <linux/mmc/host.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/sys_soc.h>
@@ -609,7 +610,7 @@ static struct platform_driver renesas_internal_dmac_sdhi_driver = {
.of_match_table = renesas_sdhi_internal_dmac_of_match,
},
.probe = renesas_sdhi_internal_dmac_probe,
- .remove = renesas_sdhi_remove,
+ .remove_new = renesas_sdhi_remove,
};
module_platform_driver(renesas_internal_dmac_sdhi_driver);
diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index b559ad38b667..9cf7f9feab72 100644
--- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -15,7 +15,8 @@
#include <linux/mmc/host.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/sys_soc.h>
@@ -470,7 +471,7 @@ static struct platform_driver renesas_sys_dmac_sdhi_driver = {
.of_match_table = renesas_sdhi_sys_dmac_of_match,
},
.probe = renesas_sdhi_sys_dmac_probe,
- .remove = renesas_sdhi_remove,
+ .remove_new = renesas_sdhi_remove,
};
module_platform_driver(renesas_sys_dmac_sdhi_driver);
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 8098726dcc0b..87d78432a1e0 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1523,15 +1523,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
return 0;
}
-static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
+static void rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
{
struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
struct rtsx_pcr *pcr;
struct mmc_host *mmc;
- if (!host)
- return 0;
-
pcr = host->pcr;
pcr->slots[RTSX_SD_CARD].p_dev = NULL;
pcr->slots[RTSX_SD_CARD].card_event = NULL;
@@ -1566,8 +1563,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
dev_dbg(&(pdev->dev),
": Realtek PCI-E SDMMC controller has been removed\n");
-
- return 0;
}
static const struct platform_device_id rtsx_pci_sdmmc_ids[] = {
@@ -1581,7 +1576,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids);
static struct platform_driver rtsx_pci_sdmmc_driver = {
.probe = rtsx_pci_sdmmc_drv_probe,
- .remove = rtsx_pci_sdmmc_drv_remove,
+ .remove_new = rtsx_pci_sdmmc_drv_remove,
.id_table = rtsx_pci_sdmmc_ids,
.driver = {
.name = DRV_NAME_RTSX_PCI_SDMMC,
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index 2c650cd58693..ded9b6849e35 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -1379,13 +1379,13 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
return 0;
}
-static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
+static void rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev);
struct mmc_host *mmc;
if (!host)
- return 0;
+ return;
mmc = host->mmc;
host->host_removal = true;
@@ -1415,8 +1415,6 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
dev_dbg(&(pdev->dev),
": Realtek USB SD/MMC module has been removed\n");
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1455,7 +1453,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
static struct platform_driver rtsx_usb_sdmmc_driver = {
.probe = rtsx_usb_sdmmc_drv_probe,
- .remove = rtsx_usb_sdmmc_drv_remove,
+ .remove_new = rtsx_usb_sdmmc_drv_remove,
.id_table = rtsx_usb_sdmmc_ids,
.driver = {
.name = "rtsx_usb_sdmmc",
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index edf2e6c14dc6..acf5fc3ad7e4 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -917,7 +917,7 @@ err_free:
return err;
}
-static int sdhci_acpi_remove(struct platform_device *pdev)
+static void sdhci_acpi_remove(struct platform_device *pdev)
{
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -939,8 +939,6 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
c->slot->free_slot(pdev);
sdhci_free_host(c->host);
-
- return 0;
}
static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed(
@@ -1033,7 +1031,7 @@ static struct platform_driver sdhci_acpi_driver = {
.pm = &sdhci_acpi_pm_ops,
},
.probe = sdhci_acpi_probe,
- .remove = sdhci_acpi_remove,
+ .remove_new = sdhci_acpi_remove,
};
module_platform_driver(sdhci_acpi_driver);
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index 6a93a54fe067..cb9152c6a65d 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -11,7 +11,6 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/mmc/slot-gpio.h>
#include "sdhci-pltfm.h"
@@ -311,6 +310,16 @@ err_pltfm_free:
return ret;
}
+static void sdhci_bcm_kona_remove(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct clk *clk = pltfm_host->clk;
+
+ sdhci_pltfm_remove(pdev);
+ clk_disable_unprepare(clk);
+}
+
static struct platform_driver sdhci_bcm_kona_driver = {
.driver = {
.name = "sdhci-kona",
@@ -319,7 +328,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {
.of_match_table = sdhci_bcm_kona_of_match,
},
.probe = sdhci_bcm_kona_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_bcm_kona_remove,
};
module_platform_driver(sdhci_bcm_kona_driver);
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index 4c22337199cf..c23251bb95f3 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -264,23 +264,17 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probe found match for %s\n", match->compatible);
- clk = devm_clk_get_optional(&pdev->dev, NULL);
+ clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
- "Failed to get clock from Device Tree\n");
-
- res = clk_prepare_enable(clk);
- if (res)
- return res;
+ "Failed to get and enable clock from Device Tree\n");
memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata));
brcmstb_pdata.ops = match_priv->ops;
host = sdhci_pltfm_init(pdev, &brcmstb_pdata,
sizeof(struct sdhci_brcmstb_priv));
- if (IS_ERR(host)) {
- res = PTR_ERR(host);
- goto err_clk;
- }
+ if (IS_ERR(host))
+ return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
@@ -369,9 +363,7 @@ add_host:
err:
sdhci_pltfm_free(pdev);
-err_clk:
clk_disable_unprepare(base_clk);
- clk_disable_unprepare(clk);
return res;
}
@@ -430,7 +422,7 @@ static struct platform_driver sdhci_brcmstb_driver = {
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
},
.probe = sdhci_brcmstb_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
.shutdown = sdhci_brcmstb_shutdown,
};
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index d2f625054689..be1505e8c536 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -11,7 +11,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include "sdhci-pltfm.h"
@@ -487,14 +487,10 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT;
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
-
data = of_device_get_match_data(dev);
if (!data)
data = &sdhci_cdns_drv_data;
@@ -502,10 +498,8 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
host = sdhci_pltfm_init(pdev, &data->pltfm_data,
struct_size(priv, phy_params, nr_phy_params));
- if (IS_ERR(host)) {
- ret = PTR_ERR(host);
- goto disable_clk;
- }
+ if (IS_ERR(host))
+ return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
@@ -556,9 +550,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
return 0;
free:
sdhci_pltfm_free(pdev);
-disable_clk:
- clk_disable_unprepare(clk);
-
return ret;
}
@@ -617,7 +608,7 @@ static struct platform_driver sdhci_cdns_driver = {
.of_match_table = sdhci_cdns_match,
},
.probe = sdhci_cdns_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_cdns_driver);
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 5e5bf82e5976..88ec23417808 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -75,10 +75,7 @@ static int sdhci_dove_probe(struct platform_device *pdev)
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
- pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
-
- if (!IS_ERR(pltfm_host->clk))
- clk_prepare_enable(pltfm_host->clk);
+ pltfm_host->clk = devm_clk_get_enabled(&pdev->dev, NULL);
ret = mmc_of_parse(host->mmc);
if (ret)
@@ -91,7 +88,6 @@ static int sdhci_dove_probe(struct platform_device *pdev)
return 0;
err_sdhci_add:
- clk_disable_unprepare(pltfm_host->clk);
sdhci_pltfm_free(pdev);
return ret;
}
@@ -110,7 +106,7 @@ static struct platform_driver sdhci_dove_driver = {
.of_match_table = sdhci_dove_of_match_table,
},
.probe = sdhci_dove_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_dove_driver);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index eebf94604a7f..3b8030f3552a 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -22,7 +22,7 @@
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include "sdhci-cqhci.h"
@@ -171,8 +171,8 @@
#define ESDHC_FLAG_HS400 BIT(9)
/*
* The IP has errata ERR010450
- * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't
- * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
+ * uSDHC: At 1.8V due to the I/O timing limit, for SDR mode, SD card
+ * clock can't exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
*/
#define ESDHC_FLAG_ERR010450 BIT(10)
/* The IP supports HS400ES mode */
@@ -961,7 +961,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) {
+ if ((imx_data->socdata->flags & ESDHC_FLAG_ERR010450) &&
+ (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V))) {
unsigned int max_clock;
max_clock = imx_data->is_ddr ? 45000000 : 150000000;
@@ -1802,7 +1803,7 @@ free_sdhci:
return err;
}
-static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
+static void sdhci_esdhc_imx_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1824,8 +1825,6 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
sdhci_pltfm_free(pdev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1986,7 +1985,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
.pm = &sdhci_esdhc_pmops,
},
.probe = sdhci_esdhc_imx_probe,
- .remove = sdhci_esdhc_imx_remove,
+ .remove_new = sdhci_esdhc_imx_remove,
};
module_platform_driver(sdhci_esdhc_imx_driver);
diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c
index 05926bf5ecf9..a07f8333cd6b 100644
--- a/drivers/mmc/host/sdhci-esdhc-mcf.c
+++ b/drivers/mmc/host/sdhci-esdhc-mcf.c
@@ -489,7 +489,7 @@ err_exit:
return err;
}
-static int sdhci_esdhc_mcf_remove(struct platform_device *pdev)
+static void sdhci_esdhc_mcf_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -502,8 +502,6 @@ static int sdhci_esdhc_mcf_remove(struct platform_device *pdev)
clk_disable_unprepare(mcf_data->clk_per);
sdhci_pltfm_free(pdev);
-
- return 0;
}
static struct platform_driver sdhci_esdhc_mcf_driver = {
@@ -512,7 +510,7 @@ static struct platform_driver sdhci_esdhc_mcf_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = sdhci_esdhc_mcf_probe,
- .remove = sdhci_esdhc_mcf_remove,
+ .remove_new = sdhci_esdhc_mcf_remove,
};
module_platform_driver(sdhci_esdhc_mcf_driver);
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index 86eb0045515e..10235fdff246 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/mmc/host.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include "sdhci-pltfm.h"
struct sdhci_iproc_data {
@@ -386,16 +386,11 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
host->mmc->caps |= iproc_host->data->mmc_caps;
if (dev->of_node) {
- pltfm_host->clk = devm_clk_get(dev, NULL);
+ pltfm_host->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
goto err;
}
- ret = clk_prepare_enable(pltfm_host->clk);
- if (ret) {
- dev_err(dev, "failed to enable host clk\n");
- goto err;
- }
}
if (iproc_host->data->missing_caps) {
@@ -406,13 +401,10 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
- goto err_clk;
+ goto err;
return 0;
-err_clk:
- if (dev->of_node)
- clk_disable_unprepare(pltfm_host->clk);
err:
sdhci_pltfm_free(pdev);
return ret;
@@ -432,7 +424,7 @@ static struct platform_driver sdhci_iproc_driver = {
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_iproc_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
.shutdown = sdhci_iproc_shutdown,
};
module_platform_driver(sdhci_iproc_driver);
diff --git a/drivers/mmc/host/sdhci-milbeaut.c b/drivers/mmc/host/sdhci-milbeaut.c
index 148b37ac6564..83706edc9796 100644
--- a/drivers/mmc/host/sdhci-milbeaut.c
+++ b/drivers/mmc/host/sdhci-milbeaut.c
@@ -313,7 +313,7 @@ err:
return ret;
}
-static int sdhci_milbeaut_remove(struct platform_device *pdev)
+static void sdhci_milbeaut_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct f_sdhost_priv *priv = sdhci_priv(host);
@@ -326,18 +326,16 @@ static int sdhci_milbeaut_remove(struct platform_device *pdev)
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
-
- return 0;
}
static struct platform_driver sdhci_milbeaut_driver = {
.driver = {
.name = "sdhci-milbeaut",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(mlb_dt_ids),
+ .of_match_table = mlb_dt_ids,
},
.probe = sdhci_milbeaut_probe,
- .remove = sdhci_milbeaut_remove,
+ .remove_new = sdhci_milbeaut_remove,
};
module_platform_driver(sdhci_milbeaut_driver);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 1c935b5bafe1..668e0aceeeba 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/mmc/mmc.h>
#include <linux/pm_runtime.h>
@@ -15,6 +14,7 @@
#include <linux/iopoll.h>
#include <linux/regulator/consumer.h>
#include <linux/interconnect.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
@@ -2668,7 +2668,7 @@ pltfm_free:
return ret;
}
-static int sdhci_msm_remove(struct platform_device *pdev)
+static void sdhci_msm_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -2687,7 +2687,6 @@ static int sdhci_msm_remove(struct platform_device *pdev)
if (!IS_ERR(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
sdhci_pltfm_free(pdev);
- return 0;
}
static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
@@ -2740,7 +2739,7 @@ static const struct dev_pm_ops sdhci_msm_pm_ops = {
static struct platform_driver sdhci_msm_driver = {
.probe = sdhci_msm_probe,
- .remove = sdhci_msm_remove,
+ .remove_new = sdhci_msm_remove,
.driver = {
.name = "sdhci_msm",
.of_match_table = sdhci_msm_dt_match,
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 294dd605fd2b..5edd024347bd 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -18,11 +18,11 @@
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
-#include <linux/of.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include "cqhci.h"
@@ -2016,12 +2016,13 @@ err_pltfm_free:
return ret;
}
-static int sdhci_arasan_remove(struct platform_device *pdev)
+static void sdhci_arasan_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
struct clk *clk_ahb = sdhci_arasan->clk_ahb;
+ struct clk *clk_xin = pltfm_host->clk;
if (!IS_ERR(sdhci_arasan->phy)) {
if (sdhci_arasan->is_phy_on)
@@ -2031,11 +2032,10 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
sdhci_arasan_unregister_sdclk(&pdev->dev);
- sdhci_pltfm_unregister(pdev);
+ sdhci_pltfm_remove(pdev);
+ clk_disable_unprepare(clk_xin);
clk_disable_unprepare(clk_ahb);
-
- return 0;
}
static struct platform_driver sdhci_arasan_driver = {
@@ -2046,7 +2046,7 @@ static struct platform_driver sdhci_arasan_driver = {
.pm = &sdhci_arasan_dev_pm_ops,
},
.probe = sdhci_arasan_probe,
- .remove = sdhci_arasan_remove,
+ .remove_new = sdhci_arasan_remove,
};
module_platform_driver(sdhci_arasan_driver);
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
index 25b4073f698b..42d54532cabe 100644
--- a/drivers/mmc/host/sdhci-of-aspeed.c
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -450,22 +450,19 @@ err_pltfm_free:
return ret;
}
-static int aspeed_sdhci_remove(struct platform_device *pdev)
+static void aspeed_sdhci_remove(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_host *host;
- int dead = 0;
host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
- sdhci_remove_host(host, dead);
+ sdhci_remove_host(host, 0);
clk_disable_unprepare(pltfm_host->clk);
sdhci_pltfm_free(pdev);
-
- return 0;
}
static const struct aspeed_sdhci_pdata ast2400_sdhci_pdata = {
@@ -521,7 +518,7 @@ static struct platform_driver aspeed_sdhci_driver = {
.of_match_table = aspeed_sdhci_of_match,
},
.probe = aspeed_sdhci_probe,
- .remove = aspeed_sdhci_remove,
+ .remove_new = aspeed_sdhci_remove,
};
static int aspeed_sdc_probe(struct platform_device *pdev)
@@ -574,13 +571,11 @@ err_clk:
return ret;
}
-static int aspeed_sdc_remove(struct platform_device *pdev)
+static void aspeed_sdc_remove(struct platform_device *pdev)
{
struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
clk_disable_unprepare(sdc->clk);
-
- return 0;
}
static const struct of_device_id aspeed_sdc_of_match[] = {
@@ -600,7 +595,7 @@ static struct platform_driver aspeed_sdc_driver = {
.of_match_table = aspeed_sdc_of_match,
},
.probe = aspeed_sdc_probe,
- .remove = aspeed_sdc_remove,
+ .remove_new = aspeed_sdc_remove,
};
#if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index cd0134580a90..23a9faad2ff8 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -17,7 +17,7 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -443,7 +443,7 @@ sdhci_pltfm_free:
return ret;
}
-static int sdhci_at91_remove(struct platform_device *pdev)
+static void sdhci_at91_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -456,13 +456,11 @@ static int sdhci_at91_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
- sdhci_pltfm_unregister(pdev);
+ sdhci_pltfm_remove(pdev);
clk_disable_unprepare(gck);
clk_disable_unprepare(hclock);
clk_disable_unprepare(mainck);
-
- return 0;
}
static struct platform_driver sdhci_at91_driver = {
@@ -473,7 +471,7 @@ static struct platform_driver sdhci_at91_driver = {
.pm = &sdhci_at91_dev_pm_ops,
},
.probe = sdhci_at91_probe,
- .remove = sdhci_at91_remove,
+ .remove_new = sdhci_at91_remove,
};
module_platform_driver(sdhci_at91_driver);
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index e68cd87998c8..3a3bae6948a8 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -14,7 +14,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/sizes.h>
@@ -548,9 +549,13 @@ static int dwcmshc_probe(struct platform_device *pdev)
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
err = sdhci_setup_host(host);
if (err)
- goto err_clk;
+ goto err_rpm;
if (rk_priv)
dwcmshc_rk35xx_postinit(host, priv);
@@ -559,10 +564,15 @@ static int dwcmshc_probe(struct platform_device *pdev)
if (err)
goto err_setup_host;
+ pm_runtime_put(dev);
+
return 0;
err_setup_host:
sdhci_cleanup_host(host);
+err_rpm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
err_clk:
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(priv->bus_clk);
@@ -574,7 +584,7 @@ free_pltfm:
return err;
}
-static int dwcmshc_remove(struct platform_device *pdev)
+static void dwcmshc_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -589,8 +599,6 @@ static int dwcmshc_remove(struct platform_device *pdev)
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
sdhci_pltfm_free(pdev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -602,6 +610,8 @@ static int dwcmshc_suspend(struct device *dev)
struct rk35xx_priv *rk_priv = priv->priv;
int ret;
+ pm_runtime_resume(dev);
+
ret = sdhci_suspend_host(host);
if (ret)
return ret;
@@ -632,21 +642,84 @@ static int dwcmshc_resume(struct device *dev)
if (!IS_ERR(priv->bus_clk)) {
ret = clk_prepare_enable(priv->bus_clk);
if (ret)
- return ret;
+ goto disable_clk;
}
if (rk_priv) {
ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS,
rk_priv->rockchip_clks);
if (ret)
- return ret;
+ goto disable_bus_clk;
}
- return sdhci_resume_host(host);
+ ret = sdhci_resume_host(host);
+ if (ret)
+ goto disable_rockchip_clks;
+
+ return 0;
+
+disable_rockchip_clks:
+ if (rk_priv)
+ clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
+ rk_priv->rockchip_clks);
+disable_bus_clk:
+ if (!IS_ERR(priv->bus_clk))
+ clk_disable_unprepare(priv->bus_clk);
+disable_clk:
+ clk_disable_unprepare(pltfm_host->clk);
+ return ret;
}
#endif
-static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
+#ifdef CONFIG_PM
+
+static void dwcmshc_enable_card_clk(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if ((ctrl & SDHCI_CLOCK_INT_EN) && !(ctrl & SDHCI_CLOCK_CARD_EN)) {
+ ctrl |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+ }
+}
+
+static void dwcmshc_disable_card_clk(struct sdhci_host *host)
+{
+ u16 ctrl;
+
+ ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if (ctrl & SDHCI_CLOCK_CARD_EN) {
+ ctrl &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);
+ }
+}
+
+static int dwcmshc_runtime_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ dwcmshc_disable_card_clk(host);
+
+ return 0;
+}
+
+static int dwcmshc_runtime_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ dwcmshc_enable_card_clk(host);
+
+ return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops dwcmshc_pmops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume)
+ SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend,
+ dwcmshc_runtime_resume, NULL)
+};
static struct platform_driver sdhci_dwcmshc_driver = {
.driver = {
@@ -657,7 +730,7 @@ static struct platform_driver sdhci_dwcmshc_driver = {
.pm = &dwcmshc_pmops,
},
.probe = dwcmshc_probe,
- .remove = dwcmshc_remove,
+ .remove_new = dwcmshc_remove,
};
module_platform_driver(sdhci_dwcmshc_driver);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 48ca1cf15b19..3ae9aa25745a 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -1521,7 +1521,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.pm = &esdhc_of_dev_pm_ops,
},
.probe = sdhci_esdhc_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_esdhc_driver);
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 12675797b296..9c1c0ce610ef 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -68,7 +68,7 @@ static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
static int sdhci_hlwd_probe(struct platform_device *pdev)
{
- return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0);
+ return sdhci_pltfm_init_and_add_host(pdev, &sdhci_hlwd_pdata, 0);
}
static const struct of_device_id sdhci_hlwd_of_match[] = {
@@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = {
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_hlwd_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_hlwd_driver);
diff --git a/drivers/mmc/host/sdhci-of-sparx5.c b/drivers/mmc/host/sdhci-of-sparx5.c
index 28e4ee69e100..64b77e7d14cd 100644
--- a/drivers/mmc/host/sdhci-of-sparx5.c
+++ b/drivers/mmc/host/sdhci-of-sparx5.c
@@ -13,9 +13,9 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include "sdhci-pltfm.h"
@@ -184,15 +184,12 @@ static int sdhci_sparx5_probe(struct platform_device *pdev)
sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
sdhci_sparx5->host = host;
- pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
+ pltfm_host->clk = devm_clk_get_enabled(&pdev->dev, "core");
if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk);
- dev_err(&pdev->dev, "failed to get core clk: %d\n", ret);
+ dev_err(&pdev->dev, "failed to get and enable core clk: %d\n", ret);
goto free_pltfm;
}
- ret = clk_prepare_enable(pltfm_host->clk);
- if (ret)
- goto free_pltfm;
if (!of_property_read_u32(np, "microchip,clock-delay", &value) &&
(value > 0 && value <= MSHC_DLY_CC_MAX))
@@ -202,13 +199,13 @@ static int sdhci_sparx5_probe(struct platform_device *pdev)
ret = mmc_of_parse(host->mmc);
if (ret)
- goto err_clk;
+ goto free_pltfm;
sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon);
if (IS_ERR(sdhci_sparx5->cpu_ctrl)) {
dev_err(&pdev->dev, "No CPU syscon regmap !\n");
ret = PTR_ERR(sdhci_sparx5->cpu_ctrl);
- goto err_clk;
+ goto free_pltfm;
}
if (sdhci_sparx5->delay_clock >= 0)
@@ -225,7 +222,7 @@ static int sdhci_sparx5_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
- goto err_clk;
+ goto free_pltfm;
/* Set AXI bus master to use un-cached access (for DMA) */
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) &&
@@ -239,8 +236,6 @@ static int sdhci_sparx5_probe(struct platform_device *pdev)
return ret;
-err_clk:
- clk_disable_unprepare(pltfm_host->clk);
free_pltfm:
sdhci_pltfm_free(pdev);
return ret;
@@ -260,7 +255,7 @@ static struct platform_driver sdhci_sparx5_driver = {
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_sparx5_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_sparx5_driver);
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 8ed9256b83da..1e0bc7bace1b 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -11,7 +11,6 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -1394,7 +1393,7 @@ err_pltfm_free:
return ret;
}
-static int sdhci_omap_remove(struct platform_device *pdev)
+static void sdhci_omap_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev);
@@ -1408,8 +1407,6 @@ static int sdhci_omap_remove(struct platform_device *pdev)
/* Ensure device gets disabled despite userspace sysfs config */
pm_runtime_force_suspend(dev);
sdhci_pltfm_free(pdev);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1478,7 +1475,7 @@ static const struct dev_pm_ops sdhci_omap_dev_pm_ops = {
static struct platform_driver sdhci_omap_driver = {
.probe = sdhci_omap_probe,
- .remove = sdhci_omap_remove,
+ .remove_new = sdhci_omap_remove,
.driver = {
.name = "sdhci-omap",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 1c2572c0f012..7c14feb5db77 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1898,6 +1898,10 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(O2, SDS1, o2),
SDHCI_PCI_DEVICE(O2, SEABIRD0, o2),
SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
+ SDHCI_PCI_DEVICE(O2, GG8_9860, o2),
+ SDHCI_PCI_DEVICE(O2, GG8_9861, o2),
+ SDHCI_PCI_DEVICE(O2, GG8_9862, o2),
+ SDHCI_PCI_DEVICE(O2, GG8_9863, o2),
SDHCI_PCI_DEVICE(ARASAN, PHY_EMMC, arasan),
SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps),
SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index 620f52ad9667..7bfee28116af 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -21,6 +21,7 @@
* O2Micro device registers
*/
+#define O2_SD_PCIE_SWITCH 0x54
#define O2_SD_MISC_REG5 0x64
#define O2_SD_LD0_CTRL 0x68
#define O2_SD_DEV_CTRL 0x88
@@ -36,6 +37,7 @@
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
#define O2_SD_MISC_CTRL 0x1C0
+#define O2_SD_EXP_INT_REG 0x1E0
#define O2_SD_PWR_FORCE_L0 0x0002
#define O2_SD_TUNING_CTRL 0x300
#define O2_SD_PLL_SETTING 0x304
@@ -49,6 +51,9 @@
#define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0
#define O2_SD_FUNC_REG4 0x3E4
+#define O2_SD_PARA_SET_REG1 0x444
+#define O2_SD_VDDX_CTRL_REG 0x508
+#define O2_SD_GPIO_CTRL_REG1 0x510
#define O2_SD_LED_ENABLE BIT(6)
#define O2_SD_FREG0_LEDOFF BIT(13)
#define O2_SD_SEL_DLL BIT(16)
@@ -334,33 +339,45 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
scratch |= O2_SD_PWR_FORCE_L0;
sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
- /* Stop clk */
- reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- reg_val &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
-
- if ((host->timing == MMC_TIMING_MMC_HS200) ||
- (host->timing == MMC_TIMING_UHS_SDR104)) {
- /* UnLock WP */
- pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
- scratch_8 &= 0x7f;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
-
- /* Set pcr 0x354[16] to choose dll clock, and set the default phase */
- pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &reg_val);
- reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
- reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE);
- pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val);
+ /* Update output phase */
+ switch (chip->pdev->device) {
+ case PCI_DEVICE_ID_O2_SDS0:
+ case PCI_DEVICE_ID_O2_SEABIRD0:
+ case PCI_DEVICE_ID_O2_SEABIRD1:
+ case PCI_DEVICE_ID_O2_SDS1:
+ case PCI_DEVICE_ID_O2_FUJIN2:
+ /* Stop clk */
+ reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ reg_val &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
+
+ if (host->timing == MMC_TIMING_MMC_HS200 ||
+ host->timing == MMC_TIMING_UHS_SDR104) {
+ /* UnLock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
+ scratch_8 &= 0x7f;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
+
+ /* Set pcr 0x354[16] to choose dll clock, and set the default phase */
+ pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &reg_val);
+ reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
+ reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE);
+ pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val);
+
+ /* Lock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
+ scratch_8 |= 0x80;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
+ }
- /* Lock WP */
- pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
- scratch_8 |= 0x80;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
+ /* Start clk */
+ reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ reg_val |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
+ break;
+ default:
+ break;
}
- /* Start clk */
- reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- reg_val |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
/* wait DLL lock, timeout value 5ms */
if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
@@ -563,6 +580,7 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
u16 clk;
u8 scratch;
u32 scratch_32;
+ u32 dmdn_208m, dmdn_200m;
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct sdhci_pci_chip *chip = slot->chip;
@@ -578,16 +596,27 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
scratch &= 0x7f;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+ if (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9860 ||
+ chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9861 ||
+ chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9862 ||
+ chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9863) {
+ dmdn_208m = 0x2c500000;
+ dmdn_200m = 0x25200000;
+ } else {
+ dmdn_208m = 0x2c280000;
+ dmdn_200m = 0x25100000;
+ }
+
if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32);
- if ((scratch_32 & 0xFFFF0000) != 0x2c280000)
- o2_pci_set_baseclk(chip, 0x2c280000);
+ if ((scratch_32 & 0xFFFF0000) != dmdn_208m)
+ o2_pci_set_baseclk(chip, dmdn_208m);
} else {
pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32);
- if ((scratch_32 & 0xFFFF0000) != 0x25100000)
- o2_pci_set_baseclk(chip, 0x25100000);
+ if ((scratch_32 & 0xFFFF0000) != dmdn_200m)
+ o2_pci_set_baseclk(chip, dmdn_200m);
}
pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
@@ -603,6 +632,67 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_o2_enable_clk(host, clk);
}
+static int sdhci_pci_o2_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ struct sdhci_pci_chip *chip = slot->chip;
+ u8 scratch8;
+ u16 scratch16;
+ int ret;
+
+ /* Disable clock */
+ sdhci_writeb(host, 0, SDHCI_CLOCK_CONTROL);
+
+ /* Set VDD2 voltage*/
+ scratch8 = sdhci_readb(host, SDHCI_POWER_CONTROL);
+ scratch8 &= 0x0F;
+ if (host->mmc->ios.timing == MMC_TIMING_SD_EXP_1_2V &&
+ host->mmc->caps2 & MMC_CAP2_SD_EXP_1_2V) {
+ scratch8 |= SDHCI_VDD2_POWER_ON | SDHCI_VDD2_POWER_120;
+ } else {
+ scratch8 |= SDHCI_VDD2_POWER_ON | SDHCI_VDD2_POWER_180;
+ }
+
+ sdhci_writeb(host, scratch8, SDHCI_POWER_CONTROL);
+
+ /* UnLock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch8);
+ scratch8 &= 0x7f;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch8);
+
+ /* Wait for express card clkreqn assert */
+ ret = read_poll_timeout(sdhci_readb, scratch8, !(scratch8 & BIT(0)),
+ 1, 30000, false, host, O2_SD_EXP_INT_REG);
+
+ if (!ret) {
+ /* Switch to PCIe mode */
+ scratch16 = sdhci_readw(host, O2_SD_PCIE_SWITCH);
+ scratch16 |= BIT(8);
+ sdhci_writew(host, scratch16, O2_SD_PCIE_SWITCH);
+ } else {
+ /* Power off VDD2 voltage*/
+ scratch8 = sdhci_readb(host, SDHCI_POWER_CONTROL);
+ scratch8 &= 0x0F;
+ sdhci_writeb(host, scratch8, SDHCI_POWER_CONTROL);
+
+ /* Keep mode as UHSI */
+ pci_read_config_word(chip->pdev, O2_SD_PARA_SET_REG1, &scratch16);
+ scratch16 &= ~BIT(11);
+ pci_write_config_word(chip->pdev, O2_SD_PARA_SET_REG1, scratch16);
+
+ host->mmc->ios.timing = MMC_TIMING_LEGACY;
+ pr_info("%s: Express card initialization failed, falling back to Legacy\n",
+ mmc_hostname(host->mmc));
+ }
+ /* Lock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch8);
+ scratch8 |= 0x80;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch8);
+
+ return 0;
+}
+
static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{
struct sdhci_pci_chip *chip;
@@ -624,6 +714,11 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
if (caps & SDHCI_CAN_DO_8BIT)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+ host->quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50;
+
+ sdhci_pci_o2_enable_msi(chip, host);
+
+ host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
switch (chip->pdev->device) {
case PCI_DEVICE_ID_O2_SDS0:
case PCI_DEVICE_ID_O2_SEABIRD0:
@@ -634,10 +729,6 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
if (reg & 0x1)
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
- host->quirks2 |= SDHCI_QUIRK2_BROKEN_DDR50;
-
- sdhci_pci_o2_enable_msi(chip, host);
-
if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) {
ret = pci_read_config_dword(chip->pdev,
O2_SD_MISC_SETTING, &reg);
@@ -663,15 +754,22 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
}
- host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
-
if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
break;
/* set dll watch dog timer */
reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2);
reg |= (1 << 12);
sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2);
-
+ break;
+ case PCI_DEVICE_ID_O2_GG8_9860:
+ case PCI_DEVICE_ID_O2_GG8_9861:
+ case PCI_DEVICE_ID_O2_GG8_9862:
+ case PCI_DEVICE_ID_O2_GG8_9863:
+ host->mmc->caps2 |= MMC_CAP2_NO_SDIO | MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
+ host->mmc->caps |= MMC_CAP_HW_RESET;
+ host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
+ slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
+ host->mmc_host_ops.init_sd_express = sdhci_pci_o2_init_sd_express;
break;
default:
break;
@@ -684,6 +782,7 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
{
int ret;
u8 scratch;
+ u16 scratch16;
u32 scratch_32;
switch (chip->pdev->device) {
@@ -893,6 +992,46 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
scratch |= 0x80;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
break;
+ case PCI_DEVICE_ID_O2_GG8_9860:
+ case PCI_DEVICE_ID_O2_GG8_9861:
+ case PCI_DEVICE_ID_O2_GG8_9862:
+ case PCI_DEVICE_ID_O2_GG8_9863:
+ /* UnLock WP */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+ if (ret)
+ return ret;
+ scratch &= 0x7f;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+
+ /* Select mode switch source as software control */
+ pci_read_config_word(chip->pdev, O2_SD_PARA_SET_REG1, &scratch16);
+ scratch16 &= 0xF8FF;
+ scratch16 |= BIT(9);
+ pci_write_config_word(chip->pdev, O2_SD_PARA_SET_REG1, scratch16);
+
+ /* set VDD1 supply source */
+ pci_read_config_word(chip->pdev, O2_SD_VDDX_CTRL_REG, &scratch16);
+ scratch16 &= 0xFFE3;
+ scratch16 |= BIT(3);
+ pci_write_config_word(chip->pdev, O2_SD_VDDX_CTRL_REG, scratch16);
+
+ /* Set host drive strength*/
+ scratch16 = 0x0025;
+ pci_write_config_word(chip->pdev, O2_SD_PLL_SETTING, scratch16);
+
+ /* Set output delay*/
+ pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
+ scratch_32 &= 0xFF0FFF00;
+ scratch_32 |= 0x00B0003B;
+ pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32);
+
+ /* Lock WP */
+ ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+ if (ret)
+ return ret;
+ scratch |= 0x80;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+ break;
}
return 0;
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 9c8863956381..153704f812ed 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -11,6 +11,10 @@
#define PCI_DEVICE_ID_O2_FUJIN2 0x8520
#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620
#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621
+#define PCI_DEVICE_ID_O2_GG8_9860 0x9860
+#define PCI_DEVICE_ID_O2_GG8_9861 0x9861
+#define PCI_DEVICE_ID_O2_GG8_9862 0x9862
+#define PCI_DEVICE_ID_O2_GG8_9863 0x9863
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c
index 6696b6bdd88e..7a0351a9c74e 100644
--- a/drivers/mmc/host/sdhci-pic32.c
+++ b/drivers/mmc/host/sdhci-pic32.c
@@ -210,7 +210,7 @@ err:
return ret;
}
-static int pic32_sdhci_remove(struct platform_device *pdev)
+static void pic32_sdhci_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host);
@@ -221,8 +221,6 @@ static int pic32_sdhci_remove(struct platform_device *pdev)
clk_disable_unprepare(sdhci_pdata->base_clk);
clk_disable_unprepare(sdhci_pdata->sys_clk);
sdhci_pltfm_free(pdev);
-
- return 0;
}
static const struct of_device_id pic32_sdhci_id_table[] = {
@@ -238,7 +236,7 @@ static struct platform_driver pic32_sdhci_driver = {
.of_match_table = of_match_ptr(pic32_sdhci_id_table),
},
.probe = pic32_sdhci_probe,
- .remove = pic32_sdhci_remove,
+ .remove_new = pic32_sdhci_remove,
};
module_platform_driver(pic32_sdhci_driver);
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 673e750a8490..a72e123a585d 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -166,9 +166,9 @@ void sdhci_pltfm_free(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
-int sdhci_pltfm_register(struct platform_device *pdev,
- const struct sdhci_pltfm_data *pdata,
- size_t priv_size)
+int sdhci_pltfm_init_and_add_host(struct platform_device *pdev,
+ const struct sdhci_pltfm_data *pdata,
+ size_t priv_size)
{
struct sdhci_host *host;
int ret = 0;
@@ -185,21 +185,17 @@ int sdhci_pltfm_register(struct platform_device *pdev,
return ret;
}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
+EXPORT_SYMBOL_GPL(sdhci_pltfm_init_and_add_host);
-int sdhci_pltfm_unregister(struct platform_device *pdev)
+void sdhci_pltfm_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
- clk_disable_unprepare(pltfm_host->clk);
sdhci_pltfm_free(pdev);
-
- return 0;
}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
+EXPORT_SYMBOL_GPL(sdhci_pltfm_remove);
#ifdef CONFIG_PM_SLEEP
int sdhci_pltfm_suspend(struct device *dev)
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 9bd717ff784b..b81d5b0fd616 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -99,10 +99,10 @@ extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
size_t priv_size);
extern void sdhci_pltfm_free(struct platform_device *pdev);
-extern int sdhci_pltfm_register(struct platform_device *pdev,
- const struct sdhci_pltfm_data *pdata,
- size_t priv_size);
-extern int sdhci_pltfm_unregister(struct platform_device *pdev);
+extern int sdhci_pltfm_init_and_add_host(struct platform_device *pdev,
+ const struct sdhci_pltfm_data *pdata,
+ size_t priv_size);
+extern void sdhci_pltfm_remove(struct platform_device *pdev);
extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index 91aca8f8d6ef..b75cbea88b40 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -19,7 +19,6 @@
#include <linux/platform_data/pxa_sdhci.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/mmc.h>
#include <linux/pinctrl/consumer.h>
@@ -269,26 +268,21 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
pxav2_host = sdhci_pltfm_priv(pltfm_host);
- clk = devm_clk_get(dev, "io");
- if (IS_ERR(clk) && PTR_ERR(clk) != -EPROBE_DEFER)
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_optional_enabled(dev, "io");
+ if (!clk)
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err_probe(dev, ret, "failed to get io clock\n");
goto free;
}
pltfm_host->clk = clk;
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(dev, "failed to enable io clock\n");
- goto free;
- }
clk_core = devm_clk_get_optional_enabled(dev, "core");
if (IS_ERR(clk_core)) {
ret = PTR_ERR(clk_core);
dev_err_probe(dev, ret, "failed to enable core clock\n");
- goto disable_clk;
+ goto free;
}
host->quirks = SDHCI_QUIRK_BROKEN_ADMA
@@ -340,12 +334,10 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret)
- goto disable_clk;
+ goto free;
return 0;
-disable_clk:
- clk_disable_unprepare(clk);
free:
sdhci_pltfm_free(pdev);
return ret;
@@ -359,7 +351,7 @@ static struct platform_driver sdhci_pxav2_driver = {
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_pxav2_probe,
- .remove = sdhci_pltfm_unregister,
+ .remove_new = sdhci_pltfm_remove,
};
module_platform_driver(sdhci_pxav2_driver);
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index e39dcc998772..3af43ac05825 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -470,7 +470,7 @@ err_clk_get:
return ret;
}
-static int sdhci_pxav3_remove(struct platform_device *pdev)
+static void sdhci_pxav3_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -486,8 +486,6 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
clk_disable_unprepare(pxa->clk_core);
sdhci_pltfm_free(pdev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -570,7 +568,7 @@ static struct platform_driver sdhci_pxav3_driver = {
.pm = &sdhci_pxav3_pmops,
},
.probe = sdhci_pxav3_probe,
- .remove = sdhci_pxav3_remove,
+ .remove_new = sdhci_pxav3_remove,
};
module_platform_driver(sdhci_pxav3_driver);
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 504015e84308..0e8a8ac14e56 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -20,7 +20,6 @@
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -668,7 +667,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
return ret;
}
-static int sdhci_s3c_remove(struct platform_device *pdev)
+static void sdhci_s3c_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_s3c *sc = sdhci_priv(host);
@@ -688,8 +687,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
sdhci_free_host(host);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -776,7 +773,7 @@ MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
static struct platform_driver sdhci_s3c_driver = {
.probe = sdhci_s3c_probe,
- .remove = sdhci_s3c_remove,
+ .remove_new = sdhci_s3c_remove,
.id_table = sdhci_s3c_driver_ids,
.driver = {
.name = "s3c-sdhci",
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index c79035727b20..c81bdfa97b89 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -117,7 +117,7 @@ err:
return ret;
}
-static int sdhci_remove(struct platform_device *pdev)
+static void sdhci_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct spear_sdhci *sdhci = sdhci_priv(host);
@@ -131,8 +131,6 @@ static int sdhci_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead);
clk_disable_unprepare(sdhci->clk);
sdhci_free_host(host);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -170,23 +168,21 @@ static int sdhci_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
-#ifdef CONFIG_OF
static const struct of_device_id sdhci_spear_id_table[] = {
{ .compatible = "st,spear300-sdhci" },
{}
};
MODULE_DEVICE_TABLE(of, sdhci_spear_id_table);
-#endif
static struct platform_driver sdhci_driver = {
.driver = {
.name = "sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_pm_ops,
- .of_match_table = of_match_ptr(sdhci_spear_id_table),
+ .of_match_table = sdhci_spear_id_table,
},
.probe = sdhci_probe,
- .remove = sdhci_remove,
+ .remove_new = sdhci_remove,
};
module_platform_driver(sdhci_driver);
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 7f4ee2e12735..649ae075e229 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -9,9 +9,10 @@
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/iopoll.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -73,6 +74,11 @@
#define SDHCI_SPRD_CLK_DEF_RATE 26000000
#define SDHCI_SPRD_PHY_DLL_CLK 52000000
+#define SDHCI_SPRD_MAX_RANGE 0xff
+#define SDHCI_SPRD_CMD_DLY_MASK GENMASK(15, 8)
+#define SDHCI_SPRD_POSRD_DLY_MASK GENMASK(23, 16)
+#define SDHCI_SPRD_CPST_EN GENMASK(27, 24)
+
struct sdhci_sprd_host {
u32 version;
struct clk *clk_sdio;
@@ -86,6 +92,11 @@ struct sdhci_sprd_host {
u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
};
+enum sdhci_sprd_tuning_type {
+ SDHCI_SPRD_TUNING_SD_HS_CMD,
+ SDHCI_SPRD_TUNING_SD_HS_DATA,
+};
+
struct sdhci_sprd_phy_cfg {
const char *property;
u8 timing;
@@ -533,6 +544,138 @@ static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
SDHCI_SPRD_REG_32_DLL_DLY);
}
+static int mmc_send_tuning_cmd(struct mmc_card *card)
+{
+ return mmc_send_status(card, NULL);
+}
+
+static int mmc_send_tuning_data(struct mmc_card *card)
+{
+ u8 *status;
+ int ret;
+
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status)
+ return -ENOMEM;
+
+ ret = mmc_sd_switch(card, 0, 0, 0, status);
+
+ kfree(status);
+
+ return ret;
+}
+
+static int sdhci_sprd_get_best_clk_sample(struct mmc_host *mmc, u8 *value)
+{
+ int range_end = SDHCI_SPRD_MAX_RANGE;
+ int range_length = 0;
+ int middle_range = 0;
+ int count = 0;
+ int i;
+
+ for (i = 0; i <= SDHCI_SPRD_MAX_RANGE; i++) {
+ if (value[i]) {
+ pr_debug("%s: tuning ok: %d\n", mmc_hostname(mmc), i);
+ count++;
+ } else {
+ pr_debug("%s: tuning fail: %d\n", mmc_hostname(mmc), i);
+ if (range_length < count) {
+ range_length = count;
+ range_end = i - 1;
+ count = 0;
+ }
+ }
+ }
+
+ if (!count)
+ return -EIO;
+
+ if (count > range_length) {
+ range_length = count;
+ range_end = i - 1;
+ }
+
+ middle_range = range_end - (range_length - 1) / 2;
+
+ return middle_range;
+}
+
+static int sdhci_sprd_tuning(struct mmc_host *mmc, struct mmc_card *card,
+ enum sdhci_sprd_tuning_type type)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ u32 *p = sprd_host->phy_delay;
+ u32 dll_cfg, dll_dly;
+ int best_clk_sample;
+ int err = 0;
+ u8 *value;
+ int i;
+
+ value = kmalloc(SDHCI_SPRD_MAX_RANGE + 1, GFP_KERNEL);
+ if (!value)
+ return -ENOMEM;
+
+ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ dll_cfg = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG);
+ dll_cfg &= ~SDHCI_SPRD_CPST_EN;
+ sdhci_writel(host, dll_cfg, SDHCI_SPRD_REG_32_DLL_CFG);
+
+ dll_dly = p[mmc->ios.timing];
+
+ for (i = 0; i <= SDHCI_SPRD_MAX_RANGE; i++) {
+ if (type == SDHCI_SPRD_TUNING_SD_HS_CMD) {
+ dll_dly &= ~SDHCI_SPRD_CMD_DLY_MASK;
+ dll_dly |= ((i << 8) & SDHCI_SPRD_CMD_DLY_MASK);
+ } else {
+ dll_dly &= ~SDHCI_SPRD_POSRD_DLY_MASK;
+ dll_dly |= ((i << 16) & SDHCI_SPRD_POSRD_DLY_MASK);
+ }
+
+ sdhci_writel(host, dll_dly, SDHCI_SPRD_REG_32_DLL_DLY);
+
+ if (type == SDHCI_SPRD_TUNING_SD_HS_CMD)
+ value[i] = !mmc_send_tuning_cmd(card);
+ else
+ value[i] = !mmc_send_tuning_data(card);
+ }
+
+ best_clk_sample = sdhci_sprd_get_best_clk_sample(mmc, value);
+ if (best_clk_sample < 0) {
+ dev_err(mmc_dev(host->mmc), "all tuning phase fail!\n");
+ goto out;
+ }
+
+ if (type == SDHCI_SPRD_TUNING_SD_HS_CMD) {
+ p[mmc->ios.timing] &= ~SDHCI_SPRD_CMD_DLY_MASK;
+ p[mmc->ios.timing] |= ((best_clk_sample << 8) & SDHCI_SPRD_CMD_DLY_MASK);
+ } else {
+ p[mmc->ios.timing] &= ~(SDHCI_SPRD_POSRD_DLY_MASK);
+ p[mmc->ios.timing] |= ((best_clk_sample << 16) & SDHCI_SPRD_POSRD_DLY_MASK);
+ }
+
+ pr_debug("%s: the best clk sample %d, delay value 0x%08x\n",
+ mmc_hostname(host->mmc), best_clk_sample, p[mmc->ios.timing]);
+
+out:
+ sdhci_writel(host, p[mmc->ios.timing], SDHCI_SPRD_REG_32_DLL_DLY);
+
+ kfree(value);
+
+ return err;
+}
+
+static int sdhci_sprd_prepare_sd_hs_cmd_tuning(struct mmc_host *mmc, struct mmc_card *card)
+{
+ return sdhci_sprd_tuning(mmc, card, SDHCI_SPRD_TUNING_SD_HS_CMD);
+}
+
+static int sdhci_sprd_execute_sd_hs_data_tuning(struct mmc_host *mmc, struct mmc_card *card)
+{
+ return sdhci_sprd_tuning(mmc, card, SDHCI_SPRD_TUNING_SD_HS_DATA);
+}
+
static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
struct device_node *np)
{
@@ -577,6 +720,11 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
host->mmc_host_ops.request = sdhci_sprd_request;
host->mmc_host_ops.hs400_enhanced_strobe =
sdhci_sprd_hs400_enhanced_strobe;
+ host->mmc_host_ops.prepare_sd_hs_tuning =
+ sdhci_sprd_prepare_sd_hs_cmd_tuning;
+ host->mmc_host_ops.execute_sd_hs_tuning =
+ sdhci_sprd_execute_sd_hs_data_tuning;
+
/*
* We can not use the standard ops to change and detect the voltage
* signal for Spreadtrum SD host controller, since our voltage regulator
@@ -720,7 +868,7 @@ pltfm_free:
return ret;
}
-static int sdhci_sprd_remove(struct platform_device *pdev)
+static void sdhci_sprd_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
@@ -732,8 +880,6 @@ static int sdhci_sprd_remove(struct platform_device *pdev)
clk_disable_unprepare(sprd_host->clk_2x_enable);
sdhci_pltfm_free(pdev);
-
- return 0;
}
static const struct of_device_id sdhci_sprd_of_match[] = {
@@ -800,7 +946,7 @@ static const struct dev_pm_ops sdhci_sprd_pm_ops = {
static struct platform_driver sdhci_sprd_driver = {
.probe = sdhci_sprd_probe,
- .remove = sdhci_sprd_remove,
+ .remove_new = sdhci_sprd_remove,
.driver = {
.name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
index 6415916fbd91..d12532b96b51 100644
--- a/drivers/mmc/host/sdhci-st.c
+++ b/drivers/mmc/host/sdhci-st.c
@@ -348,7 +348,6 @@ static int sdhci_st_probe(struct platform_device *pdev)
struct clk *clk, *icnclk;
int ret = 0;
u16 host_version;
- struct resource *res;
struct reset_control *rstc;
clk = devm_clk_get(&pdev->dev, "mmc");
@@ -397,9 +396,7 @@ static int sdhci_st_probe(struct platform_device *pdev)
}
/* Configure the FlashSS Top registers for setting eMMC TX/RX delay */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "top-mmc-delay");
- pdata->top_ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ pdata->top_ioaddr = devm_platform_ioremap_resource_byname(pdev, "top-mmc-delay");
if (IS_ERR(pdata->top_ioaddr))
pdata->top_ioaddr = NULL;
@@ -434,20 +431,20 @@ err_pltfm_init:
return ret;
}
-static int sdhci_st_remove(struct platform_device *pdev)
+static void sdhci_st_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
struct reset_control *rstc = pdata->rstc;
+ struct clk *clk = pltfm_host->clk;
- sdhci_pltfm_unregister(pdev);
+ sdhci_pltfm_remove(pdev);
clk_disable_unprepare(pdata->icnclk);
+ clk_disable_unprepare(clk);
reset_control_assert(rstc);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -510,7 +507,7 @@ MODULE_DEVICE_TABLE(of, st_sdhci_match);
static struct platform_driver sdhci_st_driver = {
.probe = sdhci_st_probe,
- .remove = sdhci_st_remove,
+ .remove_new = sdhci_st_remove,
.driver = {
.name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index bff084f178c9..1ad0a6b3a2eb 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -19,7 +19,6 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -1818,7 +1817,7 @@ err_parse_dt:
return rc;
}
-static int sdhci_tegra_remove(struct platform_device *pdev)
+static void sdhci_tegra_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -1834,8 +1833,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
clk_disable_unprepare(tegra_host->tmclk);
sdhci_pltfm_free(pdev);
-
- return 0;
}
static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev)
@@ -1933,7 +1930,7 @@ static struct platform_driver sdhci_tegra_driver = {
.pm = &sdhci_tegra_dev_pm_ops,
},
.probe = sdhci_tegra_probe,
- .remove = sdhci_tegra_remove,
+ .remove_new = sdhci_tegra_remove,
};
module_platform_driver(sdhci_tegra_driver);
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 08e838400b52..25ba7aecc3be 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -578,7 +578,7 @@ free_pltfm:
return err;
}
-static int xenon_remove(struct platform_device *pdev)
+static void xenon_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -595,8 +595,6 @@ static int xenon_remove(struct platform_device *pdev)
clk_disable_unprepare(pltfm_host->clk);
sdhci_pltfm_free(pdev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -705,7 +703,7 @@ static struct platform_driver sdhci_xenon_driver = {
.pm = &sdhci_xenon_dev_pm_ops,
},
.probe = xenon_probe,
- .remove = xenon_remove,
+ .remove_new = xenon_remove,
};
module_platform_driver(sdhci_xenon_driver);
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 7cdf0f54e3a5..c125485ba80e 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -866,22 +866,22 @@ err_pltfm_free:
return ret;
}
-static int sdhci_am654_remove(struct platform_device *pdev)
+static void sdhci_am654_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct device *dev = &pdev->dev;
int ret;
- ret = pm_runtime_resume_and_get(&pdev->dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
- return ret;
+ dev_err(dev, "pm_runtime_get_sync() Failed\n");
sdhci_remove_host(host, true);
clk_disable_unprepare(pltfm_host->clk);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
sdhci_pltfm_free(pdev);
- return 0;
}
#ifdef CONFIG_PM
@@ -993,7 +993,7 @@ static struct platform_driver sdhci_am654_driver = {
.of_match_table = sdhci_am654_of_match,
},
.probe = sdhci_am654_probe,
- .remove = sdhci_am654_remove,
+ .remove_new = sdhci_am654_remove,
};
module_platform_driver(sdhci_am654_driver);
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c
index 3215063bcf86..c58e7cb1e2a7 100644
--- a/drivers/mmc/host/sdhci_f_sdh30.c
+++ b/drivers/mmc/host/sdhci_f_sdh30.c
@@ -206,7 +206,7 @@ err:
return ret;
}
-static int sdhci_f_sdh30_remove(struct platform_device *pdev)
+static void sdhci_f_sdh30_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host);
@@ -214,13 +214,11 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
struct reset_control *rst = priv->rst;
struct clk *clk = priv->clk;
- sdhci_pltfm_unregister(pdev);
+ sdhci_pltfm_remove(pdev);
reset_control_assert(rst);
clk_disable_unprepare(clk);
clk_disable_unprepare(clk_iface);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -248,8 +246,8 @@ static struct platform_driver sdhci_f_sdh30_driver = {
.acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids),
.pm = &sdhci_pltfm_pmops,
},
- .probe = sdhci_f_sdh30_probe,
- .remove = sdhci_f_sdh30_remove,
+ .probe = sdhci_f_sdh30_probe,
+ .remove_new = sdhci_f_sdh30_remove,
};
module_platform_driver(sdhci_f_sdh30_driver);
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 5cf53348372a..077d711e964e 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -46,7 +46,6 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/pagemap.h>
#include <linux/platform_data/sh_mmcif.h>
#include <linux/platform_device.h>
@@ -1509,7 +1508,7 @@ err_host:
return ret;
}
-static int sh_mmcif_remove(struct platform_device *pdev)
+static void sh_mmcif_remove(struct platform_device *pdev)
{
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
@@ -1533,8 +1532,6 @@ static int sh_mmcif_remove(struct platform_device *pdev)
mmc_free_host(host->mmc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1561,7 +1558,7 @@ static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
static struct platform_driver sh_mmcif_driver = {
.probe = sh_mmcif_probe,
- .remove = sh_mmcif_remove,
+ .remove_new = sh_mmcif_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/sunplus-mmc.c b/drivers/mmc/host/sunplus-mmc.c
index 2bdebeb1f8e4..13c7cc0b6180 100644
--- a/drivers/mmc/host/sunplus-mmc.c
+++ b/drivers/mmc/host/sunplus-mmc.c
@@ -885,7 +885,7 @@ static int spmmc_drv_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(host->rstc), "rst get fail\n");
host->irq = platform_get_irq(pdev, 0);
- if (host->irq <= 0)
+ if (host->irq < 0)
return host->irq;
ret = devm_request_threaded_irq(&pdev->dev, host->irq,
@@ -939,7 +939,7 @@ clk_disable:
return ret;
}
-static int spmmc_drv_remove(struct platform_device *dev)
+static void spmmc_drv_remove(struct platform_device *dev)
{
struct spmmc_host *host = platform_get_drvdata(dev);
@@ -948,9 +948,6 @@ static int spmmc_drv_remove(struct platform_device *dev)
clk_disable_unprepare(host->clk);
pm_runtime_put_noidle(&dev->dev);
pm_runtime_disable(&dev->dev);
- platform_set_drvdata(dev, NULL);
-
- return 0;
}
static int spmmc_pm_runtime_suspend(struct device *dev)
@@ -985,7 +982,7 @@ MODULE_DEVICE_TABLE(of, spmmc_of_table);
static struct platform_driver spmmc_driver = {
.probe = spmmc_drv_probe,
- .remove = spmmc_drv_remove,
+ .remove_new = spmmc_drv_remove,
.driver = {
.name = "spmmc",
.pm = pm_ptr(&spmmc_pm_ops),
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 69dcb8805e05..d3bd0ac99ec4 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -1486,7 +1486,7 @@ error_free_host:
return ret;
}
-static int sunxi_mmc_remove(struct platform_device *pdev)
+static void sunxi_mmc_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct sunxi_mmc_host *host = mmc_priv(mmc);
@@ -1499,8 +1499,6 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
}
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
mmc_free_host(mmc);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1556,7 +1554,7 @@ static struct platform_driver sunxi_mmc_driver = {
.pm = &sunxi_mmc_pm_ops,
},
.probe = sunxi_mmc_probe,
- .remove = sunxi_mmc_remove,
+ .remove_new = sunxi_mmc_remove,
};
module_platform_driver(sunxi_mmc_driver);
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
index 61acd69fac0e..1404989e6151 100644
--- a/drivers/mmc/host/uniphier-sd.c
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -13,7 +13,6 @@
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -706,19 +705,19 @@ static int uniphier_sd_probe(struct platform_device *pdev)
tmio_data->max_segs = 1;
tmio_data->max_blk_count = U16_MAX;
- ret = tmio_mmc_host_probe(host);
- if (ret)
- goto disable_clk;
+ sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_ALL);
ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED,
dev_name(dev), host);
if (ret)
- goto remove_host;
+ goto disable_clk;
+
+ ret = tmio_mmc_host_probe(host);
+ if (ret)
+ goto disable_clk;
return 0;
-remove_host:
- tmio_mmc_host_remove(host);
disable_clk:
uniphier_sd_clk_disable(host);
free_host:
@@ -727,15 +726,13 @@ free_host:
return ret;
}
-static int uniphier_sd_remove(struct platform_device *pdev)
+static void uniphier_sd_remove(struct platform_device *pdev)
{
struct tmio_mmc_host *host = platform_get_drvdata(pdev);
tmio_mmc_host_remove(host);
uniphier_sd_clk_disable(host);
tmio_mmc_host_free(host);
-
- return 0;
}
static const struct of_device_id uniphier_sd_match[] = {
@@ -757,7 +754,7 @@ MODULE_DEVICE_TABLE(of, uniphier_sd_match);
static struct platform_driver uniphier_sd_driver = {
.probe = uniphier_sd_probe,
- .remove = uniphier_sd_remove,
+ .remove_new = uniphier_sd_remove,
.driver = {
.name = "uniphier-sd",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
index 2e17903658fc..6e421445d56c 100644
--- a/drivers/mmc/host/usdhi6rol0.c
+++ b/drivers/mmc/host/usdhi6rol0.c
@@ -1884,7 +1884,7 @@ e_free_mmc:
return ret;
}
-static int usdhi6_remove(struct platform_device *pdev)
+static void usdhi6_remove(struct platform_device *pdev)
{
struct usdhi6_host *host = platform_get_drvdata(pdev);
@@ -1895,13 +1895,11 @@ static int usdhi6_remove(struct platform_device *pdev)
usdhi6_dma_release(host);
clk_disable_unprepare(host->clk);
mmc_free_host(host->mmc);
-
- return 0;
}
static struct platform_driver usdhi6_driver = {
.probe = usdhi6_probe,
- .remove = usdhi6_remove,
+ .remove_new = usdhi6_remove,
.driver = {
.name = "usdhi6rol0",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index a2b0d9461665..ba6044b16e07 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -1160,7 +1160,6 @@ static int via_sd_probe(struct pci_dev *pcidev,
unmap:
iounmap(sdhost->mmiobase);
free_mmc_host:
- dev_set_drvdata(&pcidev->dev, NULL);
mmc_free_host(mmc);
release:
pci_release_regions(pcidev);
@@ -1212,7 +1211,6 @@ static void via_sd_remove(struct pci_dev *pcidev)
writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
iounmap(sdhost->mmiobase);
- dev_set_drvdata(&pcidev->dev, NULL);
mmc_free_host(sdhost->mmc);
pci_release_regions(pcidev);
pci_disable_device(pcidev);
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index bf2a92fba0ed..001a468bc149 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1264,8 +1264,6 @@ static void wbsd_free_mmc(struct device *dev)
del_timer_sync(&host->ignore_timer);
mmc_free_host(mmc);
-
- dev_set_drvdata(dev, NULL);
}
/*
@@ -1756,11 +1754,9 @@ static int wbsd_probe(struct platform_device *dev)
return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0);
}
-static int wbsd_remove(struct platform_device *dev)
+static void wbsd_remove(struct platform_device *dev)
{
wbsd_shutdown(&dev->dev, 0);
-
- return 0;
}
/*
@@ -1902,8 +1898,7 @@ static struct platform_device *wbsd_device;
static struct platform_driver wbsd_driver = {
.probe = wbsd_probe,
- .remove = wbsd_remove,
-
+ .remove_new = wbsd_remove,
.suspend = wbsd_platform_suspend,
.resume = wbsd_platform_resume,
.driver = {
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
index 68525d900046..77d5f1d24489 100644
--- a/drivers/mmc/host/wmt-sdmmc.c
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -21,7 +21,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
@@ -880,7 +879,7 @@ fail1:
return ret;
}
-static int wmt_mci_remove(struct platform_device *pdev)
+static void wmt_mci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct wmt_mci_priv *priv;
@@ -918,8 +917,6 @@ static int wmt_mci_remove(struct platform_device *pdev)
mmc_free_host(mmc);
dev_info(&pdev->dev, "WMT MCI device removed\n");
-
- return 0;
}
#ifdef CONFIG_PM
@@ -989,7 +986,7 @@ static const struct dev_pm_ops wmt_mci_pm = {
static struct platform_driver wmt_mci_driver = {
.probe = wmt_mci_probe,
- .remove = wmt_mci_remove,
+ .remove_new = wmt_mci_remove,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 368c6f5b327e..44eeb5d61ba9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -332,6 +332,28 @@ config NETCONSOLE_DYNAMIC
at runtime through a userspace interface exported using configfs.
See <file:Documentation/networking/netconsole.rst> for details.
+config NETCONSOLE_EXTENDED_LOG
+ bool "Set kernel extended message by default"
+ depends on NETCONSOLE
+ default n
+ help
+ Set extended log support for netconsole message. If this option is
+ set, log messages are transmitted with extended metadata header in a
+ format similar to /dev/kmsg. See
+ <file:Documentation/networking/netconsole.rst> for details.
+
+config NETCONSOLE_PREPEND_RELEASE
+ bool "Prepend kernel release version in the message by default"
+ depends on NETCONSOLE_EXTENDED_LOG
+ default n
+ help
+ Set kernel release to be prepended to each netconsole message by
+ default. If this option is set, the kernel release is prepended into
+ the first field of every netconsole message, so, the netconsole
+ server/peer can easily identify what kernel release is logging each
+ message. See <file:Documentation/networking/netconsole.rst> for
+ details.
+
config NETPOLL
def_bool NETCONSOLE
@@ -571,6 +593,7 @@ config VMXNET3
tristate "VMware VMXNET3 ethernet driver"
depends on PCI && INET
depends on PAGE_SIZE_LESS_THAN_64KB
+ select PAGE_POOL
help
This driver supports VMware's vmxnet3 virtual ethernet NIC.
To compile this driver as a module, choose M here: the
@@ -592,6 +615,7 @@ config NETDEVSIM
depends on INET
depends on IPV6 || IPV6=n
depends on PSAMPLE || PSAMPLE=n
+ depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n
select NET_DEVLINK
help
This driver is a developer testing tool and software model that can
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 99265667538c..d9e052c49ba1 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -464,7 +464,7 @@ static void arcnet_reply_tasklet(struct tasklet_struct *t)
ret = sock_queue_err_skb(sk, ackskb);
if (ret)
- kfree_skb(ackskb);
+ dev_kfree_skb_irq(ackskb);
local_irq_enable();
};
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index b9dbad3a8af8..dc2c7b979656 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -660,15 +660,15 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
return NULL;
arp = (struct arp_pkt *)skb_network_header(skb);
- /* Don't modify or load balance ARPs that do not originate locally
- * (e.g.,arrive via a bridge).
+ /* Don't modify or load balance ARPs that do not originate
+ * from the bond itself or a VLAN directly above the bond.
*/
- if (!bond_slave_has_mac_rx(bond, arp->mac_src))
+ if (!bond_slave_has_mac_rcu(bond, arp->mac_src))
return NULL;
dev = ip_dev_find(dev_net(bond->dev), arp->ip_src);
if (dev) {
- if (netif_is_bridge_master(dev)) {
+ if (netif_is_any_bridge_master(dev)) {
dev_put(dev);
return NULL;
}
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 594094526648..b19492a7f6ad 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -49,9 +49,6 @@ DEFINE_SHOW_ATTRIBUTE(bond_debug_rlb_hash);
void bond_debug_register(struct bonding *bond)
{
- if (!bonding_debug_root)
- return;
-
bond->debug_dir =
debugfs_create_dir(bond->dev->name, bonding_debug_root);
@@ -61,9 +58,6 @@ void bond_debug_register(struct bonding *bond)
void bond_debug_unregister(struct bonding *bond)
{
- if (!bonding_debug_root)
- return;
-
debugfs_remove_recursive(bond->debug_dir);
}
@@ -71,9 +65,6 @@ void bond_debug_reregister(struct bonding *bond)
{
struct dentry *d;
- if (!bonding_debug_root)
- return;
-
d = debugfs_rename(bonding_debug_root, bond->debug_dir,
bonding_debug_root, bond->dev->name);
if (!IS_ERR(d)) {
@@ -84,11 +75,11 @@ void bond_debug_reregister(struct bonding *bond)
}
}
-void bond_create_debugfs(void)
+void __init bond_create_debugfs(void)
{
bonding_debug_root = debugfs_create_dir("bonding", NULL);
- if (!bonding_debug_root)
+ if (IS_ERR(bonding_debug_root))
pr_warn("Warning: Cannot create bonding directory in debugfs\n");
}
@@ -113,7 +104,7 @@ void bond_debug_reregister(struct bonding *bond)
{
}
-void bond_create_debugfs(void)
+void __init bond_create_debugfs(void)
{
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 447b06ea4fc9..ed7212e61c54 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -90,6 +90,7 @@
#include <net/tls.h>
#endif
#include <net/ip6_route.h>
+#include <net/xdp.h>
#include "bonding_priv.h"
@@ -4446,11 +4447,6 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
{
struct bonding *bond = netdev_priv(bond_dev);
struct mii_ioctl_data *mii = NULL;
- const struct net_device_ops *ops;
- struct net_device *real_dev;
- struct hwtstamp_config cfg;
- struct ifreq ifrr;
- int res = 0;
netdev_dbg(bond_dev, "bond_eth_ioctl: cmd=%d\n", cmd);
@@ -4477,44 +4473,11 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
}
break;
- case SIOCSHWTSTAMP:
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- if (!(cfg.flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX))
- return -EOPNOTSUPP;
-
- fallthrough;
- case SIOCGHWTSTAMP:
- real_dev = bond_option_active_slave_get_rcu(bond);
- if (!real_dev)
- return -EOPNOTSUPP;
-
- strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
- ifrr.ifr_ifru = ifr->ifr_ifru;
-
- ops = real_dev->netdev_ops;
- if (netif_device_present(real_dev) && ops->ndo_eth_ioctl) {
- res = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
- if (res)
- return res;
-
- ifr->ifr_ifru = ifrr.ifr_ifru;
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- /* Set the BOND_PHC_INDEX flag to notify user space */
- cfg.flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;
-
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ?
- -EFAULT : 0;
- }
- fallthrough;
default:
- res = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
- return res;
+ return 0;
}
static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)
@@ -5083,19 +5046,7 @@ static void bond_set_slave_arr(struct bonding *bond,
static void bond_reset_slave_arr(struct bonding *bond)
{
- struct bond_up_slave *usable, *all;
-
- usable = rtnl_dereference(bond->usable_slaves);
- if (usable) {
- RCU_INIT_POINTER(bond->usable_slaves, NULL);
- kfree_rcu(usable, rcu);
- }
-
- all = rtnl_dereference(bond->all_slaves);
- if (all) {
- RCU_INIT_POINTER(bond->all_slaves, NULL);
- kfree_rcu(all, rcu);
- }
+ bond_set_slave_arr(bond, NULL, NULL);
}
/* Build the usable slaves array in control path for modes that use xmit-hash
@@ -5688,6 +5639,67 @@ static u32 bond_mode_bcast_speed(struct slave *slave, u32 speed)
return speed;
}
+/* Set the BOND_PHC_INDEX flag to notify user space */
+static int bond_set_phc_index_flag(struct kernel_hwtstamp_config *kernel_cfg)
+{
+ struct ifreq *ifr = kernel_cfg->ifr;
+ struct hwtstamp_config cfg;
+
+ if (kernel_cfg->copied_to_user) {
+ /* Lower device has a legacy implementation */
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ cfg.flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;
+ if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
+ return -EFAULT;
+ } else {
+ kernel_cfg->flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX;
+ }
+
+ return 0;
+}
+
+static int bond_hwtstamp_get(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg)
+{
+ struct bonding *bond = netdev_priv(dev);
+ struct net_device *real_dev;
+ int err;
+
+ real_dev = bond_option_active_slave_get_rcu(bond);
+ if (!real_dev)
+ return -EOPNOTSUPP;
+
+ err = generic_hwtstamp_get_lower(real_dev, cfg);
+ if (err)
+ return err;
+
+ return bond_set_phc_index_flag(cfg);
+}
+
+static int bond_hwtstamp_set(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct bonding *bond = netdev_priv(dev);
+ struct net_device *real_dev;
+ int err;
+
+ if (!(cfg->flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX))
+ return -EOPNOTSUPP;
+
+ real_dev = bond_option_active_slave_get_rcu(bond);
+ if (!real_dev)
+ return -EOPNOTSUPP;
+
+ err = generic_hwtstamp_set_lower(real_dev, cfg, extack);
+ if (err)
+ return err;
+
+ return bond_set_phc_index_flag(cfg);
+}
+
static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
struct ethtool_link_ksettings *cmd)
{
@@ -5706,6 +5718,7 @@ static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
*/
bond_for_each_slave(bond, slave, iter) {
if (bond_slave_can_tx(slave)) {
+ bond_update_speed_duplex(slave);
if (slave->speed != SPEED_UNKNOWN) {
if (BOND_MODE(bond) == BOND_MODE_BROADCAST)
speed = bond_mode_bcast_speed(slave,
@@ -5836,6 +5849,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_bpf = bond_xdp,
.ndo_xdp_xmit = bond_xdp_xmit,
.ndo_xdp_get_xmit_slave = bond_xdp_get_xmit_slave,
+ .ndo_hwtstamp_get = bond_hwtstamp_get,
+ .ndo_hwtstamp_set = bond_hwtstamp_set,
};
static const struct device_type bond_type = {
@@ -5849,8 +5864,7 @@ static void bond_destructor(struct net_device *bond_dev)
if (bond->wq)
destroy_workqueue(bond->wq);
- if (bond->rr_tx_counter)
- free_percpu(bond->rr_tx_counter);
+ free_percpu(bond->rr_tx_counter);
}
void bond_setup(struct net_device *bond_dev)
@@ -5925,7 +5939,6 @@ void bond_setup(struct net_device *bond_dev)
static void bond_uninit(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct bond_up_slave *usable, *all;
struct list_head *iter;
struct slave *slave;
@@ -5936,17 +5949,7 @@ static void bond_uninit(struct net_device *bond_dev)
__bond_release_one(bond_dev, slave->dev, true, true);
netdev_info(bond_dev, "Released all slaves\n");
- usable = rtnl_dereference(bond->usable_slaves);
- if (usable) {
- RCU_INIT_POINTER(bond->usable_slaves, NULL);
- kfree_rcu(usable, rcu);
- }
-
- all = rtnl_dereference(bond->all_slaves);
- if (all) {
- RCU_INIT_POINTER(bond->all_slaves, NULL);
- kfree_rcu(all, rcu);
- }
+ bond_set_slave_arr(bond, NULL, NULL);
list_del(&bond->bond_list);
@@ -5955,7 +5958,7 @@ static void bond_uninit(struct net_device *bond_dev)
/*------------------------- Module initialization ---------------------------*/
-static int bond_check_params(struct bond_params *params)
+static int __init bond_check_params(struct bond_params *params)
{
int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
struct bond_opt_value newval;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 0bb59da24922..2805135a7205 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -803,7 +803,7 @@ static const struct attribute_group bonding_group = {
/* Initialize sysfs. This sets up the bonding_masters file in
* /sys/class/net.
*/
-int bond_create_sysfs(struct bond_net *bn)
+int __net_init bond_create_sysfs(struct bond_net *bn)
{
int ret;
@@ -836,7 +836,7 @@ int bond_create_sysfs(struct bond_net *bn)
}
/* Remove /sys/class/net/bonding_masters. */
-void bond_destroy_sysfs(struct bond_net *bn)
+void __net_exit bond_destroy_sysfs(struct bond_net *bn)
{
netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net);
}
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index a5c5036dfb94..649453a3c858 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -160,8 +160,13 @@ config CAN_KVASER_PCIEFD
Kvaser PCIEcan 4xHS
Kvaser PCIEcan 2xHS v2
Kvaser PCIEcan HS v2
+ Kvaser PCIEcan 1xCAN v3
+ Kvaser PCIEcan 2xCAN v3
+ Kvaser PCIEcan 4xCAN v2
Kvaser Mini PCI Express HS v2
Kvaser Mini PCI Express 2xHS v2
+ Kvaser Mini PCI Express 1xCAN v3
+ Kvaser Mini PCI Express 2xCAN v3
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
@@ -185,10 +190,10 @@ config CAN_SLCAN
config CAN_SUN4I
tristate "Allwinner A10 CAN controller"
- depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
+ depends on MACH_SUN4I || MACH_SUN7I || RISCV || COMPILE_TEST
help
Say Y here if you want to use CAN controller found on Allwinner
- A10/A20 SoCs.
+ A10/A20/D1 SoCs.
To compile this driver as a module, choose M here: the module will
be called sun4i_can.
diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c
index 39de7164bc4e..49cf9682b925 100644
--- a/drivers/net/can/bxcan.c
+++ b/drivers/net/can/bxcan.c
@@ -23,7 +23,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index 925930b6c4ca..f44ba2600415 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -285,8 +285,8 @@ static int c_can_plat_probe(struct platform_device *pdev)
/* get the platform data */
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- ret = -ENODEV;
+ if (irq < 0) {
+ ret = irq;
goto exit;
}
diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c
index 161e45a7e8c1..77091f7d1fa7 100644
--- a/drivers/net/can/dev/rx-offload.c
+++ b/drivers/net/can/dev/rx-offload.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2014 Protonic Holland,
* David Jander
- * Copyright (C) 2014-2021 Pengutronix,
+ * Copyright (C) 2014-2021, 2023 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/
@@ -240,9 +240,10 @@ int can_rx_offload_queue_timestamp(struct can_rx_offload *offload,
}
EXPORT_SYMBOL_GPL(can_rx_offload_queue_timestamp);
-unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
- unsigned int idx, u32 timestamp,
- unsigned int *frame_len_ptr)
+unsigned int
+can_rx_offload_get_echo_skb_queue_timestamp(struct can_rx_offload *offload,
+ unsigned int idx, u32 timestamp,
+ unsigned int *frame_len_ptr)
{
struct net_device *dev = offload->dev;
struct net_device_stats *stats = &dev->stats;
@@ -262,7 +263,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
return len;
}
-EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);
+EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb_queue_timestamp);
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
struct sk_buff *skb)
@@ -279,6 +280,31 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
}
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
+unsigned int
+can_rx_offload_get_echo_skb_queue_tail(struct can_rx_offload *offload,
+ unsigned int idx,
+ unsigned int *frame_len_ptr)
+{
+ struct net_device *dev = offload->dev;
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+ unsigned int len;
+ int err;
+
+ skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
+ if (!skb)
+ return 0;
+
+ err = can_rx_offload_queue_tail(offload, skb);
+ if (err) {
+ stats->rx_errors++;
+ stats->tx_fifo_errors++;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb_queue_tail);
+
void can_rx_offload_irq_finish(struct can_rx_offload *offload)
{
unsigned long flags;
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index ff0fc18baf13..add39e922b89 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1097,8 +1097,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
handled = IRQ_HANDLED;
stats->tx_bytes +=
- can_rx_offload_get_echo_skb(&priv->offload, 0,
- reg_ctrl << 16, NULL);
+ can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, 0,
+ reg_ctrl << 16, NULL);
stats->tx_packets++;
/* after sending a RTR frame MB is in RX mode */
@@ -2089,8 +2089,8 @@ static int flexcan_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENODEV;
+ if (irq < 0)
+ return irq;
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
@@ -2167,13 +2167,13 @@ static int flexcan_probe(struct platform_device *pdev)
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
priv->irq_boff = platform_get_irq(pdev, 1);
- if (priv->irq_boff <= 0) {
- err = -ENODEV;
+ if (priv->irq_boff < 0) {
+ err = priv->irq_boff;
goto failed_platform_get_irq;
}
priv->irq_err = platform_get_irq(pdev, 2);
- if (priv->irq_err <= 0) {
- err = -ENODEV;
+ if (priv->irq_err < 0) {
+ err = priv->irq_err;
goto failed_platform_get_irq;
}
}
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 3174efdae271..6d3ba71a6a73 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -30,8 +30,9 @@
#include <linux/ethtool.h>
#include <linux/io.h>
#include <linux/can/dev.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
index 1d6642c94f2f..72307297d75e 100644
--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/can/dev.h>
diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c
index db6256f2b1b3..a57005faa04f 100644
--- a/drivers/net/can/kvaser_pciefd.c
+++ b/drivers/net/can/kvaser_pciefd.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/* Copyright (C) 2018 KVASER AB, Sweden. All rights reserved.
* Parts of this driver are based on the following:
- * - Kvaser linux pciefd driver (version 5.25)
+ * - Kvaser linux pciefd driver (version 5.42)
* - PEAK linux canfd driver
*/
@@ -33,37 +33,27 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U)
#define KVASER_PCIEFD_VENDOR 0x1a07
+/* Altera based devices */
#define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d
#define KVASER_PCIEFD_2HS_V2_DEVICE_ID 0x000e
#define KVASER_PCIEFD_HS_V2_DEVICE_ID 0x000f
#define KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID 0x0010
#define KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID 0x0011
-/* PCIe IRQ registers */
-#define KVASER_PCIEFD_IRQ_REG 0x40
-#define KVASER_PCIEFD_IEN_REG 0x50
-/* DMA address translation map register base */
-#define KVASER_PCIEFD_DMA_MAP_BASE 0x1000
-/* Loopback control register */
-#define KVASER_PCIEFD_LOOP_REG 0x1f000
-/* System identification and information registers */
-#define KVASER_PCIEFD_SYSID_BASE 0x1f020
-#define KVASER_PCIEFD_SYSID_VERSION_REG (KVASER_PCIEFD_SYSID_BASE + 0x8)
-#define KVASER_PCIEFD_SYSID_CANFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0xc)
-#define KVASER_PCIEFD_SYSID_BUSFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0x10)
-#define KVASER_PCIEFD_SYSID_BUILD_REG (KVASER_PCIEFD_SYSID_BASE + 0x14)
-/* Shared receive buffer registers */
-#define KVASER_PCIEFD_SRB_BASE 0x1f200
-#define KVASER_PCIEFD_SRB_FIFO_LAST_REG (KVASER_PCIEFD_SRB_BASE + 0x1f4)
-#define KVASER_PCIEFD_SRB_CMD_REG (KVASER_PCIEFD_SRB_BASE + 0x200)
-#define KVASER_PCIEFD_SRB_IEN_REG (KVASER_PCIEFD_SRB_BASE + 0x204)
-#define KVASER_PCIEFD_SRB_IRQ_REG (KVASER_PCIEFD_SRB_BASE + 0x20c)
-#define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210)
-#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214)
-#define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218)
+/* SmartFusion2 based devices */
+#define KVASER_PCIEFD_2CAN_V3_DEVICE_ID 0x0012
+#define KVASER_PCIEFD_1CAN_V3_DEVICE_ID 0x0013
+#define KVASER_PCIEFD_4CAN_V2_DEVICE_ID 0x0014
+#define KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID 0x0015
+#define KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID 0x0016
+
+/* Altera SerDes Enable 64-bit DMA address translation */
+#define KVASER_PCIEFD_ALTERA_DMA_64BIT BIT(0)
+
+/* SmartFusion2 SerDes LSB address translation mask */
+#define KVASER_PCIEFD_SF2_DMA_LSB_MASK GENMASK(31, 12)
+
/* Kvaser KCAN CAN controller registers */
-#define KVASER_PCIEFD_KCAN0_BASE 0x10000
-#define KVASER_PCIEFD_KCAN_BASE_OFFSET 0x1000
#define KVASER_PCIEFD_KCAN_FIFO_REG 0x100
#define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180
#define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0
@@ -77,13 +67,20 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424
#define KVASER_PCIEFD_KCAN_BTRD_REG 0x428
#define KVASER_PCIEFD_KCAN_PWM_REG 0x430
-
-/* PCI interrupt fields */
-#define KVASER_PCIEFD_IRQ_SRB BIT(4)
-#define KVASER_PCIEFD_IRQ_ALL_MASK GENMASK(4, 0)
-
-/* Enable 64-bit DMA address translation */
-#define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0)
+/* System identification and information registers */
+#define KVASER_PCIEFD_SYSID_VERSION_REG 0x8
+#define KVASER_PCIEFD_SYSID_CANFREQ_REG 0xc
+#define KVASER_PCIEFD_SYSID_BUSFREQ_REG 0x10
+#define KVASER_PCIEFD_SYSID_BUILD_REG 0x14
+/* Shared receive buffer FIFO registers */
+#define KVASER_PCIEFD_SRB_FIFO_LAST_REG 0x1f4
+/* Shared receive buffer registers */
+#define KVASER_PCIEFD_SRB_CMD_REG 0x0
+#define KVASER_PCIEFD_SRB_IEN_REG 0x04
+#define KVASER_PCIEFD_SRB_IRQ_REG 0x0c
+#define KVASER_PCIEFD_SRB_STAT_REG 0x10
+#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG 0x14
+#define KVASER_PCIEFD_SRB_CTRL_REG 0x18
/* System build information fields */
#define KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK GENMASK(31, 24)
@@ -253,7 +250,122 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
/* KCAN Error detected packet, second word */
#define KVASER_PCIEFD_EPACK_DIR_TX BIT(0)
+/* Macros for calculating addresses of registers */
+#define KVASER_PCIEFD_GET_BLOCK_ADDR(pcie, block) \
+ ((pcie)->reg_base + (pcie)->driver_data->address_offset->block)
+#define KVASER_PCIEFD_PCI_IEN_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_ien))
+#define KVASER_PCIEFD_PCI_IRQ_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_irq))
+#define KVASER_PCIEFD_SERDES_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), serdes))
+#define KVASER_PCIEFD_SYSID_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), sysid))
+#define KVASER_PCIEFD_LOOPBACK_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), loopback))
+#define KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb_fifo))
+#define KVASER_PCIEFD_SRB_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb))
+#define KVASER_PCIEFD_KCAN_CH0_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch0))
+#define KVASER_PCIEFD_KCAN_CH1_ADDR(pcie) \
+ (KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch1))
+#define KVASER_PCIEFD_KCAN_CHANNEL_SPAN(pcie) \
+ (KVASER_PCIEFD_KCAN_CH1_ADDR((pcie)) - KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)))
+#define KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i) \
+ (KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)) + (i) * KVASER_PCIEFD_KCAN_CHANNEL_SPAN((pcie)))
+
struct kvaser_pciefd;
+static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
+ dma_addr_t addr, int index);
+static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
+ dma_addr_t addr, int index);
+
+struct kvaser_pciefd_address_offset {
+ u32 serdes;
+ u32 pci_ien;
+ u32 pci_irq;
+ u32 sysid;
+ u32 loopback;
+ u32 kcan_srb_fifo;
+ u32 kcan_srb;
+ u32 kcan_ch0;
+ u32 kcan_ch1;
+};
+
+struct kvaser_pciefd_dev_ops {
+ void (*kvaser_pciefd_write_dma_map)(struct kvaser_pciefd *pcie,
+ dma_addr_t addr, int index);
+};
+
+struct kvaser_pciefd_irq_mask {
+ u32 kcan_rx0;
+ u32 kcan_tx[KVASER_PCIEFD_MAX_CAN_CHANNELS];
+ u32 all;
+};
+
+struct kvaser_pciefd_driver_data {
+ const struct kvaser_pciefd_address_offset *address_offset;
+ const struct kvaser_pciefd_irq_mask *irq_mask;
+ const struct kvaser_pciefd_dev_ops *ops;
+};
+
+static const struct kvaser_pciefd_address_offset kvaser_pciefd_altera_address_offset = {
+ .serdes = 0x1000,
+ .pci_ien = 0x50,
+ .pci_irq = 0x40,
+ .sysid = 0x1f020,
+ .loopback = 0x1f000,
+ .kcan_srb_fifo = 0x1f200,
+ .kcan_srb = 0x1f400,
+ .kcan_ch0 = 0x10000,
+ .kcan_ch1 = 0x11000,
+};
+
+static const struct kvaser_pciefd_address_offset kvaser_pciefd_sf2_address_offset = {
+ .serdes = 0x280c8,
+ .pci_ien = 0x102004,
+ .pci_irq = 0x102008,
+ .sysid = 0x100000,
+ .loopback = 0x103000,
+ .kcan_srb_fifo = 0x120000,
+ .kcan_srb = 0x121000,
+ .kcan_ch0 = 0x140000,
+ .kcan_ch1 = 0x142000,
+};
+
+static const struct kvaser_pciefd_irq_mask kvaser_pciefd_altera_irq_mask = {
+ .kcan_rx0 = BIT(4),
+ .kcan_tx = { BIT(0), BIT(1), BIT(2), BIT(3) },
+ .all = GENMASK(4, 0),
+};
+
+static const struct kvaser_pciefd_irq_mask kvaser_pciefd_sf2_irq_mask = {
+ .kcan_rx0 = BIT(4),
+ .kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19) },
+ .all = GENMASK(19, 16) | BIT(4),
+};
+
+static const struct kvaser_pciefd_dev_ops kvaser_pciefd_altera_dev_ops = {
+ .kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_altera,
+};
+
+static const struct kvaser_pciefd_dev_ops kvaser_pciefd_sf2_dev_ops = {
+ .kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_sf2,
+};
+
+static const struct kvaser_pciefd_driver_data kvaser_pciefd_altera_driver_data = {
+ .address_offset = &kvaser_pciefd_altera_address_offset,
+ .irq_mask = &kvaser_pciefd_altera_irq_mask,
+ .ops = &kvaser_pciefd_altera_dev_ops,
+};
+
+static const struct kvaser_pciefd_driver_data kvaser_pciefd_sf2_driver_data = {
+ .address_offset = &kvaser_pciefd_sf2_address_offset,
+ .irq_mask = &kvaser_pciefd_sf2_irq_mask,
+ .ops = &kvaser_pciefd_sf2_dev_ops,
+};
struct kvaser_pciefd_can {
struct can_priv can;
@@ -273,6 +385,7 @@ struct kvaser_pciefd {
struct pci_dev *pci;
void __iomem *reg_base;
struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS];
+ const struct kvaser_pciefd_driver_data *driver_data;
void *dma_data[KVASER_PCIEFD_DMA_COUNT];
u8 nr_channels;
u32 bus_freq;
@@ -305,18 +418,43 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = {
static struct pci_device_id kvaser_pciefd_id_table[] = {
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_V2_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_V2_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
+ },
+ {
+ PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2CAN_V3_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
+ },
+ {
+ PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_1CAN_V3_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
+ },
+ {
+ PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4CAN_V2_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
+ },
+ {
+ PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
+ },
+ {
+ PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID),
+ .driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
},
{
0,
@@ -783,8 +921,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
can = netdev_priv(netdev);
netdev->netdev_ops = &kvaser_pciefd_netdev_ops;
netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops;
- can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE +
- i * KVASER_PCIEFD_KCAN_BASE_OFFSET;
+ can->reg_base = KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i);
can->kv_pcie = pcie;
can->cmd_seq = 0;
can->err_rep_cnt = 0;
@@ -865,20 +1002,37 @@ static int kvaser_pciefd_reg_candev(struct kvaser_pciefd *pcie)
return 0;
}
-static void kvaser_pciefd_write_dma_map(struct kvaser_pciefd *pcie,
- dma_addr_t addr, int offset)
+static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
+ dma_addr_t addr, int index)
{
+ void __iomem *serdes_base;
u32 word1, word2;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- word1 = addr | KVASER_PCIEFD_64BIT_DMA_BIT;
+ word1 = addr | KVASER_PCIEFD_ALTERA_DMA_64BIT;
word2 = addr >> 32;
#else
word1 = addr;
word2 = 0;
#endif
- iowrite32(word1, pcie->reg_base + offset);
- iowrite32(word2, pcie->reg_base + offset + 4);
+ serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x8 * index;
+ iowrite32(word1, serdes_base);
+ iowrite32(word2, serdes_base + 0x4);
+}
+
+static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
+ dma_addr_t addr, int index)
+{
+ void __iomem *serdes_base;
+ u32 lsb = addr & KVASER_PCIEFD_SF2_DMA_LSB_MASK;
+ u32 msb = 0x0;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ msb = addr >> 32;
+#endif
+ serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x10 * index;
+ iowrite32(lsb, serdes_base);
+ iowrite32(msb, serdes_base + 0x4);
}
static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
@@ -889,10 +1043,8 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT];
/* Disable the DMA */
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
+ iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
for (i = 0; i < KVASER_PCIEFD_DMA_COUNT; i++) {
- unsigned int offset = KVASER_PCIEFD_DMA_MAP_BASE + 8 * i;
-
pcie->dma_data[i] = dmam_alloc_coherent(&pcie->pci->dev,
KVASER_PCIEFD_DMA_SIZE,
&dma_addr[i],
@@ -903,24 +1055,25 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
KVASER_PCIEFD_DMA_SIZE);
return -ENOMEM;
}
- kvaser_pciefd_write_dma_map(pcie, dma_addr[i], offset);
+ pcie->driver_data->ops->kvaser_pciefd_write_dma_map(pcie, dma_addr[i], i);
}
/* Reset Rx FIFO, and both DMA buffers */
iowrite32(KVASER_PCIEFD_SRB_CMD_FOR | KVASER_PCIEFD_SRB_CMD_RDB0 |
KVASER_PCIEFD_SRB_CMD_RDB1,
- pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
/* Empty Rx FIFO */
srb_packet_count =
FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK,
- ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG));
+ ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) +
+ KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG));
while (srb_packet_count) {
/* Drop current packet in FIFO */
- ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
+ ioread32(KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
srb_packet_count--;
}
- srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG);
+ srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) {
dev_err(&pcie->pci->dev, "DMA not idle before enabling\n");
return -EIO;
@@ -928,7 +1081,7 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
/* Enable the DMA */
iowrite32(KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE,
- pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
return 0;
}
@@ -937,30 +1090,29 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie)
{
u32 version, srb_status, build;
- version = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG);
+ version = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_VERSION_REG);
pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS,
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version));
- build = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_BUILD_REG);
+ build = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUILD_REG);
dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n",
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version),
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version),
FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build));
- srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG);
+ srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) {
dev_err(&pcie->pci->dev, "Hardware without DMA is not supported\n");
return -ENODEV;
}
- pcie->bus_freq = ioread32(pcie->reg_base +
- KVASER_PCIEFD_SYSID_BUSFREQ_REG);
- pcie->freq = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_CANFREQ_REG);
+ pcie->bus_freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUSFREQ_REG);
+ pcie->freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_CANFREQ_REG);
pcie->freq_to_ticks_div = pcie->freq / 1000000;
if (pcie->freq_to_ticks_div == 0)
pcie->freq_to_ticks_div = 1;
/* Turn off all loopback functionality */
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_LOOP_REG);
+ iowrite32(0, KVASER_PCIEFD_LOOPBACK_ADDR(pcie));
return 0;
}
@@ -1430,21 +1582,20 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf)
static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
{
- u32 irq;
+ u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
- irq = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) {
kvaser_pciefd_read_buffer(pcie, 0);
/* Reset DMA buffer 0 */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
- pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
}
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) {
kvaser_pciefd_read_buffer(pcie, 1);
/* Reset DMA buffer 1 */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
- pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
}
if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
@@ -1453,7 +1604,7 @@ static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
irq & KVASER_PCIEFD_SRB_IRQ_DUF1)
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
- iowrite32(irq, pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
+ iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
}
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
@@ -1479,15 +1630,14 @@ static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
{
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
- u32 board_irq;
+ const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
+ u32 board_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
int i;
- board_irq = ioread32(pcie->reg_base + KVASER_PCIEFD_IRQ_REG);
-
- if (!(board_irq & KVASER_PCIEFD_IRQ_ALL_MASK))
+ if (!(board_irq & irq_mask->all))
return IRQ_NONE;
- if (board_irq & KVASER_PCIEFD_IRQ_SRB)
+ if (board_irq & irq_mask->kcan_rx0)
kvaser_pciefd_receive_irq(pcie);
for (i = 0; i < pcie->nr_channels; i++) {
@@ -1498,7 +1648,7 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
}
/* Check that mask matches channel (i) IRQ mask */
- if (board_irq & (1 << i))
+ if (board_irq & irq_mask->kcan_tx[i])
kvaser_pciefd_transmit_irq(pcie->can[i]);
}
@@ -1525,6 +1675,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
{
int err;
struct kvaser_pciefd *pcie;
+ const struct kvaser_pciefd_irq_mask *irq_mask;
+ void __iomem *irq_en_base;
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -1532,6 +1684,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, pcie);
pcie->pci = pdev;
+ pcie->driver_data = (const struct kvaser_pciefd_driver_data *)id->driver_data;
+ irq_mask = pcie->driver_data->irq_mask;
err = pci_enable_device(pdev);
if (err)
@@ -1567,22 +1721,21 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
goto err_teardown_can_ctrls;
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1,
- pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1 |
KVASER_PCIEFD_SRB_IRQ_DOF0 | KVASER_PCIEFD_SRB_IRQ_DOF1 |
KVASER_PCIEFD_SRB_IRQ_DUF0 | KVASER_PCIEFD_SRB_IRQ_DUF1,
- pcie->reg_base + KVASER_PCIEFD_SRB_IEN_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
/* Enable PCI interrupts */
- iowrite32(KVASER_PCIEFD_IRQ_ALL_MASK,
- pcie->reg_base + KVASER_PCIEFD_IEN_REG);
-
+ irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie);
+ iowrite32(irq_mask->all, irq_en_base);
/* Ready the DMA buffers */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
- pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
- pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG);
+ KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
err = kvaser_pciefd_reg_candev(pcie);
if (err)
@@ -1592,12 +1745,12 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
err_free_irq:
/* Disable PCI interrupts */
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG);
+ iowrite32(0, irq_en_base);
free_irq(pcie->pci->irq, pcie);
err_teardown_can_ctrls:
kvaser_pciefd_teardown_can_ctrls(pcie);
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
+ iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
pci_clear_master(pdev);
err_pci_iounmap:
@@ -1636,8 +1789,8 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev)
kvaser_pciefd_remove_all_ctrls(pcie);
/* Disable interrupts */
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG);
- iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG);
+ iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
+ iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
free_irq(pcie->pci->irq, pcie);
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index c5af92bcc9c9..16ecc11c7f62 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -11,6 +11,7 @@
#include <linux/bitfield.h>
#include <linux/can/dev.h>
#include <linux/ethtool.h>
+#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -18,7 +19,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -308,6 +308,9 @@ enum m_can_reg {
#define TX_EVENT_MM_MASK GENMASK(31, 24)
#define TX_EVENT_TXTS_MASK GENMASK(15, 0)
+/* Hrtimer polling interval */
+#define HRTIMER_POLL_INTERVAL_MS 1
+
/* The ID and DLC registers are adjacent in M_CAN FIFO memory,
* and we can save a (potentially slow) bus round trip by combining
* reads and writes to them.
@@ -1013,10 +1016,10 @@ static void m_can_tx_update_stats(struct m_can_classdev *cdev,
if (cdev->is_peripheral)
stats->tx_bytes +=
- can_rx_offload_get_echo_skb(&cdev->offload,
- msg_mark,
- timestamp,
- NULL);
+ can_rx_offload_get_echo_skb_queue_timestamp(&cdev->offload,
+ msg_mark,
+ timestamp,
+ NULL);
else
stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
@@ -1414,6 +1417,12 @@ static int m_can_start(struct net_device *dev)
m_can_enable_all_interrupts(cdev);
+ if (!dev->irq) {
+ dev_dbg(cdev->dev, "Start hrtimer\n");
+ hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS),
+ HRTIMER_MODE_REL_PINNED);
+ }
+
return 0;
}
@@ -1568,6 +1577,11 @@ static void m_can_stop(struct net_device *dev)
{
struct m_can_classdev *cdev = netdev_priv(dev);
+ if (!dev->irq) {
+ dev_dbg(cdev->dev, "Stop hrtimer\n");
+ hrtimer_cancel(&cdev->hrtimer);
+ }
+
/* disable all interrupts */
m_can_disable_all_interrupts(cdev);
@@ -1793,6 +1807,18 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
+{
+ struct m_can_classdev *cdev = container_of(timer, struct
+ m_can_classdev, hrtimer);
+
+ m_can_isr(0, cdev->net);
+
+ hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS));
+
+ return HRTIMER_RESTART;
+}
+
static int m_can_open(struct net_device *dev)
{
struct m_can_classdev *cdev = netdev_priv(dev);
@@ -1831,7 +1857,7 @@ static int m_can_open(struct net_device *dev)
err = request_threaded_irq(dev->irq, NULL, m_can_isr,
IRQF_ONESHOT,
dev->name, dev);
- } else {
+ } else if (dev->irq) {
err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
dev);
}
@@ -1887,6 +1913,22 @@ static int register_m_can_dev(struct net_device *dev)
return register_candev(dev);
}
+int m_can_check_mram_cfg(struct m_can_classdev *cdev, u32 mram_max_size)
+{
+ u32 total_size;
+
+ total_size = cdev->mcfg[MRAM_TXB].off - cdev->mcfg[MRAM_SIDF].off +
+ cdev->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
+ if (total_size > mram_max_size) {
+ dev_err(cdev->dev, "Total size of mram config(%u) exceeds mram(%u)\n",
+ total_size, mram_max_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(m_can_check_mram_cfg);
+
static void m_can_of_parse_mram(struct m_can_classdev *cdev,
const u32 *mram_config_vals)
{
@@ -2027,6 +2069,9 @@ int m_can_class_register(struct m_can_classdev *cdev)
goto clk_disable;
}
+ if (!cdev->net->irq)
+ cdev->hrtimer.function = &hrtimer_callback;
+
ret = m_can_dev_setup(cdev);
if (ret)
goto rx_offload_del;
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index a839dc71dc9b..520e14277dff 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/freezer.h>
+#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -22,7 +23,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
@@ -93,6 +93,8 @@ struct m_can_classdev {
int is_peripheral;
struct mram_cfg mcfg[MRAM_CFG_NUM];
+
+ struct hrtimer hrtimer;
};
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
@@ -101,6 +103,7 @@ int m_can_class_register(struct m_can_classdev *cdev);
void m_can_class_unregister(struct m_can_classdev *cdev);
int m_can_class_get_clocks(struct m_can_classdev *cdev);
int m_can_init_ram(struct m_can_classdev *priv);
+int m_can_check_mram_cfg(struct m_can_classdev *cdev, u32 mram_max_size);
int m_can_class_suspend(struct device *dev);
int m_can_class_resume(struct device *dev);
diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c
index 94dc82644113..cdb28d6a092c 100644
--- a/drivers/net/can/m_can/m_can_platform.c
+++ b/drivers/net/can/m_can/m_can_platform.c
@@ -5,6 +5,7 @@
//
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
+#include <linux/hrtimer.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@@ -82,7 +83,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
void __iomem *addr;
void __iomem *mram_addr;
struct phy *transceiver;
- int irq, ret = 0;
+ int irq = 0, ret = 0;
mcan_class = m_can_class_allocate_dev(&pdev->dev,
sizeof(struct m_can_plat_priv));
@@ -96,12 +97,24 @@ static int m_can_plat_probe(struct platform_device *pdev)
goto probe_fail;
addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
- irq = platform_get_irq_byname(pdev, "int0");
- if (IS_ERR(addr) || irq < 0) {
- ret = -EINVAL;
+ if (IS_ERR(addr)) {
+ ret = PTR_ERR(addr);
goto probe_fail;
}
+ if (device_property_present(mcan_class->dev, "interrupts") ||
+ device_property_present(mcan_class->dev, "interrupt-names")) {
+ irq = platform_get_irq_byname(pdev, "int0");
+ if (irq < 0) {
+ ret = irq;
+ goto probe_fail;
+ }
+ } else {
+ dev_dbg(mcan_class->dev, "Polling enabled, initialize hrtimer");
+ hrtimer_init(&mcan_class->hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_PINNED);
+ }
+
/* message ram could be shared */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
if (!res) {
diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c
index 2342aa011647..8a4143809d33 100644
--- a/drivers/net/can/m_can/tcan4x5x-core.c
+++ b/drivers/net/can/m_can/tcan4x5x-core.c
@@ -6,8 +6,9 @@
#define TCAN4X5X_EXT_CLK_DEF 40000000
-#define TCAN4X5X_DEV_ID0 0x00
-#define TCAN4X5X_DEV_ID1 0x04
+#define TCAN4X5X_DEV_ID1 0x00
+#define TCAN4X5X_DEV_ID1_TCAN 0x4e414354 /* ASCII TCAN */
+#define TCAN4X5X_DEV_ID2 0x04
#define TCAN4X5X_REV 0x08
#define TCAN4X5X_STATUS 0x0C
#define TCAN4X5X_ERROR_STATUS_MASK 0x10
@@ -80,6 +81,7 @@
TCAN4X5X_MCAN_IR_RF1F)
#define TCAN4X5X_MRAM_START 0x8000
+#define TCAN4X5X_MRAM_SIZE 0x800
#define TCAN4X5X_MCAN_OFFSET 0x1000
#define TCAN4X5X_CLEAR_ALL_INT 0xffffffff
@@ -102,6 +104,37 @@
#define TCAN4X5X_WD_3_S_TIMER BIT(29)
#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29))
+struct tcan4x5x_version_info {
+ const char *name;
+ u32 id2_register;
+
+ bool has_wake_pin;
+ bool has_state_pin;
+};
+
+enum {
+ TCAN4552 = 0,
+ TCAN4553,
+ TCAN4X5X,
+};
+
+static const struct tcan4x5x_version_info tcan4x5x_versions[] = {
+ [TCAN4552] = {
+ .name = "4552",
+ .id2_register = 0x32353534,
+ },
+ [TCAN4553] = {
+ .name = "4553",
+ .id2_register = 0x32353534,
+ },
+ /* generic version with no id2_register at the end */
+ [TCAN4X5X] = {
+ .name = "generic",
+ .has_wake_pin = true,
+ .has_state_pin = true,
+ },
+};
+
static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev)
{
return container_of(cdev, struct tcan4x5x_priv, cdev);
@@ -253,18 +286,53 @@ static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
TCAN4X5X_DISABLE_INH_MSK, 0x01);
}
-static int tcan4x5x_get_gpios(struct m_can_classdev *cdev)
+static const struct tcan4x5x_version_info
+*tcan4x5x_find_version(struct tcan4x5x_priv *priv)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID1, &val);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (val != TCAN4X5X_DEV_ID1_TCAN) {
+ dev_err(&priv->spi->dev, "Not a tcan device %x\n", val);
+ return ERR_PTR(-ENODEV);
+ }
+
+ ret = regmap_read(priv->regmap, TCAN4X5X_DEV_ID2, &val);
+ if (ret)
+ return ERR_PTR(ret);
+
+ for (int i = 0; i != ARRAY_SIZE(tcan4x5x_versions); ++i) {
+ const struct tcan4x5x_version_info *vinfo = &tcan4x5x_versions[i];
+
+ if (!vinfo->id2_register || val == vinfo->id2_register) {
+ dev_info(&priv->spi->dev, "Detected TCAN device version %s\n",
+ vinfo->name);
+ return vinfo;
+ }
+ }
+
+ return &tcan4x5x_versions[TCAN4X5X];
+}
+
+static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
+ const struct tcan4x5x_version_info *version_info)
{
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
int ret;
- tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
- GPIOD_OUT_HIGH);
- if (IS_ERR(tcan4x5x->device_wake_gpio)) {
- if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ if (version_info->has_wake_pin) {
+ tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(tcan4x5x->device_wake_gpio)) {
+ if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
- tcan4x5x_disable_wake(cdev);
+ tcan4x5x_disable_wake(cdev);
+ }
}
tcan4x5x->reset_gpio = devm_gpiod_get_optional(cdev->dev, "reset",
@@ -276,12 +344,14 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev)
if (ret)
return ret;
- tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
- "device-state",
- GPIOD_IN);
- if (IS_ERR(tcan4x5x->device_state_gpio)) {
- tcan4x5x->device_state_gpio = NULL;
- tcan4x5x_disable_state(cdev);
+ if (version_info->has_state_pin) {
+ tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
+ "device-state",
+ GPIOD_IN);
+ if (IS_ERR(tcan4x5x->device_state_gpio)) {
+ tcan4x5x->device_state_gpio = NULL;
+ tcan4x5x_disable_state(cdev);
+ }
}
return 0;
@@ -298,6 +368,7 @@ static struct m_can_ops tcan4x5x_ops = {
static int tcan4x5x_can_probe(struct spi_device *spi)
{
+ const struct tcan4x5x_version_info *version_info;
struct tcan4x5x_priv *priv;
struct m_can_classdev *mcan_class;
int freq, ret;
@@ -307,6 +378,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
if (!mcan_class)
return -ENOMEM;
+ ret = m_can_check_mram_cfg(mcan_class, TCAN4X5X_MRAM_SIZE);
+ if (ret)
+ goto out_m_can_class_free_dev;
+
priv = cdev_to_priv(mcan_class);
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
@@ -327,6 +402,8 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
/* Sanity check */
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) {
+ dev_err(&spi->dev, "Clock frequency is out of supported range %d\n",
+ freq);
ret = -ERANGE;
goto out_m_can_class_free_dev;
}
@@ -345,28 +422,49 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
/* Configure the SPI bus */
spi->bits_per_word = 8;
ret = spi_setup(spi);
- if (ret)
+ if (ret) {
+ dev_err(&spi->dev, "SPI setup failed %pe\n", ERR_PTR(ret));
goto out_m_can_class_free_dev;
+ }
ret = tcan4x5x_regmap_init(priv);
- if (ret)
+ if (ret) {
+ dev_err(&spi->dev, "regmap init failed %pe\n", ERR_PTR(ret));
goto out_m_can_class_free_dev;
+ }
ret = tcan4x5x_power_enable(priv->power, 1);
- if (ret)
+ if (ret) {
+ dev_err(&spi->dev, "Enabling regulator failed %pe\n",
+ ERR_PTR(ret));
goto out_m_can_class_free_dev;
+ }
- ret = tcan4x5x_get_gpios(mcan_class);
- if (ret)
+ version_info = tcan4x5x_find_version(priv);
+ if (IS_ERR(version_info)) {
+ ret = PTR_ERR(version_info);
+ goto out_power;
+ }
+
+ ret = tcan4x5x_get_gpios(mcan_class, version_info);
+ if (ret) {
+ dev_err(&spi->dev, "Getting gpios failed %pe\n", ERR_PTR(ret));
goto out_power;
+ }
ret = tcan4x5x_init(mcan_class);
- if (ret)
+ if (ret) {
+ dev_err(&spi->dev, "tcan initialization failed %pe\n",
+ ERR_PTR(ret));
goto out_power;
+ }
ret = m_can_class_register(mcan_class);
- if (ret)
+ if (ret) {
+ dev_err(&spi->dev, "Failed registering m_can device %pe\n",
+ ERR_PTR(ret));
goto out_power;
+ }
netdev_info(mcan_class->net, "TCAN4X5X successfully initialized.\n");
return 0;
diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c
index 2b218ce04e9f..fafa6daa67e6 100644
--- a/drivers/net/can/m_can/tcan4x5x-regmap.c
+++ b/drivers/net/can/m_can/tcan4x5x-regmap.c
@@ -95,7 +95,6 @@ static const struct regmap_range tcan4x5x_reg_table_wr_range[] = {
regmap_reg_range(0x000c, 0x0010),
/* Device configuration registers and Interrupt Flags*/
regmap_reg_range(0x0800, 0x080c),
- regmap_reg_range(0x0814, 0x0814),
regmap_reg_range(0x0820, 0x0820),
regmap_reg_range(0x0830, 0x0830),
/* M_CAN */
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index e4d748913439..b82842718735 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -34,7 +34,6 @@
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index c56e27223e5f..ac86640998a8 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -148,7 +148,7 @@ static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
{
- struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+ struct ems_pci_card *card = priv->priv;
/* reset int flag of pita */
writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
@@ -168,7 +168,7 @@ static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
{
- struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+ struct ems_pci_card *card = priv->priv;
writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
}
@@ -186,7 +186,7 @@ static void ems_pci_v3_write_reg(const struct sja1000_priv *priv,
static void ems_pci_v3_post_irq(const struct sja1000_priv *priv)
{
- struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+ struct ems_pci_card *card = priv->priv;
writel(ASIX_LINTSR_INT0AC, card->conf_addr + ASIX_LINTSR);
}
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 4e59952c66d4..33f0e46ab1c2 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -17,7 +17,6 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include "sja1000.h"
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
index 237617b0c125..e5bd57b65aaf 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
@@ -111,9 +111,9 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
stats->tx_bytes +=
- can_rx_offload_get_echo_skb(&priv->offload,
- tef_tail, hw_tef_obj->ts,
- frame_len_ptr);
+ can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
+ tef_tail, hw_tef_obj->ts,
+ frame_len_ptr);
stats->tx_packets++;
priv->tef->tail++;
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
index 0827830bbf28..ab8d01784686 100644
--- a/drivers/net/can/sun4i_can.c
+++ b/drivers/net/can/sun4i_can.c
@@ -59,7 +59,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -91,6 +90,8 @@
#define SUN4I_REG_BUF12_ADDR 0x0070 /* CAN Tx/Rx Buffer 12 */
#define SUN4I_REG_ACPC_ADDR 0x0040 /* CAN Acceptance Code 0 */
#define SUN4I_REG_ACPM_ADDR 0x0044 /* CAN Acceptance Mask 0 */
+#define SUN4I_REG_ACPC_ADDR_D1 0x0028 /* CAN Acceptance Code 0 on the D1 */
+#define SUN4I_REG_ACPM_ADDR_D1 0x002C /* CAN Acceptance Mask 0 on the D1 */
#define SUN4I_REG_RBUF_RBACK_START_ADDR 0x0180 /* CAN transmit buffer start */
#define SUN4I_REG_RBUF_RBACK_END_ADDR 0x01b0 /* CAN transmit buffer end */
@@ -205,9 +206,11 @@
* struct sun4ican_quirks - Differences between SoC variants.
*
* @has_reset: SoC needs reset deasserted.
+ * @acp_offset: Offset of ACPC and ACPM registers
*/
struct sun4ican_quirks {
bool has_reset;
+ int acp_offset;
};
struct sun4ican_priv {
@@ -216,6 +219,7 @@ struct sun4ican_priv {
struct clk *clk;
struct reset_control *reset;
spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
+ int acp_offset;
};
static const struct can_bittiming_const sun4ican_bittiming_const = {
@@ -338,8 +342,8 @@ static int sun4i_can_start(struct net_device *dev)
}
/* set filters - we accept all */
- writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR);
- writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR);
+ writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR + priv->acp_offset);
+ writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR + priv->acp_offset);
/* clear error counters and error code capture */
writel(0, priv->base + SUN4I_REG_ERRC_ADDR);
@@ -768,10 +772,17 @@ static const struct ethtool_ops sun4ican_ethtool_ops = {
static const struct sun4ican_quirks sun4ican_quirks_a10 = {
.has_reset = false,
+ .acp_offset = 0,
};
static const struct sun4ican_quirks sun4ican_quirks_r40 = {
.has_reset = true,
+ .acp_offset = 0,
+};
+
+static const struct sun4ican_quirks sun4ican_quirks_d1 = {
+ .has_reset = true,
+ .acp_offset = (SUN4I_REG_ACPC_ADDR_D1 - SUN4I_REG_ACPC_ADDR),
};
static const struct of_device_id sun4ican_of_match[] = {
@@ -785,6 +796,9 @@ static const struct of_device_id sun4ican_of_match[] = {
.compatible = "allwinner,sun8i-r40-can",
.data = &sun4ican_quirks_r40
}, {
+ .compatible = "allwinner,sun20i-d1-can",
+ .data = &sun4ican_quirks_d1
+ }, {
/* sentinel */
},
};
@@ -870,6 +884,7 @@ static int sun4ican_probe(struct platform_device *pdev)
priv->base = addr;
priv->clk = clk;
priv->reset = reset;
+ priv->acp_offset = quirks->acp_offset;
spin_lock_init(&priv->cmdreg_lock);
platform_set_drvdata(pdev, dev);
@@ -907,4 +922,4 @@ module_platform_driver(sun4i_can_driver);
MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>");
MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20)");
+MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20/D1)");
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 54284661992e..5aab440074c6 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -21,7 +21,6 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/can/dev.h>
@@ -748,8 +747,8 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
spin_unlock_irqrestore(&priv->mbx_lock, flags);
stamp = hecc_read_stamp(priv, mbxno);
stats->tx_bytes +=
- can_rx_offload_get_echo_skb(&priv->offload,
- mbxno, stamp, NULL);
+ can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
+ mbxno, stamp, NULL);
stats->tx_packets++;
--priv->tx_tail;
}
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 58fcd2b34820..d1450722cb3c 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -52,6 +52,7 @@ config CAN_F81604
config CAN_GS_USB
tristate "Geschwister Schneider UG and candleLight compatible interfaces"
+ select CAN_RX_OFFLOAD
help
This driver supports the Geschwister Schneider and
bytewerk.org candleLight compatible
diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
index 6201637ac0ff..41a0e4261d15 100644
--- a/drivers/net/can/usb/esd_usb.c
+++ b/drivers/net/can/usb/esd_usb.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro
+ * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro
*
* Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu>
* Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu>
@@ -19,17 +19,19 @@
MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>");
MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>");
-MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces");
+MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces");
MODULE_LICENSE("GPL v2");
/* USB vendor and product ID */
#define ESD_USB_ESDGMBH_VENDOR_ID 0x0ab4
#define ESD_USB_CANUSB2_PRODUCT_ID 0x0010
#define ESD_USB_CANUSBM_PRODUCT_ID 0x0011
+#define ESD_USB_CANUSB3_PRODUCT_ID 0x0014
/* CAN controller clock frequencies */
#define ESD_USB_2_CAN_CLOCK (60 * MEGA) /* Hz */
#define ESD_USB_M_CAN_CLOCK (36 * MEGA) /* Hz */
+#define ESD_USB_3_CAN_CLOCK (80 * MEGA) /* Hz */
/* Maximum number of CAN nets */
#define ESD_USB_MAX_NETS 2
@@ -44,6 +46,9 @@ MODULE_LICENSE("GPL v2");
/* esd CAN message flags - dlc field */
#define ESD_USB_RTR BIT(4)
+#define ESD_USB_NO_BRS BIT(4)
+#define ESD_USB_ESI BIT(5)
+#define ESD_USB_FD BIT(7)
/* esd CAN message flags - id field */
#define ESD_USB_EXTID BIT(29)
@@ -65,6 +70,9 @@ MODULE_LICENSE("GPL v2");
#define ESD_USB_M_SJW_SHIFT 24
#define ESD_USB_TRIPLE_SAMPLES BIT(23)
+/* Transmitter Delay Compensation */
+#define ESD_USB_3_TDC_MODE_AUTO 0
+
/* esd IDADD message */
#define ESD_USB_ID_ENABLE BIT(7)
#define ESD_USB_MAX_ID_SEGMENT 64
@@ -88,6 +96,21 @@ MODULE_LICENSE("GPL v2");
#define ESD_USB_MAX_RX_URBS 4
#define ESD_USB_MAX_TX_URBS 16 /* must be power of 2 */
+/* Modes for CAN-USB/3, to be used for esd_usb_3_set_baudrate_msg_x.mode */
+#define ESD_USB_3_BAUDRATE_MODE_DISABLE 0 /* remove from bus */
+#define ESD_USB_3_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */
+#define ESD_USB_3_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (controller)*/
+#define ESD_USB_3_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (canonical) */
+#define ESD_USB_3_BAUDRATE_MODE_NUM 4 /* numerical bit rate */
+#define ESD_USB_3_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */
+
+/* Flags for CAN-USB/3, to be used for esd_usb_3_set_baudrate_msg_x.flags */
+#define ESD_USB_3_BAUDRATE_FLAG_FD BIT(0) /* enable CAN FD mode */
+#define ESD_USB_3_BAUDRATE_FLAG_LOM BIT(1) /* enable listen only mode */
+#define ESD_USB_3_BAUDRATE_FLAG_STM BIT(2) /* enable self test mode */
+#define ESD_USB_3_BAUDRATE_FLAG_TRS BIT(3) /* enable triple sampling */
+#define ESD_USB_3_BAUDRATE_FLAG_TXP BIT(4) /* enable transmit pause */
+
struct esd_usb_header_msg {
u8 len; /* total message length in 32bit words */
u8 cmd;
@@ -122,6 +145,7 @@ struct esd_usb_rx_msg {
__le32 id; /* upper 3 bits contain flags */
union {
u8 data[CAN_MAX_DLEN];
+ u8 data_fd[CANFD_MAX_DLEN];
struct {
u8 status; /* CAN Controller Status */
u8 ecc; /* Error Capture Register */
@@ -138,7 +162,10 @@ struct esd_usb_tx_msg {
u8 dlc;
u32 hnd; /* opaque handle, not used by device */
__le32 id; /* upper 3 bits contain flags */
- u8 data[CAN_MAX_DLEN];
+ union {
+ u8 data[CAN_MAX_DLEN];
+ u8 data_fd[CANFD_MAX_DLEN];
+ };
};
struct esd_usb_tx_done_msg {
@@ -166,6 +193,50 @@ struct esd_usb_set_baudrate_msg {
__le32 baud;
};
+/* CAN-USB/3 baudrate configuration, used for nominal as well as for data bit rate */
+struct esd_usb_3_baudrate_cfg {
+ __le16 brp; /* bit rate pre-scaler */
+ __le16 tseg1; /* time segment before sample point */
+ __le16 tseg2; /* time segment after sample point */
+ __le16 sjw; /* synchronization jump Width */
+};
+
+/* In principle, the esd CAN-USB/3 supports Transmitter Delay Compensation (TDC),
+ * but currently only the automatic TDC mode is supported by this driver.
+ * An implementation for manual TDC configuration will follow.
+ *
+ * For information about struct esd_usb_3_tdc_cfg, see
+ * NTCAN Application Developers Manual, 6.2.25 NTCAN_TDC_CFG + related chapters
+ * https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf
+ */
+struct esd_usb_3_tdc_cfg {
+ u8 tdc_mode; /* transmitter delay compensation mode */
+ u8 ssp_offset; /* secondary sample point offset in mtq */
+ s8 ssp_shift; /* secondary sample point shift in mtq */
+ u8 tdc_filter; /* TDC filter in mtq */
+};
+
+/* Extended version of the above set_baudrate_msg for a CAN-USB/3
+ * to define the CAN bit timing configuration of the CAN controller in
+ * CAN FD mode as well as in Classical CAN mode.
+ *
+ * The payload of this command is a NTCAN_BAUDRATE_X structure according to
+ * esd electronics gmbh, NTCAN Application Developers Manual, 6.2.15 NTCAN_BAUDRATE_X
+ * https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf
+ */
+struct esd_usb_3_set_baudrate_msg_x {
+ u8 len; /* total message length in 32bit words */
+ u8 cmd;
+ u8 net;
+ u8 rsvd; /*reserved */
+ /* Payload ... */
+ __le16 mode; /* mode word, see ESD_USB_3_BAUDRATE_MODE_xxx */
+ __le16 flags; /* control flags, see ESD_USB_3_BAUDRATE_FLAG_xxx */
+ struct esd_usb_3_tdc_cfg tdc; /* TDC configuration */
+ struct esd_usb_3_baudrate_cfg nom; /* nominal bit rate */
+ struct esd_usb_3_baudrate_cfg data; /* data bit rate */
+};
+
/* Main message type used between library and application */
union __packed esd_usb_msg {
struct esd_usb_header_msg hdr;
@@ -175,12 +246,14 @@ union __packed esd_usb_msg {
struct esd_usb_tx_msg tx;
struct esd_usb_tx_done_msg txdone;
struct esd_usb_set_baudrate_msg setbaud;
+ struct esd_usb_3_set_baudrate_msg_x setbaud_x;
struct esd_usb_id_filter_msg filter;
};
static struct usb_device_id esd_usb_table[] = {
{USB_DEVICE(ESD_USB_ESDGMBH_VENDOR_ID, ESD_USB_CANUSB2_PRODUCT_ID)},
{USB_DEVICE(ESD_USB_ESDGMBH_VENDOR_ID, ESD_USB_CANUSBM_PRODUCT_ID)},
+ {USB_DEVICE(ESD_USB_ESDGMBH_VENDOR_ID, ESD_USB_CANUSB3_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE(usb, esd_usb_table);
@@ -321,9 +394,10 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
{
struct net_device_stats *stats = &priv->netdev->stats;
struct can_frame *cf;
+ struct canfd_frame *cfd;
struct sk_buff *skb;
- int i;
u32 id;
+ u8 len;
if (!netif_device_present(priv->netdev))
return;
@@ -333,27 +407,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
if (id & ESD_USB_EVENT) {
esd_usb_rx_event(priv, msg);
} else {
- skb = alloc_can_skb(priv->netdev, &cf);
+ if (msg->rx.dlc & ESD_USB_FD) {
+ skb = alloc_canfd_skb(priv->netdev, &cfd);
+ } else {
+ skb = alloc_can_skb(priv->netdev, &cf);
+ cfd = (struct canfd_frame *)cf;
+ }
+
if (skb == NULL) {
stats->rx_dropped++;
return;
}
- cf->can_id = id & ESD_USB_IDMASK;
- can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_USB_RTR,
- priv->can.ctrlmode);
-
- if (id & ESD_USB_EXTID)
- cf->can_id |= CAN_EFF_FLAG;
+ cfd->can_id = id & ESD_USB_IDMASK;
- if (msg->rx.dlc & ESD_USB_RTR) {
- cf->can_id |= CAN_RTR_FLAG;
+ if (msg->rx.dlc & ESD_USB_FD) {
+ /* masking by 0x0F is already done within can_fd_dlc2len() */
+ cfd->len = can_fd_dlc2len(msg->rx.dlc);
+ len = cfd->len;
+ if ((msg->rx.dlc & ESD_USB_NO_BRS) == 0)
+ cfd->flags |= CANFD_BRS;
+ if (msg->rx.dlc & ESD_USB_ESI)
+ cfd->flags |= CANFD_ESI;
} else {
- for (i = 0; i < cf->len; i++)
- cf->data[i] = msg->rx.data[i];
-
- stats->rx_bytes += cf->len;
+ can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_USB_RTR, priv->can.ctrlmode);
+ len = cf->len;
+ if (msg->rx.dlc & ESD_USB_RTR) {
+ cf->can_id |= CAN_RTR_FLAG;
+ len = 0;
+ }
}
+
+ if (id & ESD_USB_EXTID)
+ cfd->can_id |= CAN_EFF_FLAG;
+
+ memcpy(cfd->data, msg->rx.data_fd, len);
+ stats->rx_bytes += len;
stats->rx_packets++;
netif_rx(skb);
@@ -728,7 +817,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
struct esd_usb *dev = priv->usb;
struct esd_tx_urb_context *context = NULL;
struct net_device_stats *stats = &netdev->stats;
- struct can_frame *cf = (struct can_frame *)skb->data;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
union esd_usb_msg *msg;
struct urb *urb;
u8 *buf;
@@ -762,20 +851,29 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
msg->hdr.len = offsetof(struct esd_usb_tx_msg, data) / sizeof(u32);
msg->hdr.cmd = ESD_USB_CMD_CAN_TX;
msg->tx.net = priv->index;
- msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
- msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
- if (cf->can_id & CAN_RTR_FLAG)
- msg->tx.dlc |= ESD_USB_RTR;
+ if (can_is_canfd_skb(skb)) {
+ msg->tx.dlc = can_fd_len2dlc(cfd->len);
+ msg->tx.dlc |= ESD_USB_FD;
+
+ if ((cfd->flags & CANFD_BRS) == 0)
+ msg->tx.dlc |= ESD_USB_NO_BRS;
+ } else {
+ msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode);
+
+ if (cfd->can_id & CAN_RTR_FLAG)
+ msg->tx.dlc |= ESD_USB_RTR;
+ }
+
+ msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK);
- if (cf->can_id & CAN_EFF_FLAG)
+ if (cfd->can_id & CAN_EFF_FLAG)
msg->tx.id |= cpu_to_le32(ESD_USB_EXTID);
- for (i = 0; i < cf->len; i++)
- msg->tx.data[i] = cf->data[i];
+ memcpy(msg->tx.data_fd, cfd->data, cfd->len);
/* round up, then divide by 4 to add the payload length as # of 32bit words */
- msg->hdr.len += DIV_ROUND_UP(cf->len, sizeof(u32));
+ msg->hdr.len += DIV_ROUND_UP(cfd->len, sizeof(u32));
for (i = 0; i < ESD_USB_MAX_TX_URBS; i++) {
if (priv->tx_contexts[i].echo_index == ESD_USB_MAX_TX_URBS) {
@@ -962,6 +1060,105 @@ static int esd_usb_2_set_bittiming(struct net_device *netdev)
return err;
}
+/* Nominal bittiming constants, see
+ * Microchip SAM E70/S70/V70/V71, Data Sheet, Rev. G - 07/2022
+ * 48.6.8 MCAN Nominal Bit Timing and Prescaler Register
+ */
+static const struct can_bittiming_const esd_usb_3_nom_bittiming_const = {
+ .name = "esd_usb_3",
+ .tseg1_min = 2,
+ .tseg1_max = 256,
+ .tseg2_min = 2,
+ .tseg2_max = 128,
+ .sjw_max = 128,
+ .brp_min = 1,
+ .brp_max = 512,
+ .brp_inc = 1,
+};
+
+/* Data bittiming constants, see
+ * Microchip SAM E70/S70/V70/V71, Data Sheet, Rev. G - 07/2022
+ * 48.6.4 MCAN Data Bit Timing and Prescaler Register
+ */
+static const struct can_bittiming_const esd_usb_3_data_bittiming_const = {
+ .name = "esd_usb_3",
+ .tseg1_min = 2,
+ .tseg1_max = 32,
+ .tseg2_min = 1,
+ .tseg2_max = 16,
+ .sjw_max = 8,
+ .brp_min = 1,
+ .brp_max = 32,
+ .brp_inc = 1,
+};
+
+static int esd_usb_3_set_bittiming(struct net_device *netdev)
+{
+ const struct can_bittiming_const *nom_btc = &esd_usb_3_nom_bittiming_const;
+ const struct can_bittiming_const *data_btc = &esd_usb_3_data_bittiming_const;
+ struct esd_usb_net_priv *priv = netdev_priv(netdev);
+ struct can_bittiming *nom_bt = &priv->can.bittiming;
+ struct can_bittiming *data_bt = &priv->can.data_bittiming;
+ struct esd_usb_3_set_baudrate_msg_x *baud_x;
+ union esd_usb_msg *msg;
+ u16 flags = 0;
+ int err;
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ baud_x = &msg->setbaud_x;
+
+ /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */
+ baud_x->mode = cpu_to_le16(ESD_USB_3_BAUDRATE_MODE_BTR_CANONICAL);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ flags |= ESD_USB_3_BAUDRATE_FLAG_LOM;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ flags |= ESD_USB_3_BAUDRATE_FLAG_TRS;
+
+ baud_x->nom.brp = cpu_to_le16(nom_bt->brp & (nom_btc->brp_max - 1));
+ baud_x->nom.sjw = cpu_to_le16(nom_bt->sjw & (nom_btc->sjw_max - 1));
+ baud_x->nom.tseg1 = cpu_to_le16((nom_bt->prop_seg + nom_bt->phase_seg1)
+ & (nom_btc->tseg1_max - 1));
+ baud_x->nom.tseg2 = cpu_to_le16(nom_bt->phase_seg2 & (nom_btc->tseg2_max - 1));
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ baud_x->data.brp = cpu_to_le16(data_bt->brp & (data_btc->brp_max - 1));
+ baud_x->data.sjw = cpu_to_le16(data_bt->sjw & (data_btc->sjw_max - 1));
+ baud_x->data.tseg1 = cpu_to_le16((data_bt->prop_seg + data_bt->phase_seg1)
+ & (data_btc->tseg1_max - 1));
+ baud_x->data.tseg2 = cpu_to_le16(data_bt->phase_seg2 & (data_btc->tseg2_max - 1));
+ flags |= ESD_USB_3_BAUDRATE_FLAG_FD;
+ }
+
+ /* Currently this driver only supports the automatic TDC mode */
+ baud_x->tdc.tdc_mode = ESD_USB_3_TDC_MODE_AUTO;
+ baud_x->tdc.ssp_offset = 0;
+ baud_x->tdc.ssp_shift = 0;
+ baud_x->tdc.tdc_filter = 0;
+
+ baud_x->flags = cpu_to_le16(flags);
+ baud_x->net = priv->index;
+ baud_x->rsvd = 0;
+
+ /* set len as # of 32bit words */
+ msg->hdr.len = sizeof(struct esd_usb_3_set_baudrate_msg_x) / sizeof(u32);
+ msg->hdr.cmd = ESD_USB_CMD_SETBAUD;
+
+ netdev_dbg(netdev,
+ "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flags=%#x\n",
+ priv->can.ctrlmode, priv->can.ctrlmode_supported,
+ priv->index, le16_to_cpu(baud_x->mode), flags);
+
+ err = esd_usb_send_msg(priv->usb, msg);
+
+ kfree(msg);
+ return err;
+}
+
static int esd_usb_get_berr_counter(const struct net_device *netdev,
struct can_berr_counter *bec)
{
@@ -1019,16 +1216,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
CAN_CTRLMODE_CC_LEN8_DLC |
CAN_CTRLMODE_BERR_REPORTING;
- if (le16_to_cpu(dev->udev->descriptor.idProduct) ==
- ESD_USB_CANUSBM_PRODUCT_ID)
+ switch (le16_to_cpu(dev->udev->descriptor.idProduct)) {
+ case ESD_USB_CANUSB3_PRODUCT_ID:
+ priv->can.clock.freq = ESD_USB_3_CAN_CLOCK;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+ priv->can.bittiming_const = &esd_usb_3_nom_bittiming_const;
+ priv->can.data_bittiming_const = &esd_usb_3_data_bittiming_const;
+ priv->can.do_set_bittiming = esd_usb_3_set_bittiming;
+ priv->can.do_set_data_bittiming = esd_usb_3_set_bittiming;
+ break;
+
+ case ESD_USB_CANUSBM_PRODUCT_ID:
priv->can.clock.freq = ESD_USB_M_CAN_CLOCK;
- else {
+ priv->can.bittiming_const = &esd_usb_2_bittiming_const;
+ priv->can.do_set_bittiming = esd_usb_2_set_bittiming;
+ break;
+
+ case ESD_USB_CANUSB2_PRODUCT_ID:
+ default:
priv->can.clock.freq = ESD_USB_2_CAN_CLOCK;
priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ priv->can.bittiming_const = &esd_usb_2_bittiming_const;
+ priv->can.do_set_bittiming = esd_usb_2_set_bittiming;
+ break;
}
- priv->can.bittiming_const = &esd_usb_2_bittiming_const;
- priv->can.do_set_bittiming = esd_usb_2_set_bittiming;
priv->can.do_set_mode = esd_usb_set_mode;
priv->can.do_get_berr_counter = esd_usb_get_berr_counter;
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index bd9eb066ecf1..95b0fdb602c8 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -5,6 +5,7 @@
* Copyright (C) 2013-2016 Geschwister Schneider Technologie-,
* Entwicklungs- und Vertriebs UG (Haftungsbeschränkt).
* Copyright (C) 2016 Hubert Denkmair
+ * Copyright (c) 2023 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
*
* Many thanks to all socketcan devs!
*/
@@ -24,6 +25,7 @@
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
+#include <linux/can/rx-offload.h>
/* Device specific constants */
#define USB_GS_USB_1_VENDOR_ID 0x1d50
@@ -282,6 +284,8 @@ struct gs_host_frame {
#define GS_MAX_TX_URBS 10
/* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */
#define GS_MAX_RX_URBS 30
+#define GS_NAPI_WEIGHT 32
+
/* Maximum number of interfaces the driver supports per device.
* Current hardware only supports 3 interfaces. The future may vary.
*/
@@ -295,6 +299,7 @@ struct gs_tx_context {
struct gs_can {
struct can_priv can; /* must be the first member */
+ struct can_rx_offload offload;
struct gs_usb *parent;
struct net_device *netdev;
@@ -506,27 +511,64 @@ static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
}
}
-static void gs_usb_set_timestamp(struct gs_can *dev, struct sk_buff *skb,
- const struct gs_host_frame *hf)
+static u32 gs_usb_set_timestamp(struct gs_can *dev, struct sk_buff *skb,
+ const struct gs_host_frame *hf)
{
u32 timestamp;
- if (!(dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP))
- return;
-
if (hf->flags & GS_CAN_FLAG_FD)
timestamp = le32_to_cpu(hf->canfd_ts->timestamp_us);
else
timestamp = le32_to_cpu(hf->classic_can_ts->timestamp_us);
- gs_usb_skb_set_timestamp(dev, skb, timestamp);
+ if (skb)
+ gs_usb_skb_set_timestamp(dev, skb, timestamp);
+
+ return timestamp;
+}
+
+static void gs_usb_rx_offload(struct gs_can *dev, struct sk_buff *skb,
+ const struct gs_host_frame *hf)
+{
+ struct can_rx_offload *offload = &dev->offload;
+ int rc;
+
+ if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) {
+ const u32 ts = gs_usb_set_timestamp(dev, skb, hf);
+
+ rc = can_rx_offload_queue_timestamp(offload, skb, ts);
+ } else {
+ rc = can_rx_offload_queue_tail(offload, skb);
+ }
+
+ if (rc)
+ dev->netdev->stats.rx_fifo_errors++;
+}
+
+static unsigned int
+gs_usb_get_echo_skb(struct gs_can *dev, struct sk_buff *skb,
+ const struct gs_host_frame *hf)
+{
+ struct can_rx_offload *offload = &dev->offload;
+ const u32 echo_id = hf->echo_id;
+ unsigned int len;
+
+ if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) {
+ const u32 ts = gs_usb_set_timestamp(dev, skb, hf);
+
+ len = can_rx_offload_get_echo_skb_queue_timestamp(offload, echo_id,
+ ts, NULL);
+ } else {
+ len = can_rx_offload_get_echo_skb_queue_tail(offload, echo_id,
+ NULL);
+ }
- return;
+ return len;
}
static void gs_usb_receive_bulk_callback(struct urb *urb)
{
- struct gs_usb *usbcan = urb->context;
+ struct gs_usb *parent = urb->context;
struct gs_can *dev;
struct net_device *netdev;
int rc;
@@ -537,7 +579,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
struct canfd_frame *cfd;
struct sk_buff *skb;
- BUG_ON(!usbcan);
+ BUG_ON(!parent);
switch (urb->status) {
case 0: /* success */
@@ -554,7 +596,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->channel >= GS_MAX_INTF)
goto device_detach;
- dev = usbcan->canch[hf->channel];
+ dev = parent->canch[hf->channel];
netdev = dev->netdev;
stats = &netdev->stats;
@@ -567,7 +609,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->echo_id == -1) { /* normal rx */
if (hf->flags & GS_CAN_FLAG_FD) {
- skb = alloc_canfd_skb(dev->netdev, &cfd);
+ skb = alloc_canfd_skb(netdev, &cfd);
if (!skb)
return;
@@ -580,7 +622,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
memcpy(cfd->data, hf->canfd->data, cfd->len);
} else {
- skb = alloc_can_skb(dev->netdev, &cf);
+ skb = alloc_can_skb(netdev, &cf);
if (!skb)
return;
@@ -594,12 +636,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
gs_update_state(dev, cf);
}
- gs_usb_set_timestamp(dev, skb, hf);
-
- netdev->stats.rx_packets++;
- netdev->stats.rx_bytes += hf->can_dlc;
-
- netif_rx(skb);
+ gs_usb_rx_offload(dev, skb, hf);
} else { /* echo_id == hf->echo_id */
if (hf->echo_id >= GS_MAX_TX_URBS) {
netdev_err(netdev,
@@ -619,12 +656,8 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
}
skb = dev->can.echo_skb[hf->echo_id];
- gs_usb_set_timestamp(dev, skb, hf);
-
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += can_get_echo_skb(netdev, hf->echo_id,
- NULL);
-
+ stats->tx_packets++;
+ stats->tx_bytes += gs_usb_get_echo_skb(dev, skb, hf);
gs_free_tx_context(txc);
atomic_dec(&dev->active_tx_urbs);
@@ -633,6 +666,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
}
if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
skb = alloc_can_err_skb(netdev, &cf);
if (!skb)
goto resubmit_urb;
@@ -640,25 +676,26 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
cf->can_id |= CAN_ERR_CRTL;
cf->len = CAN_ERR_DLC;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
- stats->rx_over_errors++;
- stats->rx_errors++;
- netif_rx(skb);
+
+ gs_usb_rx_offload(dev, skb, hf);
}
- resubmit_urb:
- usb_fill_bulk_urb(urb, usbcan->udev,
- usb_rcvbulkpipe(usbcan->udev, GS_USB_ENDPOINT_IN),
+ can_rx_offload_irq_finish(&dev->offload);
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, parent->udev,
+ usb_rcvbulkpipe(parent->udev, GS_USB_ENDPOINT_IN),
hf, dev->parent->hf_size_rx,
- gs_usb_receive_bulk_callback, usbcan);
+ gs_usb_receive_bulk_callback, parent);
rc = usb_submit_urb(urb, GFP_ATOMIC);
/* USB failure take down all interfaces */
if (rc == -ENODEV) {
- device_detach:
+device_detach:
for (rc = 0; rc < GS_MAX_INTF; rc++) {
- if (usbcan->canch[rc])
- netif_device_detach(usbcan->canch[rc]->netdev);
+ if (parent->canch[rc])
+ netif_device_detach(parent->canch[rc]->netdev);
}
}
}
@@ -742,10 +779,8 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
goto nomem_urb;
hf = kmalloc(dev->hf_size_tx, GFP_ATOMIC);
- if (!hf) {
- netdev_err(netdev, "No memory left for USB buffer\n");
+ if (!hf)
goto nomem_hf;
- }
idx = txc->echo_id;
@@ -818,12 +853,12 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
- badidx:
+badidx:
kfree(hf);
- nomem_hf:
+nomem_hf:
usb_free_urb(urb);
- nomem_urb:
+nomem_urb:
gs_free_tx_context(txc);
dev_kfree_skb(skb);
stats->tx_dropped++;
@@ -860,6 +895,8 @@ static int gs_can_open(struct net_device *netdev)
dev->hf_size_tx = struct_size(hf, classic_can, 1);
}
+ can_rx_offload_enable(&dev->offload);
+
if (!parent->active_channels) {
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
gs_usb_timestamp_init(parent);
@@ -878,8 +915,6 @@ static int gs_can_open(struct net_device *netdev)
buf = kmalloc(dev->parent->hf_size_rx,
GFP_KERNEL);
if (!buf) {
- netdev_err(netdev,
- "No memory left for USB buffer\n");
rc = -ENOMEM;
goto out_usb_free_urb;
}
@@ -902,7 +937,8 @@ static int gs_can_open(struct net_device *netdev)
netif_device_detach(dev->netdev);
netdev_err(netdev,
- "usb_submit failed (err=%d)\n", rc);
+ "usb_submit_urb() failed, error %pe\n",
+ ERR_PTR(rc));
goto out_usb_unanchor_urb;
}
@@ -969,6 +1005,7 @@ out_usb_kill_anchored_urbs:
gs_usb_timestamp_stop(parent);
}
+ can_rx_offload_disable(&dev->offload);
close_candev(netdev);
return rc;
@@ -1033,9 +1070,7 @@ static int gs_can_close(struct net_device *netdev)
dev->can.state = CAN_STATE_STOPPED;
/* reset the device */
- rc = gs_cmd_reset(dev);
- if (rc < 0)
- netdev_warn(netdev, "Couldn't shutdown device (err=%d)", rc);
+ gs_cmd_reset(dev);
/* reset tx contexts */
for (rc = 0; rc < GS_MAX_TX_URBS; rc++) {
@@ -1043,6 +1078,8 @@ static int gs_can_close(struct net_device *netdev)
dev->tx_context[rc].echo_id = GS_MAX_TX_URBS;
}
+ can_rx_offload_disable(&dev->offload);
+
/* close the netdev */
close_candev(netdev);
@@ -1342,6 +1379,7 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.data_bittiming_const = &dev->data_bt_const;
}
+ can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT);
SET_NETDEV_DEV(netdev, &intf->dev);
rc = register_candev(dev->netdev);
@@ -1349,12 +1387,14 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev_err(&intf->dev,
"Couldn't register candev for channel %d (%pe)\n",
channel, ERR_PTR(rc));
- goto out_free_candev;
+ goto out_can_rx_offload_del;
}
return dev;
- out_free_candev:
+out_can_rx_offload_del:
+ can_rx_offload_del(&dev->offload);
+out_free_candev:
free_candev(dev->netdev);
return ERR_PTR(rc);
}
@@ -1362,7 +1402,7 @@ static struct gs_can *gs_make_candev(unsigned int channel,
static void gs_destroy_candev(struct gs_can *dev)
{
unregister_candev(dev->netdev);
- usb_kill_anchored_urbs(&dev->tx_submitted);
+ can_rx_offload_del(&dev->offload);
free_candev(dev->netdev);
}
@@ -1371,7 +1411,7 @@ static int gs_usb_probe(struct usb_interface *intf,
{
struct usb_device *udev = interface_to_usbdev(intf);
struct gs_host_frame *hf;
- struct gs_usb *dev;
+ struct gs_usb *parent;
struct gs_host_config hconf = {
.byte_order = cpu_to_le32(0x0000beef),
};
@@ -1414,49 +1454,49 @@ static int gs_usb_probe(struct usb_interface *intf,
return -EINVAL;
}
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
+ parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+ if (!parent)
return -ENOMEM;
- init_usb_anchor(&dev->rx_submitted);
+ init_usb_anchor(&parent->rx_submitted);
- usb_set_intfdata(intf, dev);
- dev->udev = udev;
+ usb_set_intfdata(intf, parent);
+ parent->udev = udev;
for (i = 0; i < icount; i++) {
unsigned int hf_size_rx = 0;
- dev->canch[i] = gs_make_candev(i, intf, &dconf);
- if (IS_ERR_OR_NULL(dev->canch[i])) {
+ parent->canch[i] = gs_make_candev(i, intf, &dconf);
+ if (IS_ERR_OR_NULL(parent->canch[i])) {
/* save error code to return later */
- rc = PTR_ERR(dev->canch[i]);
+ rc = PTR_ERR(parent->canch[i]);
/* on failure destroy previously created candevs */
icount = i;
for (i = 0; i < icount; i++)
- gs_destroy_candev(dev->canch[i]);
+ gs_destroy_candev(parent->canch[i]);
- usb_kill_anchored_urbs(&dev->rx_submitted);
- kfree(dev);
+ usb_kill_anchored_urbs(&parent->rx_submitted);
+ kfree(parent);
return rc;
}
- dev->canch[i]->parent = dev;
+ parent->canch[i]->parent = parent;
/* set RX packet size based on FD and if hardware
- * timestamps are supported.
- */
- if (dev->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
- if (dev->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+ * timestamps are supported.
+ */
+ if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+ if (parent->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
hf_size_rx = struct_size(hf, canfd_ts, 1);
else
hf_size_rx = struct_size(hf, canfd, 1);
} else {
- if (dev->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+ if (parent->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
hf_size_rx = struct_size(hf, classic_can_ts, 1);
else
hf_size_rx = struct_size(hf, classic_can, 1);
}
- dev->hf_size_rx = max(dev->hf_size_rx, hf_size_rx);
+ parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx);
}
return 0;
@@ -1464,22 +1504,21 @@ static int gs_usb_probe(struct usb_interface *intf,
static void gs_usb_disconnect(struct usb_interface *intf)
{
- struct gs_usb *dev = usb_get_intfdata(intf);
+ struct gs_usb *parent = usb_get_intfdata(intf);
unsigned int i;
usb_set_intfdata(intf, NULL);
- if (!dev) {
+ if (!parent) {
dev_err(&intf->dev, "Disconnect (nodata)\n");
return;
}
for (i = 0; i < GS_MAX_INTF; i++)
- if (dev->canch[i])
- gs_destroy_candev(dev->canch[i]);
+ if (parent->canch[i])
+ gs_destroy_candev(parent->canch[i]);
- usb_kill_anchored_urbs(&dev->rx_submitted);
- kfree(dev);
+ kfree(parent);
}
static const struct usb_device_id gs_usb_table[] = {
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index d881e1d30183..24ad9f593a77 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -214,19 +214,6 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
}
}
-/*
- * post received skb after having set any hw timestamp
- */
-int peak_usb_netif_rx(struct sk_buff *skb,
- struct peak_time_ref *time_ref, u32 ts_low)
-{
- struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
-
- peak_usb_get_ts_time(time_ref, ts_low, &hwts->hwtstamp);
-
- return netif_rx(skb);
-}
-
/* post received skb with native 64-bit hw timestamp */
int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high)
{
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index 980e315186cf..f6cf84bb718f 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -142,8 +142,6 @@ void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *tv);
-int peak_usb_netif_rx(struct sk_buff *skb,
- struct peak_time_ref *time_ref, u32 ts_low);
int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high);
void peak_usb_async_complete(struct urb *urb);
void peak_usb_restart_complete(struct peak_usb_device *dev);
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index a0f7bcec719c..39a63b7313a4 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -284,7 +284,7 @@ struct ucan_priv {
*/
spinlock_t echo_skb_lock;
- /* usb device information information */
+ /* usb device information */
u8 intf_index;
u8 in_ep_addr;
u8 out_ep_addr;
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
index 4068d962203d..98c669ad5141 100644
--- a/drivers/net/can/vxcan.c
+++ b/drivers/net/can/vxcan.c
@@ -192,12 +192,7 @@ static int vxcan_newlink(struct net *net, struct net_device *dev,
nla_peer = data[VXCAN_INFO_PEER];
ifmp = nla_data(nla_peer);
- err = rtnl_nla_parse_ifla(peer_tb,
- nla_data(nla_peer) +
- sizeof(struct ifinfomsg),
- nla_len(nla_peer) -
- sizeof(struct ifinfomsg),
- NULL);
+ err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
if (err < 0)
return err;
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index 4d3283db3a13..abe58f103043 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -30,6 +30,7 @@
#include <linux/can/error.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#define DRIVER_NAME "xilinx_can"
@@ -200,6 +201,7 @@ struct xcan_devtype_data {
* @can_clk: Pointer to struct clk
* @devtype: Device type specific constants
* @transceiver: Optional pointer to associated CAN transceiver
+ * @rstc: Pointer to reset control
*/
struct xcan_priv {
struct can_priv can;
@@ -218,6 +220,7 @@ struct xcan_priv {
struct clk *can_clk;
struct xcan_devtype_data devtype;
struct phy *transceiver;
+ struct reset_control *rstc;
};
/* CAN Bittiming constants as per Xilinx CAN specs */
@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev)
priv->can.do_get_berr_counter = xcan_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_BERR_REPORTING;
+ priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(priv->rstc)) {
+ dev_err(&pdev->dev, "Cannot get CAN reset.\n");
+ ret = PTR_ERR(priv->rstc);
+ goto err_free;
+ }
+
+ ret = reset_control_reset(priv->rstc);
+ if (ret)
+ goto err_free;
if (devtype->cantype == XAXI_CANFD) {
priv->can.data_bittiming_const =
@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev)
/* Get IRQ for the device */
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto err_free;
+ goto err_reset;
ndev->irq = ret;
@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev)
if (IS_ERR(priv->can_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
"device clock not found\n");
- goto err_free;
+ goto err_reset;
}
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
"bus clock not found\n");
- goto err_free;
+ goto err_reset;
}
transceiver = devm_phy_optional_get(&pdev->dev, NULL);
if (IS_ERR(transceiver)) {
ret = PTR_ERR(transceiver);
dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
- goto err_free;
+ goto err_reset;
}
priv->transceiver = transceiver;
@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev)
err_disableclks:
pm_runtime_put(priv->dev);
pm_runtime_disable(&pdev->dev);
+err_reset:
+ reset_control_assert(priv->rstc);
err_free:
free_candev(ndev);
err:
@@ -1920,9 +1935,11 @@ err:
static void xcan_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);
unregister_candev(ndev);
pm_runtime_disable(&pdev->dev);
+ reset_control_assert(priv->rstc);
free_candev(ndev);
}
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 3ed5391bb18d..f8c1d73b251d 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -37,7 +37,6 @@ config NET_DSA_LANTIQ_GSWIP
config NET_DSA_MT7530
tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
select NET_DSA_TAG_MTK
- select MEDIATEK_GE_PHY
imply NET_DSA_MT7530_MDIO
imply NET_DSA_MT7530_MMIO
help
@@ -49,6 +48,7 @@ config NET_DSA_MT7530
config NET_DSA_MT7530_MDIO
tristate "MediaTek MT7530 MDIO interface driver"
depends on NET_DSA_MT7530
+ imply MEDIATEK_GE_PHY
select PCS_MTK_LYNXI
help
This enables support for the MediaTek MT7530 and MT7531 switch
@@ -60,6 +60,7 @@ config NET_DSA_MT7530_MMIO
tristate "MediaTek MT7530 MMIO interface driver"
depends on NET_DSA_MT7530
depends on HAS_IOMEM
+ imply MEDIATEK_GE_SOC_PHY
help
This enables support for the built-in Ethernet switch found
in the MediaTek MT7988 SoC.
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 3464ce5e7470..4e27dc913cf7 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1393,12 +1393,6 @@ static void b53_phylink_get_caps(struct dsa_switch *ds, int port,
/* Get the implementation specific capabilities */
if (dev->ops->phylink_get_caps)
dev->ops->phylink_get_caps(dev, port, config);
-
- /* This driver does not make use of the speed, duplex, pause or the
- * advertisement in its mac_config, so it is safe to mark this driver
- * as non-legacy.
- */
- config->legacy_pre_march2020 = false;
}
static struct phylink_pcs *b53_phylink_mac_select_pcs(struct dsa_switch *ds,
diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c
index 8b422b298cd5..4d55d8d18376 100644
--- a/drivers/net/dsa/b53/b53_mdio.c
+++ b/drivers/net/dsa/b53/b53_mdio.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/phy.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/delay.h>
#include <linux/brcmphy.h>
#include <linux/rtnetlink.h>
diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c
index 5db1ed26f03a..5e39641ea887 100644
--- a/drivers/net/dsa/b53/b53_mmap.c
+++ b/drivers/net/dsa/b53/b53_mmap.c
@@ -19,6 +19,7 @@
#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/platform_data/b53.h>
diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c
index b0ccebcd3ffa..3f8a491ce885 100644
--- a/drivers/net/dsa/b53/b53_serdes.c
+++ b/drivers/net/dsa/b53/b53_serdes.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Northstar Plus switch SerDes/SGMII PHY main logic
*
diff --git a/drivers/net/dsa/b53/b53_serdes.h b/drivers/net/dsa/b53/b53_serdes.h
index ef81f5da5f81..3d367c4df4d9 100644
--- a/drivers/net/dsa/b53/b53_serdes.h
+++ b/drivers/net/dsa/b53/b53_serdes.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Northstar Plus switch SerDes/SGMII PHY definitions
*
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index af50001ccdd4..11ef1d7ea229 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: (GPL-2.0 or MIT)
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* DSA driver for:
* Hirschmann Hellcreek TSN switch.
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
diff --git a/drivers/net/dsa/hirschmann/hellcreek.h b/drivers/net/dsa/hirschmann/hellcreek.h
index 4a678f7d61ae..6874cb9dc361 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.h
+++ b/drivers/net/dsa/hirschmann/hellcreek.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0 or MIT) */
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* DSA driver for:
* Hirschmann Hellcreek TSN switch.
diff --git a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
index ffd06cf8c44f..bd7aacc71a63 100644
--- a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
+++ b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
@@ -298,17 +298,10 @@ static void hellcreek_get_rxts(struct hellcreek *hellcreek,
struct sk_buff_head received;
unsigned long flags;
- /* The latched timestamp belongs to one of the received frames. */
+ /* Construct Rx timestamps for all received PTP packets. */
__skb_queue_head_init(&received);
-
- /* Lock & disable interrupts */
spin_lock_irqsave(&rxq->lock, flags);
-
- /* Add the reception queue "rxq" to the "received" queue an reintialize
- * "rxq". From now on, we deal with "received" not with "rxq"
- */
skb_queue_splice_tail_init(rxq, &received);
-
spin_unlock_irqrestore(&rxq->lock, flags);
for (; skb; skb = __skb_dequeue(&received)) {
diff --git a/drivers/net/dsa/hirschmann/hellcreek_ptp.c b/drivers/net/dsa/hirschmann/hellcreek_ptp.c
index 3e44ccb7db84..5249a1c2a80b 100644
--- a/drivers/net/dsa/hirschmann/hellcreek_ptp.c
+++ b/drivers/net/dsa/hirschmann/hellcreek_ptp.c
@@ -9,6 +9,7 @@
* Kurt Kanzenbach <kurt@linutronix.de>
*/
+#include <linux/of.h>
#include <linux/ptp_clock_kernel.h>
#include "hellcreek.h"
#include "hellcreek_ptp.h"
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index ff76444057d2..ee67adeb2cdb 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -8,6 +8,7 @@
#include <linux/regmap.h>
#include <linux/mutex.h>
#include <linux/mii.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
@@ -1290,12 +1291,6 @@ static void lan9303_phylink_get_caps(struct dsa_switch *ds, int port,
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces);
}
-
- /* This driver does not make use of the speed, duplex, pause or the
- * advertisement in its mac_config, so it is safe to mark this driver
- * as non-legacy.
- */
- config->legacy_pre_march2020 = false;
}
static void lan9303_phylink_mac_link_up(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h
index e68465fdf6b9..4cea811e73ac 100644
--- a/drivers/net/dsa/microchip/ksz8.h
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -48,13 +48,11 @@ int ksz8_port_mirror_add(struct ksz_device *dev, int port,
bool ingress, struct netlink_ext_ack *extack);
void ksz8_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror);
-int ksz8_get_stp_reg(void);
void ksz8_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
void ksz8_config_cpu_port(struct dsa_switch *ds);
int ksz8_enable_stp_addr(struct ksz_device *dev);
int ksz8_reset_switch(struct ksz_device *dev);
-int ksz8_switch_detect(struct ksz_device *dev);
int ksz8_switch_init(struct ksz_device *dev);
void ksz8_switch_exit(struct ksz_device *dev);
int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu);
diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c
index fd6e2e69a42a..5711a59e2ac9 100644
--- a/drivers/net/dsa/microchip/ksz8863_smi.c
+++ b/drivers/net/dsa/microchip/ksz8863_smi.c
@@ -5,6 +5,9 @@
* Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
*/
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+
#include "ksz8.h"
#include "ksz_common.h"
diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h
index b6f7e3c46e3f..a6f425866a29 100644
--- a/drivers/net/dsa/microchip/ksz9477.h
+++ b/drivers/net/dsa/microchip/ksz9477.h
@@ -36,7 +36,6 @@ int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
bool ingress, struct netlink_ext_ack *extack);
void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
struct dsa_mall_mirror_tc_entry *mirror);
-int ksz9477_get_stp_reg(void);
void ksz9477_get_caps(struct ksz_device *dev, int port,
struct phylink_config *config);
int ksz9477_fdb_dump(struct ksz_device *dev, int port,
@@ -54,7 +53,6 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds);
int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val);
int ksz9477_enable_stp_addr(struct ksz_device *dev);
int ksz9477_reset_switch(struct ksz_device *dev);
-int ksz9477_dsa_init(struct ksz_device *dev);
int ksz9477_switch_init(struct ksz_device *dev);
void ksz9477_switch_exit(struct ksz_device *dev);
void ksz9477_port_queue_split(struct ksz_device *dev, int port);
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 6c0623f88654..6673122266b7 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -18,8 +18,8 @@
#include <linux/if_vlan.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/micrel_phy.h>
#include <net/dsa.h>
@@ -1619,8 +1619,6 @@ static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
{
struct ksz_device *dev = ds->priv;
- config->legacy_pre_march2020 = false;
-
if (dev->info->supports_mii[port])
__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
diff --git a/drivers/net/dsa/mt7530-mmio.c b/drivers/net/dsa/mt7530-mmio.c
index 1a3d4b692f34..0a6a2fe34e64 100644
--- a/drivers/net/dsa/mt7530-mmio.c
+++ b/drivers/net/dsa/mt7530-mmio.c
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 38b3c6dda386..035a34b50f31 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1006,6 +1006,10 @@ mt753x_trap_frames(struct mt7530_priv *priv)
mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
MT753X_BPDU_CPU_ONLY);
+ /* Trap 802.1X PAE frames to the CPU port(s) */
+ mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_PORT_FW_MASK,
+ MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY));
+
/* Trap LLDP frames with :0E MAC DA to the CPU port(s) */
mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK,
MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
@@ -2949,12 +2953,6 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000FD;
- /* This driver does not make use of the speed, duplex, pause or the
- * advertisement in its mac_config, so it is safe to mark this driver
- * as non-legacy.
- */
- config->legacy_pre_march2020 = false;
-
priv->info->mac_port_get_caps(ds, port, config);
}
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 08045b035e6a..17e42d30fff4 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -66,6 +66,8 @@ enum mt753x_id {
/* Registers for BPDU and PAE frame control*/
#define MT753X_BPC 0x24
#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
+#define MT753X_PAE_PORT_FW_MASK GENMASK(18, 16)
+#define MT753X_PAE_PORT_FW(x) FIELD_PREP(MT753X_PAE_PORT_FW_MASK, x)
/* Register for :03 and :0E MAC DA frame control */
#define MT753X_RGAC2 0x2c
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index fdda62d6eb16..294312b58e4f 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -247,11 +247,56 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
return reg_write(priv, addr, regnum, val);
}
+static void mv88e6060_phylink_get_caps(struct dsa_switch *ds, int port,
+ struct phylink_config *config)
+{
+ unsigned long *interfaces = config->supported_interfaces;
+ struct mv88e6060_priv *priv = ds->priv;
+ int addr = REG_PORT(port);
+ int ret;
+
+ ret = reg_read(priv, addr, PORT_STATUS);
+ if (ret < 0) {
+ dev_err(ds->dev,
+ "port %d: unable to read status register: %pe\n",
+ port, ERR_PTR(ret));
+ return;
+ }
+
+ /* If the port is configured in SNI mode (acts as a 10Mbps PHY),
+ * it should have phy-mode = "sni", but that doesn't yet exist, so
+ * forcibly fail validation until the need arises to introduce it.
+ */
+ if (!(ret & PORT_STATUS_PORTMODE)) {
+ dev_warn(ds->dev, "port %d: SNI mode not supported\n", port);
+ return;
+ }
+
+ config->mac_capabilities = MAC_100 | MAC_10 | MAC_SYM_PAUSE;
+
+ if (port >= 4) {
+ /* Ports 4 and 5 can support MII, REVMII and REVRMII modes */
+ __set_bit(PHY_INTERFACE_MODE_MII, interfaces);
+ __set_bit(PHY_INTERFACE_MODE_REVMII, interfaces);
+ __set_bit(PHY_INTERFACE_MODE_REVRMII, interfaces);
+ }
+ if (port <= 4) {
+ /* Ports 0 to 3 have internal PHYs, and port 4 can optionally
+ * use an internal PHY.
+ */
+ /* Internal PHY */
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);
+ /* Default phylib interface mode */
+ __set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
+ }
+}
+
static const struct dsa_switch_ops mv88e6060_switch_ops = {
.get_tag_protocol = mv88e6060_get_tag_protocol,
.setup = mv88e6060_setup,
.phy_read = mv88e6060_phy_read,
.phy_write = mv88e6060_phy_write,
+ .phylink_get_caps = mv88e6060_phylink_get_caps,
};
static int mv88e6060_probe(struct mdio_device *mdiodev)
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 1409e691ab77..a9a9651187db 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -9,6 +9,9 @@ mv88e6xxx-objs += global2.o
mv88e6xxx-objs += global2_avb.o
mv88e6xxx-objs += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
+mv88e6xxx-objs += pcs-6185.o
+mv88e6xxx-objs += pcs-6352.o
+mv88e6xxx-objs += pcs-639x.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7af2f08a62f1..52a99d8bada0 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -23,7 +23,7 @@
#include <linux/list.h>
#include <linux/mdio.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/platform_data/mv88e6xxx.h>
@@ -499,81 +499,6 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT);
}
-static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port,
- struct phylink_link_state *state)
-{
- struct mv88e6xxx_chip *chip = ds->priv;
- int lane;
- int err;
-
- mv88e6xxx_reg_lock(chip);
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0 && chip->info->ops->serdes_pcs_get_state)
- err = chip->info->ops->serdes_pcs_get_state(chip, port, lane,
- state);
- else
- err = -EOPNOTSUPP;
- mv88e6xxx_reg_unlock(chip);
-
- return err;
-}
-
-static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise)
-{
- const struct mv88e6xxx_ops *ops = chip->info->ops;
- int lane;
-
- if (ops->serdes_pcs_config) {
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0)
- return ops->serdes_pcs_config(chip, port, lane, mode,
- interface, advertise);
- }
-
- return 0;
-}
-
-static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port)
-{
- struct mv88e6xxx_chip *chip = ds->priv;
- const struct mv88e6xxx_ops *ops;
- int err = 0;
- int lane;
-
- ops = chip->info->ops;
-
- if (ops->serdes_pcs_an_restart) {
- mv88e6xxx_reg_lock(chip);
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0)
- err = ops->serdes_pcs_an_restart(chip, port, lane);
- mv88e6xxx_reg_unlock(chip);
-
- if (err)
- dev_err(ds->dev, "p%d: failed to restart AN\n", port);
- }
-}
-
-static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- unsigned int mode,
- int speed, int duplex)
-{
- const struct mv88e6xxx_ops *ops = chip->info->ops;
- int lane;
-
- if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) {
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0)
- return ops->serdes_pcs_link_up(chip, port, lane,
- speed, duplex);
- }
-
- return 0;
-}
-
static const u8 mv88e6185_phy_interface_modes[] = {
[MV88E6185_PORT_STS_CMODE_GMII_FD] = PHY_INTERFACE_MODE_GMII,
[MV88E6185_PORT_STS_CMODE_MII_100_FD_PS] = PHY_INTERFACE_MODE_MII,
@@ -853,6 +778,20 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
}
}
+static struct phylink_pcs *mv88e6xxx_mac_select_pcs(struct dsa_switch *ds,
+ int port,
+ phy_interface_t interface)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
+
+ if (chip->info->ops->pcs_ops)
+ pcs = chip->info->ops->pcs_ops->pcs_select(chip, port,
+ interface);
+
+ return pcs;
+}
+
static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface)
{
@@ -889,16 +828,6 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
state->interface);
if (err && err != -EOPNOTSUPP)
goto err_unlock;
-
- err = mv88e6xxx_serdes_pcs_config(chip, port, mode,
- state->interface,
- state->advertising);
- /* FIXME: we should restart negotiation if something changed -
- * which is something we get if we convert to using phylinks
- * PCS operations.
- */
- if (err > 0)
- err = 0;
}
err_unlock:
@@ -982,17 +911,6 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
*/
if (!mv88e6xxx_port_ppu_updates(chip, port) ||
mode == MLO_AN_FIXED) {
- /* FIXME: for an automedia port, should we force the link
- * down here - what if the link comes up due to "other" media
- * while we're bringing the port up, how is the exclusivity
- * handled in the Marvell hardware? E.g. port 2 on 88E6390
- * shared between internal PHY and Serdes.
- */
- err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed,
- duplex);
- if (err)
- goto error;
-
if (ops->port_set_speed_duplex) {
err = ops->port_set_speed_duplex(chip, port,
speed, duplex);
@@ -3171,102 +3089,6 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
return 0;
}
-static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id)
-{
- struct mv88e6xxx_port *mvp = dev_id;
- struct mv88e6xxx_chip *chip = mvp->chip;
- irqreturn_t ret = IRQ_NONE;
- int port = mvp->port;
- int lane;
-
- mv88e6xxx_reg_lock(chip);
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0)
- ret = mv88e6xxx_serdes_irq_status(chip, port, lane);
- mv88e6xxx_reg_unlock(chip);
-
- return ret;
-}
-
-static int mv88e6xxx_serdes_irq_request(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- struct mv88e6xxx_port *dev_id = &chip->ports[port];
- unsigned int irq;
- int err;
-
- /* Nothing to request if this SERDES port has no IRQ */
- irq = mv88e6xxx_serdes_irq_mapping(chip, port);
- if (!irq)
- return 0;
-
- snprintf(dev_id->serdes_irq_name, sizeof(dev_id->serdes_irq_name),
- "mv88e6xxx-%s-serdes-%d", dev_name(chip->dev), port);
-
- /* Requesting the IRQ will trigger IRQ callbacks, so release the lock */
- mv88e6xxx_reg_unlock(chip);
- err = request_threaded_irq(irq, NULL, mv88e6xxx_serdes_irq_thread_fn,
- IRQF_ONESHOT, dev_id->serdes_irq_name,
- dev_id);
- mv88e6xxx_reg_lock(chip);
- if (err)
- return err;
-
- dev_id->serdes_irq = irq;
-
- return mv88e6xxx_serdes_irq_enable(chip, port, lane);
-}
-
-static int mv88e6xxx_serdes_irq_free(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- struct mv88e6xxx_port *dev_id = &chip->ports[port];
- unsigned int irq = dev_id->serdes_irq;
- int err;
-
- /* Nothing to free if no IRQ has been requested */
- if (!irq)
- return 0;
-
- err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
-
- /* Freeing the IRQ will trigger IRQ callbacks, so release the lock */
- mv88e6xxx_reg_unlock(chip);
- free_irq(irq, dev_id);
- mv88e6xxx_reg_lock(chip);
-
- dev_id->serdes_irq = 0;
-
- return err;
-}
-
-static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
- bool on)
-{
- int lane;
- int err;
-
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane < 0)
- return 0;
-
- if (on) {
- err = mv88e6xxx_serdes_power_up(chip, port, lane);
- if (err)
- return err;
-
- err = mv88e6xxx_serdes_irq_request(chip, port, lane);
- } else {
- err = mv88e6xxx_serdes_irq_free(chip, port, lane);
- if (err)
- return err;
-
- err = mv88e6xxx_serdes_power_down(chip, port, lane);
- }
-
- return err;
-}
-
static int mv88e6xxx_set_egress_port(struct mv88e6xxx_chip *chip,
enum mv88e6xxx_egress_direction direction,
int port)
@@ -3330,56 +3152,17 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
{
struct device_node *phy_handle = NULL;
struct dsa_switch *ds = chip->ds;
- phy_interface_t mode;
struct dsa_port *dp;
- int tx_amp, speed;
+ int tx_amp;
int err;
u16 reg;
chip->ports[port].chip = chip;
chip->ports[port].port = port;
- dp = dsa_to_port(ds, port);
-
- /* MAC Forcing register: don't force link, speed, duplex or flow control
- * state to any particular values on physical ports, but force the CPU
- * port and all DSA ports to their maximum bandwidth and full duplex.
- */
- if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
- struct phylink_config pl_config = {};
- unsigned long caps;
-
- chip->info->ops->phylink_get_caps(chip, port, &pl_config);
-
- caps = pl_config.mac_capabilities;
-
- if (chip->info->ops->port_max_speed_mode)
- mode = chip->info->ops->port_max_speed_mode(chip, port);
- else
- mode = PHY_INTERFACE_MODE_NA;
-
- if (caps & MAC_10000FD)
- speed = SPEED_10000;
- else if (caps & MAC_5000FD)
- speed = SPEED_5000;
- else if (caps & MAC_2500FD)
- speed = SPEED_2500;
- else if (caps & MAC_1000)
- speed = SPEED_1000;
- else if (caps & MAC_100)
- speed = SPEED_100;
- else
- speed = SPEED_10;
-
- err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
- speed, DUPLEX_FULL,
- PAUSE_OFF, mode);
- } else {
- err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
- SPEED_UNFORCED, DUPLEX_UNFORCED,
- PAUSE_ON,
- PHY_INTERFACE_MODE_NA);
- }
+ err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
+ SPEED_UNFORCED, DUPLEX_UNFORCED,
+ PAUSE_ON, PHY_INTERFACE_MODE_NA);
if (err)
return err;
@@ -3556,6 +3339,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
}
if (chip->info->ops->serdes_set_tx_amplitude) {
+ dp = dsa_to_port(ds, port);
if (dp)
phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0);
@@ -3629,29 +3413,6 @@ static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
return ret;
}
-static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
- struct phy_device *phydev)
-{
- struct mv88e6xxx_chip *chip = ds->priv;
- int err;
-
- mv88e6xxx_reg_lock(chip);
- err = mv88e6xxx_serdes_power(chip, port, true);
- mv88e6xxx_reg_unlock(chip);
-
- return err;
-}
-
-static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
-{
- struct mv88e6xxx_chip *chip = ds->priv;
-
- mv88e6xxx_reg_lock(chip);
- if (mv88e6xxx_serdes_power(chip, port, false))
- dev_err(chip->dev, "failed to power off SERDES\n");
- mv88e6xxx_reg_unlock(chip);
-}
-
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time)
{
@@ -4114,12 +3875,26 @@ out_mdios:
static int mv88e6xxx_port_setup(struct dsa_switch *ds, int port)
{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int err;
+
+ if (chip->info->ops->pcs_ops->pcs_init) {
+ err = chip->info->ops->pcs_ops->pcs_init(chip, port);
+ if (err)
+ return err;
+ }
+
return mv88e6xxx_setup_devlink_regions_port(ds, port);
}
static void mv88e6xxx_port_teardown(struct dsa_switch *ds, int port)
{
+ struct mv88e6xxx_chip *chip = ds->priv;
+
mv88e6xxx_teardown_devlink_regions_port(ds, port);
+
+ if (chip->info->ops->pcs_ops->pcs_teardown)
+ chip->info->ops->pcs_ops->pcs_teardown(chip, port);
}
static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds)
@@ -4236,15 +4011,13 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_get_strings = mv88e6095_stats_get_strings,
.stats_get_stats = mv88e6095_stats_get_stats,
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
- .serdes_power = mv88e6185_serdes_power,
- .serdes_get_lane = mv88e6185_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
.ppu_enable = mv88e6185_g1_ppu_enable,
.ppu_disable = mv88e6185_g1_ppu_disable,
.reset = mv88e6185_g1_reset,
.vtu_getnext = mv88e6185_g1_vtu_getnext,
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.phylink_get_caps = mv88e6095_phylink_get_caps,
+ .pcs_ops = &mv88e6185_pcs_ops,
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
};
@@ -4282,18 +4055,14 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
- .serdes_power = mv88e6185_serdes_power,
- .serdes_get_lane = mv88e6185_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6097_serdes_irq_enable,
- .serdes_irq_status = mv88e6097_serdes_irq_status,
.pot_clear = mv88e6xxx_g2_pot_clear,
.reset = mv88e6352_g1_reset,
.rmu_disable = mv88e6085_g1_rmu_disable,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.phylink_get_caps = mv88e6095_phylink_get_caps,
+ .pcs_ops = &mv88e6185_pcs_ops,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
@@ -4429,16 +4198,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6341_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.gpio_ops = &mv88e6352_gpio_ops,
.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
.serdes_get_strings = mv88e6390_serdes_get_strings,
@@ -4446,6 +4207,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
.serdes_get_regs = mv88e6390_serdes_get_regs,
.phylink_get_caps = mv88e6341_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6161_ops = {
@@ -4626,16 +4388,11 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_get_lane = mv88e6352_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6352_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
- .serdes_power = mv88e6352_serdes_power,
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
.serdes_get_regs = mv88e6352_serdes_get_regs,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_get_caps = mv88e6352_phylink_get_caps,
+ .pcs_ops = &mv88e6352_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -4731,20 +4488,13 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_get_lane = mv88e6352_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6352_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
- .serdes_power = mv88e6352_serdes_power,
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6352_serdes_irq_enable,
- .serdes_irq_status = mv88e6352_serdes_irq_status,
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
.serdes_get_regs = mv88e6352_serdes_get_regs,
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_get_caps = mv88e6352_phylink_get_caps,
+ .pcs_ops = &mv88e6352_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -4774,9 +4524,6 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
- .serdes_power = mv88e6185_serdes_power,
- .serdes_get_lane = mv88e6185_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
.set_cascade_port = mv88e6185_g1_set_cascade_port,
.ppu_enable = mv88e6185_g1_ppu_enable,
.ppu_disable = mv88e6185_g1_ppu_disable,
@@ -4784,6 +4531,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.vtu_getnext = mv88e6185_g1_vtu_getnext,
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.phylink_get_caps = mv88e6185_phylink_get_caps,
+ .pcs_ops = &mv88e6185_pcs_ops,
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
};
@@ -4834,22 +4582,15 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.serdes_get_strings = mv88e6390_serdes_get_strings,
.serdes_get_stats = mv88e6390_serdes_get_stats,
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
.serdes_get_regs = mv88e6390_serdes_get_regs,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_get_caps = mv88e6390_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6190x_ops = {
@@ -4899,22 +4640,15 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.serdes_get_strings = mv88e6390_serdes_get_strings,
.serdes_get_stats = mv88e6390_serdes_get_stats,
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
.serdes_get_regs = mv88e6390_serdes_get_regs,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_get_caps = mv88e6390x_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6191_ops = {
@@ -4962,16 +4696,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.serdes_get_strings = mv88e6390_serdes_get_strings,
.serdes_get_stats = mv88e6390_serdes_get_stats,
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
@@ -4979,6 +4705,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
.phylink_get_caps = mv88e6390_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -5028,15 +4755,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_get_lane = mv88e6352_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6352_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
- .serdes_power = mv88e6352_serdes_power,
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6352_serdes_irq_enable,
- .serdes_irq_status = mv88e6352_serdes_irq_status,
.serdes_get_regs_len = mv88e6352_serdes_get_regs_len,
.serdes_get_regs = mv88e6352_serdes_get_regs,
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
@@ -5044,6 +4763,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
.phylink_get_caps = mv88e6352_phylink_get_caps,
+ .pcs_ops = &mv88e6352_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6250_ops = {
@@ -5135,16 +4855,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.serdes_get_strings = mv88e6390_serdes_get_strings,
.serdes_get_stats = mv88e6390_serdes_get_stats,
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
@@ -5153,6 +4865,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6390_ptp_ops,
.phylink_get_caps = mv88e6390_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -5297,16 +5010,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6341_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
@@ -5316,6 +5021,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
.serdes_get_regs = mv88e6390_serdes_get_regs,
.phylink_get_caps = mv88e6341_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -5459,15 +5165,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.stu_getnext = mv88e6352_g1_stu_getnext,
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
- .serdes_get_lane = mv88e6352_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6352_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up,
- .serdes_power = mv88e6352_serdes_power,
.serdes_irq_mapping = mv88e6352_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6352_serdes_irq_enable,
- .serdes_irq_status = mv88e6352_serdes_irq_status,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
@@ -5478,6 +5176,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.serdes_get_regs = mv88e6352_serdes_get_regs,
.serdes_set_tx_amplitude = mv88e6352_serdes_set_tx_amplitude,
.phylink_get_caps = mv88e6352_phylink_get_caps,
+ .pcs_ops = &mv88e6352_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
@@ -5528,16 +5227,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
- /* Check status register pause & lpa register */
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6390_ptp_ops,
@@ -5547,6 +5238,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.serdes_get_regs_len = mv88e6390_serdes_get_regs_len,
.serdes_get_regs = mv88e6390_serdes_get_regs,
.phylink_get_caps = mv88e6390_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -5597,15 +5289,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6390_serdes_irq_enable,
- .serdes_irq_status = mv88e6390_serdes_irq_status,
.serdes_get_sset_count = mv88e6390_serdes_get_sset_count,
.serdes_get_strings = mv88e6390_serdes_get_strings,
.serdes_get_stats = mv88e6390_serdes_get_stats,
@@ -5615,11 +5300,11 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6390_ptp_ops,
.phylink_get_caps = mv88e6390x_phylink_get_caps,
+ .pcs_ops = &mv88e6390_pcs_ops,
};
static const struct mv88e6xxx_ops mv88e6393x_ops = {
/* MV88E6XXX_FAMILY_6393 */
- .setup_errata = mv88e6393x_serdes_setup_errata,
.irl_init_all = mv88e6390_g2_irl_init_all,
.get_eeprom = mv88e6xxx_g2_get_eeprom8,
.set_eeprom = mv88e6xxx_g2_set_eeprom8,
@@ -5669,20 +5354,14 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.stu_getnext = mv88e6390_g1_stu_getnext,
.stu_loadpurge = mv88e6390_g1_stu_loadpurge,
- .serdes_power = mv88e6393x_serdes_power,
.serdes_get_lane = mv88e6393x_serdes_get_lane,
- .serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state,
- .serdes_pcs_config = mv88e6390_serdes_pcs_config,
- .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
- .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
- .serdes_irq_enable = mv88e6393x_serdes_irq_enable,
- .serdes_irq_status = mv88e6393x_serdes_irq_status,
/* TODO: serdes stats */
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
.phylink_get_caps = mv88e6393x_phylink_get_caps,
+ .pcs_ops = &mv88e6393x_pcs_ops,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
@@ -7114,18 +6793,15 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.port_setup = mv88e6xxx_port_setup,
.port_teardown = mv88e6xxx_port_teardown,
.phylink_get_caps = mv88e6xxx_get_caps,
- .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state,
+ .phylink_mac_select_pcs = mv88e6xxx_mac_select_pcs,
.phylink_mac_prepare = mv88e6xxx_mac_prepare,
.phylink_mac_config = mv88e6xxx_mac_config,
.phylink_mac_finish = mv88e6xxx_mac_finish,
- .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart,
.phylink_mac_link_down = mv88e6xxx_mac_link_down,
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
- .port_enable = mv88e6xxx_port_enable,
- .port_disable = mv88e6xxx_port_disable,
.port_max_mtu = mv88e6xxx_get_max_mtu,
.port_change_mtu = mv88e6xxx_change_mtu,
.get_mac_eee = mv88e6xxx_get_mac_eee,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 0ad34b2d8913..44383a03ef2f 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -205,6 +205,7 @@ struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops;
struct mv88e6xxx_avb_ops;
struct mv88e6xxx_ptp_ops;
+struct mv88e6xxx_pcs_ops;
struct mv88e6xxx_irq {
u16 masked;
@@ -285,9 +286,8 @@ struct mv88e6xxx_port {
u8 cmode;
bool mirror_ingress;
bool mirror_egress;
- unsigned int serdes_irq;
- char serdes_irq_name[64];
struct devlink_region *region;
+ void *pcs_private;
/* MacAuth Bypass control flag */
bool mab;
@@ -590,31 +590,12 @@ struct mv88e6xxx_ops {
int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);
- /* Power on/off a SERDES interface */
- int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, int lane,
- bool up);
-
/* SERDES lane mapping */
int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port);
- int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state);
- int (*serdes_pcs_config)(struct mv88e6xxx_chip *chip, int port,
- int lane, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise);
- int (*serdes_pcs_an_restart)(struct mv88e6xxx_chip *chip, int port,
- int lane);
- int (*serdes_pcs_link_up)(struct mv88e6xxx_chip *chip, int port,
- int lane, int speed, int duplex);
-
/* SERDES interrupt handling */
unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip,
int port);
- int (*serdes_irq_enable)(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable);
- irqreturn_t (*serdes_irq_status)(struct mv88e6xxx_chip *chip, int port,
- int lane);
/* Statistics from the SERDES interface */
int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
@@ -664,6 +645,8 @@ struct mv88e6xxx_ops {
void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port,
struct phylink_config *config);
+ const struct mv88e6xxx_pcs_ops *pcs_ops;
+
/* Max Frame Size */
int (*set_max_frame_size)(struct mv88e6xxx_chip *chip, int mtu);
};
@@ -736,6 +719,14 @@ struct mv88e6xxx_ptp_ops {
u32 cc_mult_dem;
};
+struct mv88e6xxx_pcs_ops {
+ int (*pcs_init)(struct mv88e6xxx_chip *chip, int port);
+ void (*pcs_teardown)(struct mv88e6xxx_chip *chip, int port);
+ struct phylink_pcs *(*pcs_select)(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+
+};
+
#define STATS_TYPE_PORT BIT(0)
#define STATS_TYPE_BANK0 BIT(1)
#define STATS_TYPE_BANK1 BIT(2)
diff --git a/drivers/net/dsa/mv88e6xxx/pcs-6185.c b/drivers/net/dsa/mv88e6xxx/pcs-6185.c
new file mode 100644
index 000000000000..4d677f836807
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/pcs-6185.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6185 family SERDES PCS support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ */
+#include <linux/phylink.h>
+
+#include "global2.h"
+#include "port.h"
+#include "serdes.h"
+
+struct mv88e6185_pcs {
+ struct phylink_pcs phylink_pcs;
+ unsigned int irq;
+ char name[64];
+
+ struct mv88e6xxx_chip *chip;
+ int port;
+};
+
+static struct mv88e6185_pcs *pcs_to_mv88e6185_pcs(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct mv88e6185_pcs, phylink_pcs);
+}
+
+static irqreturn_t mv88e6185_pcs_handle_irq(int irq, void *dev_id)
+{
+ struct mv88e6185_pcs *mpcs = dev_id;
+ struct mv88e6xxx_chip *chip;
+ irqreturn_t ret = IRQ_NONE;
+ bool link_up;
+ u16 status;
+ int port;
+ int err;
+
+ chip = mpcs->chip;
+ port = mpcs->port;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (!err) {
+ link_up = !!(status & MV88E6XXX_PORT_STS_LINK);
+
+ phylink_pcs_change(&mpcs->phylink_pcs, link_up);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static void mv88e6185_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct mv88e6185_pcs *mpcs = pcs_to_mv88e6185_pcs(pcs);
+ struct mv88e6xxx_chip *chip = mpcs->chip;
+ int port = mpcs->port;
+ u16 status;
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
+ mv88e6xxx_reg_unlock(chip);
+
+ if (err)
+ status = 0;
+
+ state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
+ if (state->link) {
+ state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ?
+ DUPLEX_FULL : DUPLEX_HALF;
+
+ switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) {
+ case MV88E6XXX_PORT_STS_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+
+ case MV88E6XXX_PORT_STS_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+
+ case MV88E6XXX_PORT_STS_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+
+ default:
+ state->link = false;
+ break;
+ }
+ }
+}
+
+static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ return 0;
+}
+
+static void mv88e6185_pcs_an_restart(struct phylink_pcs *pcs)
+{
+}
+
+static const struct phylink_pcs_ops mv88e6185_phylink_pcs_ops = {
+ .pcs_get_state = mv88e6185_pcs_get_state,
+ .pcs_config = mv88e6185_pcs_config,
+ .pcs_an_restart = mv88e6185_pcs_an_restart,
+};
+
+static int mv88e6185_pcs_init(struct mv88e6xxx_chip *chip, int port)
+{
+ struct mv88e6185_pcs *mpcs;
+ struct device *dev;
+ unsigned int irq;
+ int err;
+
+ /* There are no configurable serdes lanes on this switch chip, so
+ * we use the static cmode configuration to determine whether we
+ * have a PCS or not.
+ */
+ if (chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_SERDES &&
+ chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_1000BASE_X)
+ return 0;
+
+ dev = chip->dev;
+
+ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
+ if (!mpcs)
+ return -ENOMEM;
+
+ mpcs->chip = chip;
+ mpcs->port = port;
+ mpcs->phylink_pcs.ops = &mv88e6185_phylink_pcs_ops;
+
+ irq = mv88e6xxx_serdes_irq_mapping(chip, port);
+ if (irq) {
+ snprintf(mpcs->name, sizeof(mpcs->name),
+ "mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
+
+ err = request_threaded_irq(irq, NULL, mv88e6185_pcs_handle_irq,
+ IRQF_ONESHOT, mpcs->name, mpcs);
+ if (err) {
+ kfree(mpcs);
+ return err;
+ }
+
+ mpcs->irq = irq;
+ } else {
+ mpcs->phylink_pcs.poll = true;
+ }
+
+ chip->ports[port].pcs_private = &mpcs->phylink_pcs;
+
+ return 0;
+}
+
+static void mv88e6185_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
+{
+ struct mv88e6185_pcs *mpcs;
+
+ mpcs = chip->ports[port].pcs_private;
+ if (!mpcs)
+ return;
+
+ if (mpcs->irq)
+ free_irq(mpcs->irq, mpcs);
+
+ kfree(mpcs);
+
+ chip->ports[port].pcs_private = NULL;
+}
+
+static struct phylink_pcs *mv88e6185_pcs_select(struct mv88e6xxx_chip *chip,
+ int port,
+ phy_interface_t interface)
+{
+ return chip->ports[port].pcs_private;
+}
+
+const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops = {
+ .pcs_init = mv88e6185_pcs_init,
+ .pcs_teardown = mv88e6185_pcs_teardown,
+ .pcs_select = mv88e6185_pcs_select,
+};
diff --git a/drivers/net/dsa/mv88e6xxx/pcs-6352.c b/drivers/net/dsa/mv88e6xxx/pcs-6352.c
new file mode 100644
index 000000000000..88f624b65470
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/pcs-6352.c
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6352 family SERDES PCS support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ */
+#include <linux/phylink.h>
+
+#include "global2.h"
+#include "port.h"
+#include "serdes.h"
+
+/* Definitions from drivers/net/phy/marvell.c, which would be good to reuse. */
+#define MII_M1011_PHY_STATUS 17
+#define MII_M1011_IMASK 18
+#define MII_M1011_IMASK_LINK_CHANGE BIT(10)
+#define MII_M1011_IEVENT 19
+#define MII_M1011_IEVENT_LINK_CHANGE BIT(10)
+#define MII_MARVELL_PHY_PAGE 22
+#define MII_MARVELL_FIBER_PAGE 1
+
+struct marvell_c22_pcs {
+ struct mdio_device mdio;
+ struct phylink_pcs phylink_pcs;
+ unsigned int irq;
+ char name[64];
+ bool (*link_check)(struct marvell_c22_pcs *mpcs);
+ struct mv88e6xxx_port *port;
+};
+
+static struct marvell_c22_pcs *pcs_to_marvell_c22_pcs(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct marvell_c22_pcs, phylink_pcs);
+}
+
+static int marvell_c22_pcs_set_fiber_page(struct marvell_c22_pcs *mpcs)
+{
+ u16 page;
+ int err;
+
+ mutex_lock(&mpcs->mdio.bus->mdio_lock);
+
+ err = __mdiodev_read(&mpcs->mdio, MII_MARVELL_PHY_PAGE);
+ if (err < 0) {
+ dev_err(mpcs->mdio.dev.parent,
+ "%s: can't read Serdes page register: %pe\n",
+ mpcs->name, ERR_PTR(err));
+ return err;
+ }
+
+ page = err;
+
+ err = __mdiodev_write(&mpcs->mdio, MII_MARVELL_PHY_PAGE,
+ MII_MARVELL_FIBER_PAGE);
+ if (err) {
+ dev_err(mpcs->mdio.dev.parent,
+ "%s: can't set Serdes page register: %pe\n",
+ mpcs->name, ERR_PTR(err));
+ return err;
+ }
+
+ return page;
+}
+
+static int marvell_c22_pcs_restore_page(struct marvell_c22_pcs *mpcs,
+ int oldpage, int ret)
+{
+ int err;
+
+ if (oldpage >= 0) {
+ err = __mdiodev_write(&mpcs->mdio, MII_MARVELL_PHY_PAGE,
+ oldpage);
+ if (err)
+ dev_err(mpcs->mdio.dev.parent,
+ "%s: can't restore Serdes page register: %pe\n",
+ mpcs->name, ERR_PTR(err));
+ if (!err || ret < 0)
+ err = ret;
+ } else {
+ err = oldpage;
+ }
+ mutex_unlock(&mpcs->mdio.bus->mdio_lock);
+
+ return err;
+}
+
+static irqreturn_t marvell_c22_pcs_handle_irq(int irq, void *dev_id)
+{
+ struct marvell_c22_pcs *mpcs = dev_id;
+ irqreturn_t status = IRQ_NONE;
+ int err, oldpage;
+
+ oldpage = marvell_c22_pcs_set_fiber_page(mpcs);
+ if (oldpage < 0)
+ goto fail;
+
+ err = __mdiodev_read(&mpcs->mdio, MII_M1011_IEVENT);
+ if (err >= 0 && err & MII_M1011_IEVENT_LINK_CHANGE) {
+ phylink_pcs_change(&mpcs->phylink_pcs, true);
+ status = IRQ_HANDLED;
+ }
+
+fail:
+ marvell_c22_pcs_restore_page(mpcs, oldpage, 0);
+
+ return status;
+}
+
+static int marvell_c22_pcs_modify(struct marvell_c22_pcs *mpcs, u8 reg,
+ u16 mask, u16 val)
+{
+ int oldpage, err = 0;
+
+ oldpage = marvell_c22_pcs_set_fiber_page(mpcs);
+ if (oldpage >= 0)
+ err = __mdiodev_modify(&mpcs->mdio, reg, mask, val);
+
+ return marvell_c22_pcs_restore_page(mpcs, oldpage, err);
+}
+
+static int marvell_c22_pcs_power(struct marvell_c22_pcs *mpcs,
+ bool on)
+{
+ u16 val = on ? 0 : BMCR_PDOWN;
+
+ return marvell_c22_pcs_modify(mpcs, MII_BMCR, BMCR_PDOWN, val);
+}
+
+static int marvell_c22_pcs_control_irq(struct marvell_c22_pcs *mpcs,
+ bool enable)
+{
+ u16 val = enable ? MII_M1011_IMASK_LINK_CHANGE : 0;
+
+ return marvell_c22_pcs_modify(mpcs, MII_M1011_IMASK,
+ MII_M1011_IMASK_LINK_CHANGE, val);
+}
+
+static int marvell_c22_pcs_enable(struct phylink_pcs *pcs)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+ int err;
+
+ err = marvell_c22_pcs_power(mpcs, true);
+ if (err)
+ return err;
+
+ return marvell_c22_pcs_control_irq(mpcs, !!mpcs->irq);
+}
+
+static void marvell_c22_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+
+ marvell_c22_pcs_control_irq(mpcs, false);
+ marvell_c22_pcs_power(mpcs, false);
+}
+
+static void marvell_c22_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+ int oldpage, bmsr, lpa, status;
+
+ state->link = false;
+
+ if (mpcs->link_check && !mpcs->link_check(mpcs))
+ return;
+
+ oldpage = marvell_c22_pcs_set_fiber_page(mpcs);
+ if (oldpage >= 0) {
+ bmsr = __mdiodev_read(&mpcs->mdio, MII_BMSR);
+ lpa = __mdiodev_read(&mpcs->mdio, MII_LPA);
+ status = __mdiodev_read(&mpcs->mdio, MII_M1011_PHY_STATUS);
+ }
+
+ if (marvell_c22_pcs_restore_page(mpcs, oldpage, 0) >= 0 &&
+ bmsr >= 0 && lpa >= 0 && status >= 0)
+ mv88e6xxx_pcs_decode_state(mpcs->mdio.dev.parent, bmsr, lpa,
+ status, state);
+}
+
+static int marvell_c22_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+ int oldpage, adv, err, ret = 0;
+ u16 bmcr;
+
+ adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
+ if (adv < 0)
+ return 0;
+
+ bmcr = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? BMCR_ANENABLE : 0;
+
+ oldpage = marvell_c22_pcs_set_fiber_page(mpcs);
+ if (oldpage < 0)
+ goto restore;
+
+ err = __mdiodev_modify_changed(&mpcs->mdio, MII_ADVERTISE, 0xffff, adv);
+ ret = err;
+ if (err < 0)
+ goto restore;
+
+ err = __mdiodev_modify_changed(&mpcs->mdio, MII_BMCR, BMCR_ANENABLE,
+ bmcr);
+ if (err < 0) {
+ ret = err;
+ goto restore;
+ }
+
+ /* If the ANENABLE bit was changed, the PHY will restart negotiation,
+ * so we don't need to flag a change to trigger its own restart.
+ */
+ if (err)
+ ret = 0;
+
+restore:
+ return marvell_c22_pcs_restore_page(mpcs, oldpage, ret);
+}
+
+static void marvell_c22_pcs_an_restart(struct phylink_pcs *pcs)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+
+ marvell_c22_pcs_modify(mpcs, MII_BMCR, BMCR_ANRESTART, BMCR_ANRESTART);
+}
+
+static void marvell_c22_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface, int speed,
+ int duplex)
+{
+ struct marvell_c22_pcs *mpcs = pcs_to_marvell_c22_pcs(pcs);
+ u16 bmcr;
+ int err;
+
+ if (phylink_autoneg_inband(mode))
+ return;
+
+ bmcr = mii_bmcr_encode_fixed(speed, duplex);
+
+ err = marvell_c22_pcs_modify(mpcs, MII_BMCR, BMCR_SPEED100 |
+ BMCR_FULLDPLX | BMCR_SPEED1000, bmcr);
+ if (err)
+ dev_err(mpcs->mdio.dev.parent,
+ "%s: failed to configure mpcs: %pe\n", mpcs->name,
+ ERR_PTR(err));
+}
+
+static const struct phylink_pcs_ops marvell_c22_pcs_ops = {
+ .pcs_enable = marvell_c22_pcs_enable,
+ .pcs_disable = marvell_c22_pcs_disable,
+ .pcs_get_state = marvell_c22_pcs_get_state,
+ .pcs_config = marvell_c22_pcs_config,
+ .pcs_an_restart = marvell_c22_pcs_an_restart,
+ .pcs_link_up = marvell_c22_pcs_link_up,
+};
+
+static struct marvell_c22_pcs *marvell_c22_pcs_alloc(struct device *dev,
+ struct mii_bus *bus,
+ unsigned int addr)
+{
+ struct marvell_c22_pcs *mpcs;
+
+ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
+ if (!mpcs)
+ return NULL;
+
+ mpcs->mdio.dev.parent = dev;
+ mpcs->mdio.bus = bus;
+ mpcs->mdio.addr = addr;
+ mpcs->phylink_pcs.ops = &marvell_c22_pcs_ops;
+ mpcs->phylink_pcs.neg_mode = true;
+
+ return mpcs;
+}
+
+static int marvell_c22_pcs_setup_irq(struct marvell_c22_pcs *mpcs,
+ unsigned int irq)
+{
+ int err;
+
+ mpcs->phylink_pcs.poll = !irq;
+ mpcs->irq = irq;
+
+ if (irq) {
+ err = request_threaded_irq(irq, NULL,
+ marvell_c22_pcs_handle_irq,
+ IRQF_ONESHOT, mpcs->name, mpcs);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* mv88e6352 specifics */
+
+static bool mv88e6352_pcs_link_check(struct marvell_c22_pcs *mpcs)
+{
+ struct mv88e6xxx_port *port = mpcs->port;
+ struct mv88e6xxx_chip *chip = port->chip;
+ u8 cmode;
+
+ /* Port 4 can be in auto-media mode. Check that the port is
+ * associated with the mpcs.
+ */
+ mv88e6xxx_reg_lock(chip);
+ chip->info->ops->port_get_cmode(chip, port->port, &cmode);
+ mv88e6xxx_reg_unlock(chip);
+
+ return cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
+ cmode == MV88E6XXX_PORT_STS_CMODE_SGMII;
+}
+
+static int mv88e6352_pcs_init(struct mv88e6xxx_chip *chip, int port)
+{
+ struct marvell_c22_pcs *mpcs;
+ struct mii_bus *bus;
+ struct device *dev;
+ unsigned int irq;
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
+ mv88e6xxx_reg_unlock(chip);
+ if (err <= 0)
+ return err;
+
+ irq = mv88e6xxx_serdes_irq_mapping(chip, port);
+ bus = mv88e6xxx_default_mdio_bus(chip);
+ dev = chip->dev;
+
+ mpcs = marvell_c22_pcs_alloc(dev, bus, MV88E6352_ADDR_SERDES);
+ if (!mpcs)
+ return -ENOMEM;
+
+ snprintf(mpcs->name, sizeof(mpcs->name),
+ "mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
+
+ mpcs->link_check = mv88e6352_pcs_link_check;
+ mpcs->port = &chip->ports[port];
+
+ err = marvell_c22_pcs_setup_irq(mpcs, irq);
+ if (err) {
+ kfree(mpcs);
+ return err;
+ }
+
+ chip->ports[port].pcs_private = &mpcs->phylink_pcs;
+
+ return 0;
+}
+
+static void mv88e6352_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
+{
+ struct marvell_c22_pcs *mpcs;
+ struct phylink_pcs *pcs;
+
+ pcs = chip->ports[port].pcs_private;
+ if (!pcs)
+ return;
+
+ mpcs = pcs_to_marvell_c22_pcs(pcs);
+
+ if (mpcs->irq)
+ free_irq(mpcs->irq, mpcs);
+
+ kfree(mpcs);
+
+ chip->ports[port].pcs_private = NULL;
+}
+
+static struct phylink_pcs *mv88e6352_pcs_select(struct mv88e6xxx_chip *chip,
+ int port,
+ phy_interface_t interface)
+{
+ return chip->ports[port].pcs_private;
+}
+
+const struct mv88e6xxx_pcs_ops mv88e6352_pcs_ops = {
+ .pcs_init = mv88e6352_pcs_init,
+ .pcs_teardown = mv88e6352_pcs_teardown,
+ .pcs_select = mv88e6352_pcs_select,
+};
diff --git a/drivers/net/dsa/mv88e6xxx/pcs-639x.c b/drivers/net/dsa/mv88e6xxx/pcs-639x.c
new file mode 100644
index 000000000000..ba373656bfe1
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/pcs-639x.c
@@ -0,0 +1,943 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Marvell 88E6352 family SERDES PCS support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ */
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/mii.h>
+
+#include "chip.h"
+#include "global2.h"
+#include "phy.h"
+#include "port.h"
+#include "serdes.h"
+
+struct mv88e639x_pcs {
+ struct mdio_device mdio;
+ struct phylink_pcs sgmii_pcs;
+ struct phylink_pcs xg_pcs;
+ bool erratum_3_14;
+ bool supports_5g;
+ phy_interface_t interface;
+ unsigned int irq;
+ char name[64];
+ irqreturn_t (*handle_irq)(struct mv88e639x_pcs *mpcs);
+};
+
+static int mv88e639x_read(struct mv88e639x_pcs *mpcs, u16 regnum, u16 *val)
+{
+ int err;
+
+ err = mdiodev_c45_read(&mpcs->mdio, MDIO_MMD_PHYXS, regnum);
+ if (err < 0)
+ return err;
+
+ *val = err;
+
+ return 0;
+}
+
+static int mv88e639x_write(struct mv88e639x_pcs *mpcs, u16 regnum, u16 val)
+{
+ return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, val);
+}
+
+static int mv88e639x_modify(struct mv88e639x_pcs *mpcs, u16 regnum, u16 mask,
+ u16 val)
+{
+ return mdiodev_c45_modify(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, mask,
+ val);
+}
+
+static int mv88e639x_modify_changed(struct mv88e639x_pcs *mpcs, u16 regnum,
+ u16 mask, u16 set)
+{
+ return mdiodev_c45_modify_changed(&mpcs->mdio, MDIO_MMD_PHYXS, regnum,
+ mask, set);
+}
+
+static struct mv88e639x_pcs *
+mv88e639x_pcs_alloc(struct device *dev, struct mii_bus *bus, unsigned int addr,
+ int port)
+{
+ struct mv88e639x_pcs *mpcs;
+
+ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
+ if (!mpcs)
+ return NULL;
+
+ mpcs->mdio.dev.parent = dev;
+ mpcs->mdio.bus = bus;
+ mpcs->mdio.addr = addr;
+
+ snprintf(mpcs->name, sizeof(mpcs->name),
+ "mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
+
+ return mpcs;
+}
+
+static irqreturn_t mv88e639x_pcs_handle_irq(int irq, void *dev_id)
+{
+ struct mv88e639x_pcs *mpcs = dev_id;
+ irqreturn_t (*handler)(struct mv88e639x_pcs *);
+
+ handler = READ_ONCE(mpcs->handle_irq);
+ if (!handler)
+ return IRQ_NONE;
+
+ return handler(mpcs);
+}
+
+static int mv88e639x_pcs_setup_irq(struct mv88e639x_pcs *mpcs,
+ struct mv88e6xxx_chip *chip, int port)
+{
+ unsigned int irq;
+
+ irq = mv88e6xxx_serdes_irq_mapping(chip, port);
+ if (!irq) {
+ /* Use polling mode */
+ mpcs->sgmii_pcs.poll = true;
+ mpcs->xg_pcs.poll = true;
+ return 0;
+ }
+
+ mpcs->irq = irq;
+
+ return request_threaded_irq(irq, NULL, mv88e639x_pcs_handle_irq,
+ IRQF_ONESHOT, mpcs->name, mpcs);
+}
+
+static void mv88e639x_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
+{
+ struct mv88e639x_pcs *mpcs = chip->ports[port].pcs_private;
+
+ if (!mpcs)
+ return;
+
+ if (mpcs->irq)
+ free_irq(mpcs->irq, mpcs);
+
+ kfree(mpcs);
+
+ chip->ports[port].pcs_private = NULL;
+}
+
+static struct mv88e639x_pcs *sgmii_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct mv88e639x_pcs, sgmii_pcs);
+}
+
+static irqreturn_t mv88e639x_sgmii_handle_irq(struct mv88e639x_pcs *mpcs)
+{
+ u16 int_status;
+ int err;
+
+ err = mv88e639x_read(mpcs, MV88E6390_SGMII_INT_STATUS, &int_status);
+ if (err)
+ return IRQ_NONE;
+
+ if (int_status & (MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP)) {
+ phylink_pcs_change(&mpcs->sgmii_pcs,
+ int_status & MV88E6390_SGMII_INT_LINK_UP);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mv88e639x_sgmii_pcs_control_irq(struct mv88e639x_pcs *mpcs,
+ bool enable)
+{
+ u16 val = 0;
+
+ if (enable)
+ val |= MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP;
+
+ return mv88e639x_modify(mpcs, MV88E6390_SGMII_INT_ENABLE,
+ MV88E6390_SGMII_INT_LINK_DOWN |
+ MV88E6390_SGMII_INT_LINK_UP, val);
+}
+
+static int mv88e639x_sgmii_pcs_control_pwr(struct mv88e639x_pcs *mpcs,
+ bool enable)
+{
+ u16 mask, val;
+
+ if (enable) {
+ mask = BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN;
+ val = 0;
+ } else {
+ mask = val = BMCR_PDOWN;
+ }
+
+ return mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR, mask, val);
+}
+
+static int mv88e639x_sgmii_pcs_enable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ /* power enable done in post_config */
+ mpcs->handle_irq = mv88e639x_sgmii_handle_irq;
+
+ return mv88e639x_sgmii_pcs_control_irq(mpcs, !!mpcs->irq);
+}
+
+static void mv88e639x_sgmii_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_sgmii_pcs_control_irq(mpcs, false);
+ mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
+}
+
+static void mv88e639x_sgmii_pcs_pre_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
+}
+
+static int mv88e6390_erratum_3_14(struct mv88e639x_pcs *mpcs)
+{
+ const int lanes[] = { MV88E6390_PORT9_LANE0, MV88E6390_PORT9_LANE1,
+ MV88E6390_PORT9_LANE2, MV88E6390_PORT9_LANE3,
+ MV88E6390_PORT10_LANE0, MV88E6390_PORT10_LANE1,
+ MV88E6390_PORT10_LANE2, MV88E6390_PORT10_LANE3 };
+ int err, i;
+
+ /* 88e6190x and 88e6390x errata 3.14:
+ * After chip reset, SERDES reconfiguration or SERDES core
+ * Software Reset, the SERDES lanes may not be properly aligned
+ * resulting in CRC errors
+ */
+
+ for (i = 0; i < ARRAY_SIZE(lanes); i++) {
+ err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i],
+ MDIO_MMD_PHYXS,
+ 0xf054, 0x400C);
+ if (err)
+ return err;
+
+ err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i],
+ MDIO_MMD_PHYXS,
+ 0xf054, 0x4000);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int mv88e639x_sgmii_pcs_post_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+ int err;
+
+ mv88e639x_sgmii_pcs_control_pwr(mpcs, true);
+
+ if (mpcs->erratum_3_14) {
+ err = mv88e6390_erratum_3_14(mpcs);
+ if (err)
+ dev_err(mpcs->mdio.dev.parent,
+ "failed to apply erratum 3.14: %pe\n",
+ ERR_PTR(err));
+ }
+
+ return 0;
+}
+
+static void mv88e639x_sgmii_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+ u16 bmsr, lpa, status;
+ int err;
+
+ err = mv88e639x_read(mpcs, MV88E6390_SGMII_BMSR, &bmsr);
+ if (err) {
+ dev_err(mpcs->mdio.dev.parent,
+ "can't read Serdes PHY %s: %pe\n",
+ "BMSR", ERR_PTR(err));
+ state->link = false;
+ return;
+ }
+
+ err = mv88e639x_read(mpcs, MV88E6390_SGMII_LPA, &lpa);
+ if (err) {
+ dev_err(mpcs->mdio.dev.parent,
+ "can't read Serdes PHY %s: %pe\n",
+ "LPA", ERR_PTR(err));
+ state->link = false;
+ return;
+ }
+
+ err = mv88e639x_read(mpcs, MV88E6390_SGMII_PHY_STATUS, &status);
+ if (err) {
+ dev_err(mpcs->mdio.dev.parent,
+ "can't read Serdes PHY %s: %pe\n",
+ "status", ERR_PTR(err));
+ state->link = false;
+ return;
+ }
+
+ mv88e6xxx_pcs_decode_state(mpcs->mdio.dev.parent, bmsr, lpa, status,
+ state);
+}
+
+static int mv88e639x_sgmii_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+ u16 val, bmcr;
+ bool changed;
+ int adv, err;
+
+ adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
+ if (adv < 0)
+ return 0;
+
+ mpcs->interface = interface;
+
+ err = mv88e639x_modify_changed(mpcs, MV88E6390_SGMII_ADVERTISE,
+ 0xffff, adv);
+ if (err < 0)
+ return err;
+
+ changed = err > 0;
+
+ err = mv88e639x_read(mpcs, MV88E6390_SGMII_BMCR, &val);
+ if (err)
+ return err;
+
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+ bmcr = val | BMCR_ANENABLE;
+ else
+ bmcr = val & ~BMCR_ANENABLE;
+
+ /* setting ANENABLE triggers a restart of negotiation */
+ if (bmcr == val)
+ return changed;
+
+ return mv88e639x_write(mpcs, MV88E6390_SGMII_BMCR, bmcr);
+}
+
+static void mv88e639x_sgmii_pcs_an_restart(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
+ BMCR_ANRESTART, BMCR_ANRESTART);
+}
+
+static void mv88e639x_sgmii_pcs_link_up(struct phylink_pcs *pcs,
+ unsigned int mode,
+ phy_interface_t interface,
+ int speed, int duplex)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+ u16 bmcr;
+ int err;
+
+ if (phylink_autoneg_inband(mode))
+ return;
+
+ bmcr = mii_bmcr_encode_fixed(speed, duplex);
+
+ err = mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
+ BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX,
+ bmcr);
+ if (err)
+ dev_err(mpcs->mdio.dev.parent,
+ "can't access Serdes PHY %s: %pe\n",
+ "BMCR", ERR_PTR(err));
+}
+
+static const struct phylink_pcs_ops mv88e639x_sgmii_pcs_ops = {
+ .pcs_enable = mv88e639x_sgmii_pcs_enable,
+ .pcs_disable = mv88e639x_sgmii_pcs_disable,
+ .pcs_pre_config = mv88e639x_sgmii_pcs_pre_config,
+ .pcs_post_config = mv88e639x_sgmii_pcs_post_config,
+ .pcs_get_state = mv88e639x_sgmii_pcs_get_state,
+ .pcs_an_restart = mv88e639x_sgmii_pcs_an_restart,
+ .pcs_config = mv88e639x_sgmii_pcs_config,
+ .pcs_link_up = mv88e639x_sgmii_pcs_link_up,
+};
+
+static struct mv88e639x_pcs *xg_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs)
+{
+ return container_of(pcs, struct mv88e639x_pcs, xg_pcs);
+}
+
+static int mv88e639x_xg_pcs_enable(struct mv88e639x_pcs *mpcs)
+{
+ return mv88e639x_modify(mpcs, MV88E6390_10G_CTRL1,
+ MDIO_CTRL1_RESET | MDIO_PCS_CTRL1_LOOPBACK |
+ MDIO_CTRL1_LPOWER, 0);
+}
+
+static void mv88e639x_xg_pcs_disable(struct mv88e639x_pcs *mpcs)
+{
+ mv88e639x_modify(mpcs, MV88E6390_10G_CTRL1, MDIO_CTRL1_LPOWER,
+ MDIO_CTRL1_LPOWER);
+}
+
+static void mv88e639x_xg_pcs_get_state(struct phylink_pcs *pcs,
+ struct phylink_link_state *state)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+ u16 status;
+ int err;
+
+ state->link = false;
+
+ err = mv88e639x_read(mpcs, MV88E6390_10G_STAT1, &status);
+ if (err) {
+ dev_err(mpcs->mdio.dev.parent,
+ "can't read Serdes PHY %s: %pe\n",
+ "STAT1", ERR_PTR(err));
+ return;
+ }
+
+ state->link = !!(status & MDIO_STAT1_LSTATUS);
+ if (state->link) {
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_5GBASER:
+ state->speed = SPEED_5000;
+ break;
+
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_RXAUI:
+ case PHY_INTERFACE_MODE_XAUI:
+ state->speed = SPEED_10000;
+ break;
+
+ default:
+ state->link = false;
+ return;
+ }
+
+ state->duplex = DUPLEX_FULL;
+ }
+}
+
+static int mv88e639x_xg_pcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ return 0;
+}
+
+static struct phylink_pcs *
+mv88e639x_pcs_select(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ struct mv88e639x_pcs *mpcs;
+
+ mpcs = chip->ports[port].pcs_private;
+ if (!mpcs)
+ return NULL;
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ return &mpcs->sgmii_pcs;
+
+ case PHY_INTERFACE_MODE_5GBASER:
+ if (!mpcs->supports_5g)
+ return NULL;
+ fallthrough;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_XAUI:
+ case PHY_INTERFACE_MODE_RXAUI:
+ return &mpcs->xg_pcs;
+
+ default:
+ return NULL;
+ }
+}
+
+/* Marvell 88E6390 Specific support */
+
+static irqreturn_t mv88e6390_xg_handle_irq(struct mv88e639x_pcs *mpcs)
+{
+ u16 int_status;
+ int err;
+
+ err = mv88e639x_read(mpcs, MV88E6390_10G_INT_STATUS, &int_status);
+ if (err)
+ return IRQ_NONE;
+
+ if (int_status & (MV88E6390_10G_INT_LINK_DOWN |
+ MV88E6390_10G_INT_LINK_UP)) {
+ phylink_pcs_change(&mpcs->xg_pcs,
+ int_status & MV88E6390_10G_INT_LINK_UP);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mv88e6390_xg_control_irq(struct mv88e639x_pcs *mpcs, bool enable)
+{
+ u16 val = 0;
+
+ if (enable)
+ val = MV88E6390_10G_INT_LINK_DOWN | MV88E6390_10G_INT_LINK_UP;
+
+ return mv88e639x_modify(mpcs, MV88E6390_10G_INT_ENABLE,
+ MV88E6390_10G_INT_LINK_DOWN |
+ MV88E6390_10G_INT_LINK_UP, val);
+}
+
+static int mv88e6390_xg_pcs_enable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+ int err;
+
+ err = mv88e639x_xg_pcs_enable(mpcs);
+ if (err)
+ return err;
+
+ mpcs->handle_irq = mv88e6390_xg_handle_irq;
+
+ return mv88e6390_xg_control_irq(mpcs, !!mpcs->irq);
+}
+
+static void mv88e6390_xg_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e6390_xg_control_irq(mpcs, false);
+ mv88e639x_xg_pcs_disable(mpcs);
+}
+
+static const struct phylink_pcs_ops mv88e6390_xg_pcs_ops = {
+ .pcs_enable = mv88e6390_xg_pcs_enable,
+ .pcs_disable = mv88e6390_xg_pcs_disable,
+ .pcs_get_state = mv88e639x_xg_pcs_get_state,
+ .pcs_config = mv88e639x_xg_pcs_config,
+};
+
+static int mv88e6390_pcs_enable_checker(struct mv88e639x_pcs *mpcs)
+{
+ return mv88e639x_modify(mpcs, MV88E6390_PG_CONTROL,
+ MV88E6390_PG_CONTROL_ENABLE_PC,
+ MV88E6390_PG_CONTROL_ENABLE_PC);
+}
+
+static int mv88e6390_pcs_init(struct mv88e6xxx_chip *chip, int port)
+{
+ struct mv88e639x_pcs *mpcs;
+ struct mii_bus *bus;
+ struct device *dev;
+ int lane, err;
+
+ lane = mv88e6xxx_serdes_get_lane(chip, port);
+ if (lane < 0)
+ return 0;
+
+ bus = mv88e6xxx_default_mdio_bus(chip);
+ dev = chip->dev;
+
+ mpcs = mv88e639x_pcs_alloc(dev, bus, lane, port);
+ if (!mpcs)
+ return -ENOMEM;
+
+ mpcs->sgmii_pcs.ops = &mv88e639x_sgmii_pcs_ops;
+ mpcs->sgmii_pcs.neg_mode = true;
+ mpcs->xg_pcs.ops = &mv88e6390_xg_pcs_ops;
+ mpcs->xg_pcs.neg_mode = true;
+
+ if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6190X ||
+ chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6390X)
+ mpcs->erratum_3_14 = true;
+
+ err = mv88e639x_pcs_setup_irq(mpcs, chip, port);
+ if (err)
+ goto err_free;
+
+ /* 6390 and 6390x has the checker, 6393x doesn't appear to? */
+ /* This is to enable gathering the statistics. Maybe this
+ * should call out to a helper? Or we could do this at init time.
+ */
+ err = mv88e6390_pcs_enable_checker(mpcs);
+ if (err)
+ goto err_free;
+
+ chip->ports[port].pcs_private = mpcs;
+
+ return 0;
+
+err_free:
+ kfree(mpcs);
+ return err;
+}
+
+const struct mv88e6xxx_pcs_ops mv88e6390_pcs_ops = {
+ .pcs_init = mv88e6390_pcs_init,
+ .pcs_teardown = mv88e639x_pcs_teardown,
+ .pcs_select = mv88e639x_pcs_select,
+};
+
+/* Marvell 88E6393X Specific support */
+
+static int mv88e6393x_power_lane(struct mv88e639x_pcs *mpcs, bool enable)
+{
+ u16 val = MV88E6393X_SERDES_CTRL1_TX_PDOWN |
+ MV88E6393X_SERDES_CTRL1_RX_PDOWN;
+
+ return mv88e639x_modify(mpcs, MV88E6393X_SERDES_CTRL1, val,
+ enable ? 0 : val);
+}
+
+/* mv88e6393x family errata 4.6:
+ * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD mode or
+ * P0_mode is configured for [x]MII.
+ * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1.
+ *
+ * It seems that after this workaround the SERDES is automatically powered up
+ * (the bit is cleared), so power it down.
+ */
+static int mv88e6393x_erratum_4_6(struct mv88e639x_pcs *mpcs)
+{
+ int err;
+
+ err = mv88e639x_modify(mpcs, MV88E6393X_SERDES_POC,
+ MV88E6393X_SERDES_POC_PDOWN |
+ MV88E6393X_SERDES_POC_RESET,
+ MV88E6393X_SERDES_POC_RESET);
+ if (err)
+ return err;
+
+ err = mv88e639x_modify(mpcs, MV88E6390_SGMII_BMCR,
+ BMCR_PDOWN, BMCR_PDOWN);
+ if (err)
+ return err;
+
+ err = mv88e639x_sgmii_pcs_control_pwr(mpcs, false);
+ if (err)
+ return err;
+
+ return mv88e6393x_power_lane(mpcs, false);
+}
+
+/* mv88e6393x family errata 4.8:
+ * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
+ * come up after hardware reset or software reset of SERDES core. Workaround
+ * is to write SERDES register 4.F074.14=1 for only those modes and 0 in all
+ * other modes.
+ */
+static int mv88e6393x_erratum_4_8(struct mv88e639x_pcs *mpcs)
+{
+ u16 reg, poc;
+ int err;
+
+ err = mv88e639x_read(mpcs, MV88E6393X_SERDES_POC, &poc);
+ if (err)
+ return err;
+
+ poc &= MV88E6393X_SERDES_POC_PCS_MASK;
+ if (poc == MV88E6393X_SERDES_POC_PCS_1000BASEX ||
+ poc == MV88E6393X_SERDES_POC_PCS_SGMII_PHY ||
+ poc == MV88E6393X_SERDES_POC_PCS_SGMII_MAC)
+ reg = MV88E6393X_ERRATA_4_8_BIT;
+ else
+ reg = 0;
+
+ return mv88e639x_modify(mpcs, MV88E6393X_ERRATA_4_8_REG,
+ MV88E6393X_ERRATA_4_8_BIT, reg);
+}
+
+/* mv88e6393x family errata 5.2:
+ * For optimal signal integrity the following sequence should be applied to
+ * SERDES operating in 10G mode. These registers only apply to 10G operation
+ * and have no effect on other speeds.
+ */
+static int mv88e6393x_erratum_5_2(struct mv88e639x_pcs *mpcs)
+{
+ static const struct {
+ u16 dev, reg, val, mask;
+ } fixes[] = {
+ { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
+ { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
+ { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
+ { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
+ { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
+ { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
+ { MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC,
+ MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET },
+ };
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
+ err = mdiodev_c45_modify(&mpcs->mdio, fixes[i].dev,
+ fixes[i].reg, fixes[i].mask,
+ fixes[i].val);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Inband AN is broken on Amethyst in 2500base-x mode when set by standard
+ * mechanism (via cmode).
+ * We can get around this by configuring the PCS mode to 1000base-x and then
+ * writing value 0x58 to register 1e.8000. (This must be done while SerDes
+ * receiver and transmitter are disabled, which is, when this function is
+ * called.)
+ * It seem that when we do this configuration to 2500base-x mode (by changing
+ * PCS mode to 1000base-x and frequency to 3.125 GHz from 1.25 GHz) and then
+ * configure to sgmii or 1000base-x, the device thinks that it already has
+ * SerDes at 1.25 GHz and does not change the 1e.8000 register, leaving SerDes
+ * at 3.125 GHz.
+ * To avoid this, change PCS mode back to 2500base-x when disabling SerDes from
+ * 2500base-x mode.
+ */
+static int mv88e6393x_fix_2500basex_an(struct mv88e639x_pcs *mpcs, bool on)
+{
+ u16 reg;
+ int err;
+
+ if (on)
+ reg = MV88E6393X_SERDES_POC_PCS_1000BASEX |
+ MV88E6393X_SERDES_POC_AN;
+ else
+ reg = MV88E6393X_SERDES_POC_PCS_2500BASEX;
+
+ reg |= MV88E6393X_SERDES_POC_RESET;
+
+ err = mv88e639x_modify(mpcs, MV88E6393X_SERDES_POC,
+ MV88E6393X_SERDES_POC_PCS_MASK |
+ MV88E6393X_SERDES_POC_AN |
+ MV88E6393X_SERDES_POC_RESET, reg);
+ if (err)
+ return err;
+
+ return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_VEND1, 0x8000, 0x58);
+}
+
+static int mv88e6393x_sgmii_apply_2500basex_an(struct mv88e639x_pcs *mpcs,
+ phy_interface_t interface,
+ bool enable)
+{
+ int err;
+
+ if (interface != PHY_INTERFACE_MODE_2500BASEX)
+ return 0;
+
+ err = mv88e6393x_fix_2500basex_an(mpcs, enable);
+ if (err)
+ dev_err(mpcs->mdio.dev.parent,
+ "failed to %s 2500basex fix: %pe\n",
+ enable ? "enable" : "disable", ERR_PTR(err));
+
+ return err;
+}
+
+static void mv88e6393x_sgmii_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_sgmii_pcs_disable(pcs);
+ mv88e6393x_power_lane(mpcs, false);
+ mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false);
+}
+
+static void mv88e6393x_sgmii_pcs_pre_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_sgmii_pcs_pre_config(pcs, interface);
+ mv88e6393x_power_lane(mpcs, false);
+ mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false);
+}
+
+static int mv88e6393x_sgmii_pcs_post_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs);
+ int err;
+
+ err = mv88e6393x_erratum_4_8(mpcs);
+ if (err)
+ return err;
+
+ err = mv88e6393x_sgmii_apply_2500basex_an(mpcs, interface, true);
+ if (err)
+ return err;
+
+ err = mv88e6393x_power_lane(mpcs, true);
+ if (err)
+ return err;
+
+ return mv88e639x_sgmii_pcs_post_config(pcs, interface);
+}
+
+static const struct phylink_pcs_ops mv88e6393x_sgmii_pcs_ops = {
+ .pcs_enable = mv88e639x_sgmii_pcs_enable,
+ .pcs_disable = mv88e6393x_sgmii_pcs_disable,
+ .pcs_pre_config = mv88e6393x_sgmii_pcs_pre_config,
+ .pcs_post_config = mv88e6393x_sgmii_pcs_post_config,
+ .pcs_get_state = mv88e639x_sgmii_pcs_get_state,
+ .pcs_an_restart = mv88e639x_sgmii_pcs_an_restart,
+ .pcs_config = mv88e639x_sgmii_pcs_config,
+ .pcs_link_up = mv88e639x_sgmii_pcs_link_up,
+};
+
+static irqreturn_t mv88e6393x_xg_handle_irq(struct mv88e639x_pcs *mpcs)
+{
+ u16 int_status, stat1;
+ bool link_down;
+ int err;
+
+ err = mv88e639x_read(mpcs, MV88E6393X_10G_INT_STATUS, &int_status);
+ if (err)
+ return IRQ_NONE;
+
+ if (int_status & MV88E6393X_10G_INT_LINK_CHANGE) {
+ err = mv88e639x_read(mpcs, MV88E6390_10G_STAT1, &stat1);
+ if (err)
+ return IRQ_NONE;
+
+ link_down = !(stat1 & MDIO_STAT1_LSTATUS);
+
+ phylink_pcs_change(&mpcs->xg_pcs, !link_down);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mv88e6393x_xg_control_irq(struct mv88e639x_pcs *mpcs, bool enable)
+{
+ u16 val = 0;
+
+ if (enable)
+ val = MV88E6393X_10G_INT_LINK_CHANGE;
+
+ return mv88e639x_modify(mpcs, MV88E6393X_10G_INT_ENABLE,
+ MV88E6393X_10G_INT_LINK_CHANGE, val);
+}
+
+static int mv88e6393x_xg_pcs_enable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+
+ mpcs->handle_irq = mv88e6393x_xg_handle_irq;
+
+ return mv88e6393x_xg_control_irq(mpcs, !!mpcs->irq);
+}
+
+static void mv88e6393x_xg_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e6393x_xg_control_irq(mpcs, false);
+ mv88e639x_xg_pcs_disable(mpcs);
+ mv88e6393x_power_lane(mpcs, false);
+}
+
+/* The PCS has to be powered down while CMODE is changed */
+static void mv88e6393x_xg_pcs_pre_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+
+ mv88e639x_xg_pcs_disable(mpcs);
+ mv88e6393x_power_lane(mpcs, false);
+}
+
+static int mv88e6393x_xg_pcs_post_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs);
+ int err;
+
+ if (interface == PHY_INTERFACE_MODE_10GBASER) {
+ err = mv88e6393x_erratum_5_2(mpcs);
+ if (err)
+ return err;
+ }
+
+ err = mv88e6393x_power_lane(mpcs, true);
+ if (err)
+ return err;
+
+ return mv88e639x_xg_pcs_enable(mpcs);
+}
+
+static const struct phylink_pcs_ops mv88e6393x_xg_pcs_ops = {
+ .pcs_enable = mv88e6393x_xg_pcs_enable,
+ .pcs_disable = mv88e6393x_xg_pcs_disable,
+ .pcs_pre_config = mv88e6393x_xg_pcs_pre_config,
+ .pcs_post_config = mv88e6393x_xg_pcs_post_config,
+ .pcs_get_state = mv88e639x_xg_pcs_get_state,
+ .pcs_config = mv88e639x_xg_pcs_config,
+};
+
+static int mv88e6393x_pcs_init(struct mv88e6xxx_chip *chip, int port)
+{
+ struct mv88e639x_pcs *mpcs;
+ struct mii_bus *bus;
+ struct device *dev;
+ int lane, err;
+
+ lane = mv88e6xxx_serdes_get_lane(chip, port);
+ if (lane < 0)
+ return 0;
+
+ bus = mv88e6xxx_default_mdio_bus(chip);
+ dev = chip->dev;
+
+ mpcs = mv88e639x_pcs_alloc(dev, bus, lane, port);
+ if (!mpcs)
+ return -ENOMEM;
+
+ mpcs->sgmii_pcs.ops = &mv88e6393x_sgmii_pcs_ops;
+ mpcs->sgmii_pcs.neg_mode = true;
+ mpcs->xg_pcs.ops = &mv88e6393x_xg_pcs_ops;
+ mpcs->xg_pcs.neg_mode = true;
+ mpcs->supports_5g = true;
+
+ err = mv88e6393x_erratum_4_6(mpcs);
+ if (err)
+ goto err_free;
+
+ err = mv88e639x_pcs_setup_irq(mpcs, chip, port);
+ if (err)
+ goto err_free;
+
+ chip->ports[port].pcs_private = mpcs;
+
+ return 0;
+
+err_free:
+ kfree(mpcs);
+ return err;
+}
+
+const struct mv88e6xxx_pcs_ops mv88e6393x_pcs_ops = {
+ .pcs_init = mv88e6393x_pcs_init,
+ .pcs_teardown = mv88e639x_pcs_teardown,
+ .pcs_select = mv88e639x_pcs_select,
+};
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index dd66ec902d4c..5394a8cf7bf1 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -524,7 +524,6 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
u16 cmode;
- int lane;
u16 reg;
int err;
@@ -577,19 +576,6 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
if (cmode == chip->ports[port].cmode && !force)
return 0;
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane >= 0) {
- if (chip->ports[port].serdes_irq) {
- err = mv88e6xxx_serdes_irq_disable(chip, port, lane);
- if (err)
- return err;
- }
-
- err = mv88e6xxx_serdes_power_down(chip, port, lane);
- if (err)
- return err;
- }
-
chip->ports[port].cmode = 0;
if (cmode) {
@@ -605,22 +591,6 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return err;
chip->ports[port].cmode = cmode;
-
- lane = mv88e6xxx_serdes_get_lane(chip, port);
- if (lane == -ENODEV)
- return 0;
- if (lane < 0)
- return lane;
-
- err = mv88e6xxx_serdes_power_up(chip, port, lane);
- if (err)
- return err;
-
- if (chip->ports[port].serdes_irq) {
- err = mv88e6xxx_serdes_irq_enable(chip, port, lane);
- if (err)
- return err;
- }
}
return 0;
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 80167d53212f..3b4b42651fa3 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -39,15 +39,8 @@ static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
return mv88e6xxx_phy_read_c45(chip, lane, device, reg, val);
}
-static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
- int lane, int device, int reg, u16 val)
-{
- return mv88e6xxx_phy_write_c45(chip, lane, device, reg, val);
-}
-
-static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
- u16 bmsr, u16 lpa, u16 status,
- struct phylink_link_state *state)
+int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa,
+ u16 status, struct phylink_link_state *state)
{
state->link = false;
@@ -88,7 +81,7 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
state->speed = SPEED_10;
break;
default:
- dev_err(chip->dev, "invalid PHY speed\n");
+ dev_err(dev, "invalid PHY speed\n");
return -EINVAL;
}
} else if (state->link &&
@@ -117,160 +110,6 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
return 0;
}
-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool up)
-{
- u16 val, new_val;
- int err;
-
- err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
- if (err)
- return err;
-
- if (up)
- new_val = val & ~BMCR_PDOWN;
- else
- new_val = val | BMCR_PDOWN;
-
- if (val != new_val)
- err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
-
- return err;
-}
-
-int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- int lane, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise)
-{
- u16 adv, bmcr, val;
- bool changed;
- int err;
-
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- adv = 0x0001;
- break;
-
- case PHY_INTERFACE_MODE_1000BASEX:
- adv = linkmode_adv_to_mii_adv_x(advertise,
- ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
- break;
-
- default:
- return 0;
- }
-
- err = mv88e6352_serdes_read(chip, MII_ADVERTISE, &val);
- if (err)
- return err;
-
- changed = val != adv;
- if (changed) {
- err = mv88e6352_serdes_write(chip, MII_ADVERTISE, adv);
- if (err)
- return err;
- }
-
- err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
- if (err)
- return err;
-
- if (phylink_autoneg_inband(mode))
- bmcr = val | BMCR_ANENABLE;
- else
- bmcr = val & ~BMCR_ANENABLE;
-
- if (bmcr == val)
- return changed;
-
- return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
-}
-
-int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state)
-{
- u16 bmsr, lpa, status;
- int err;
-
- err = mv88e6352_serdes_read(chip, MII_BMSR, &bmsr);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY BMSR: %d\n", err);
- return err;
- }
-
- err = mv88e6352_serdes_read(chip, 0x11, &status);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
- return err;
- }
-
- err = mv88e6352_serdes_read(chip, MII_LPA, &lpa);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
- return err;
- }
-
- return mv88e6xxx_serdes_pcs_get_state(chip, bmsr, lpa, status, state);
-}
-
-int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- u16 bmcr;
- int err;
-
- err = mv88e6352_serdes_read(chip, MII_BMCR, &bmcr);
- if (err)
- return err;
-
- return mv88e6352_serdes_write(chip, MII_BMCR, bmcr | BMCR_ANRESTART);
-}
-
-int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- int lane, int speed, int duplex)
-{
- u16 val, bmcr;
- int err;
-
- err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
- if (err)
- return err;
-
- bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
- switch (speed) {
- case SPEED_1000:
- bmcr |= BMCR_SPEED1000;
- break;
- case SPEED_100:
- bmcr |= BMCR_SPEED100;
- break;
- case SPEED_10:
- break;
- }
-
- if (duplex == DUPLEX_FULL)
- bmcr |= BMCR_FULLDPLX;
-
- if (bmcr == val)
- return 0;
-
- return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
-}
-
-int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
-{
- u8 cmode = chip->ports[port].cmode;
- int lane = -ENODEV;
-
- if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
- (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
- (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
- lane = 0xff; /* Unused */
-
- return lane;
-}
-
struct mv88e6352_serdes_hw_stat {
char string[ETH_GSTRING_LEN];
int sizeof_stat;
@@ -363,51 +202,6 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
-static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
-{
- u16 bmsr;
- int err;
-
- /* If the link has dropped, we want to know about it. */
- err = mv88e6352_serdes_read(chip, MII_BMSR, &bmsr);
- if (err) {
- dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
- return;
- }
-
- dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
-}
-
-irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- irqreturn_t ret = IRQ_NONE;
- u16 status;
- int err;
-
- err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
- if (err)
- return ret;
-
- if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
- ret = IRQ_HANDLED;
- mv88e6352_serdes_irq_link(chip, port);
- }
-
- return ret;
-}
-
-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable)
-{
- u16 val = 0;
-
- if (enable)
- val |= MV88E6352_SERDES_INT_LINK_CHANGE;
-
- return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
-}
-
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
@@ -461,115 +255,6 @@ int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}
-int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool up)
-{
- /* The serdes power can't be controlled on this switch chip but we need
- * to supply this function to avoid returning -EOPNOTSUPP in
- * mv88e6xxx_serdes_power_up/mv88e6xxx_serdes_power_down
- */
- return 0;
-}
-
-int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
-{
- /* There are no configurable serdes lanes on this switch chip but we
- * need to return a non-negative lane number so that callers of
- * mv88e6xxx_serdes_get_lane() know this is a serdes port.
- */
- switch (chip->ports[port].cmode) {
- case MV88E6185_PORT_STS_CMODE_SERDES:
- case MV88E6185_PORT_STS_CMODE_1000BASE_X:
- return 0;
- default:
- return -ENODEV;
- }
-}
-
-int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state)
-{
- int err;
- u16 status;
-
- err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
- if (err)
- return err;
-
- state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
-
- if (state->link) {
- state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ? DUPLEX_FULL : DUPLEX_HALF;
-
- switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) {
- case MV88E6XXX_PORT_STS_SPEED_1000:
- state->speed = SPEED_1000;
- break;
- case MV88E6XXX_PORT_STS_SPEED_100:
- state->speed = SPEED_100;
- break;
- case MV88E6XXX_PORT_STS_SPEED_10:
- state->speed = SPEED_10;
- break;
- default:
- dev_err(chip->dev, "invalid PHY speed\n");
- return -EINVAL;
- }
- } else {
- state->duplex = DUPLEX_UNKNOWN;
- state->speed = SPEED_UNKNOWN;
- }
-
- return 0;
-}
-
-int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable)
-{
- u8 cmode = chip->ports[port].cmode;
-
- /* The serdes interrupts are enabled in the G2_INT_MASK register. We
- * need to return 0 to avoid returning -EOPNOTSUPP in
- * mv88e6xxx_serdes_irq_enable/mv88e6xxx_serdes_irq_disable
- */
- switch (cmode) {
- case MV88E6185_PORT_STS_CMODE_SERDES:
- case MV88E6185_PORT_STS_CMODE_1000BASE_X:
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-static void mv88e6097_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
-{
- u16 status;
- int err;
-
- err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
- if (err) {
- dev_err(chip->dev, "can't read port status: %d\n", err);
- return;
- }
-
- dsa_port_phylink_mac_change(chip->ds, port, !!(status & MV88E6XXX_PORT_STS_LINK));
-}
-
-irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- u8 cmode = chip->ports[port].cmode;
-
- switch (cmode) {
- case MV88E6185_PORT_STS_CMODE_SERDES:
- case MV88E6185_PORT_STS_CMODE_1000BASE_X:
- mv88e6097_serdes_irq_link(chip, port);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
u8 cmode = chip->ports[port].cmode;
@@ -690,57 +375,6 @@ int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
return lane;
}
-/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
-static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
- bool up)
-{
- u16 val, new_val;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_10G_CTRL1, &val);
-
- if (err)
- return err;
-
- if (up)
- new_val = val & ~(MDIO_CTRL1_RESET |
- MDIO_PCS_CTRL1_LOOPBACK |
- MDIO_CTRL1_LPOWER);
- else
- new_val = val | MDIO_CTRL1_LPOWER;
-
- if (val != new_val)
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_10G_CTRL1, new_val);
-
- return err;
-}
-
-/* Set power up/down for SGMII and 1000Base-X */
-static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
- bool up)
-{
- u16 val, new_val;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, &val);
- if (err)
- return err;
-
- if (up)
- new_val = val & ~(BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN);
- else
- new_val = val | BMCR_PDOWN;
-
- if (val != new_val)
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, new_val);
-
- return err;
-}
-
struct mv88e6390_serdes_hw_stat {
char string[ETH_GSTRING_LEN];
int reg;
@@ -814,484 +448,6 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}
-static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, int lane)
-{
- u16 reg;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_PG_CONTROL, &reg);
- if (err)
- return err;
-
- reg |= MV88E6390_PG_CONTROL_ENABLE_PC;
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_PG_CONTROL, reg);
-}
-
-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool up)
-{
- u8 cmode = chip->ports[port].cmode;
- int err;
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- err = mv88e6390_serdes_power_sgmii(chip, lane, up);
- break;
- case MV88E6XXX_PORT_STS_CMODE_XAUI:
- case MV88E6XXX_PORT_STS_CMODE_RXAUI:
- err = mv88e6390_serdes_power_10g(chip, lane, up);
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- if (!err && up)
- err = mv88e6390_serdes_enable_checker(chip, lane);
-
- return err;
-}
-
-int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- int lane, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise)
-{
- u16 val, bmcr, adv;
- bool changed;
- int err;
-
- switch (interface) {
- case PHY_INTERFACE_MODE_SGMII:
- adv = 0x0001;
- break;
-
- case PHY_INTERFACE_MODE_1000BASEX:
- adv = linkmode_adv_to_mii_adv_x(advertise,
- ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
- break;
-
- case PHY_INTERFACE_MODE_2500BASEX:
- adv = linkmode_adv_to_mii_adv_x(advertise,
- ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
- break;
-
- default:
- return 0;
- }
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_ADVERTISE, &val);
- if (err)
- return err;
-
- changed = val != adv;
- if (changed) {
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_ADVERTISE, adv);
- if (err)
- return err;
- }
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, &val);
- if (err)
- return err;
-
- if (phylink_autoneg_inband(mode))
- bmcr = val | BMCR_ANENABLE;
- else
- bmcr = val & ~BMCR_ANENABLE;
-
- /* setting ANENABLE triggers a restart of negotiation */
- if (bmcr == val)
- return changed;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, bmcr);
-}
-
-static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
- int port, int lane, struct phylink_link_state *state)
-{
- u16 bmsr, lpa, status;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMSR, &bmsr);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY BMSR: %d\n", err);
- return err;
- }
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_PHY_STATUS, &status);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
- return err;
- }
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_LPA, &lpa);
- if (err) {
- dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
- return err;
- }
-
- return mv88e6xxx_serdes_pcs_get_state(chip, bmsr, lpa, status, state);
-}
-
-static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
- int port, int lane, struct phylink_link_state *state)
-{
- u16 status;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_10G_STAT1, &status);
- if (err)
- return err;
-
- state->link = !!(status & MDIO_STAT1_LSTATUS);
- if (state->link) {
- state->speed = SPEED_10000;
- state->duplex = DUPLEX_FULL;
- }
-
- return 0;
-}
-
-static int mv88e6393x_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
- int port, int lane,
- struct phylink_link_state *state)
-{
- u16 status;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_10G_STAT1, &status);
- if (err)
- return err;
-
- state->link = !!(status & MDIO_STAT1_LSTATUS);
- if (state->link) {
- if (state->interface == PHY_INTERFACE_MODE_5GBASER)
- state->speed = SPEED_5000;
- else
- state->speed = SPEED_10000;
- state->duplex = DUPLEX_FULL;
- }
- return 0;
-}
-
-/* USXGMII registers for Marvell switch 88e639x are undocumented and this function is based
- * on some educated guesses. It appears that there are no status bits related to
- * autonegotiation complete or flow control.
- */
-static int mv88e639x_serdes_pcs_get_state_usxgmii(struct mv88e6xxx_chip *chip,
- int port, int lane,
- struct phylink_link_state *state)
-{
- u16 status, lp_status;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_USXGMII_PHY_STATUS, &status);
- if (err) {
- dev_err(chip->dev, "can't read Serdes USXGMII PHY status: %d\n", err);
- return err;
- }
- dev_dbg(chip->dev, "USXGMII PHY status: 0x%x\n", status);
-
- state->link = !!(status & MDIO_USXGMII_LINK);
- state->an_complete = state->link;
-
- if (state->link) {
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_USXGMII_LP_STATUS, &lp_status);
- if (err) {
- dev_err(chip->dev, "can't read Serdes USXGMII LP status: %d\n", err);
- return err;
- }
- dev_dbg(chip->dev, "USXGMII LP status: 0x%x\n", lp_status);
- /* lp_status appears to include the "link" bit as per USXGMII spec. */
- phylink_decode_usxgmii_word(state, lp_status);
- }
- return 0;
-}
-
-int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state)
-{
- switch (state->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- case PHY_INTERFACE_MODE_2500BASEX:
- return mv88e6390_serdes_pcs_get_state_sgmii(chip, port, lane,
- state);
- case PHY_INTERFACE_MODE_XAUI:
- case PHY_INTERFACE_MODE_RXAUI:
- return mv88e6390_serdes_pcs_get_state_10g(chip, port, lane,
- state);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
-int mv88e6393x_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state)
-{
- switch (state->interface) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- case PHY_INTERFACE_MODE_2500BASEX:
- return mv88e6390_serdes_pcs_get_state_sgmii(chip, port, lane,
- state);
- case PHY_INTERFACE_MODE_5GBASER:
- case PHY_INTERFACE_MODE_10GBASER:
- return mv88e6393x_serdes_pcs_get_state_10g(chip, port, lane,
- state);
- case PHY_INTERFACE_MODE_USXGMII:
- return mv88e639x_serdes_pcs_get_state_usxgmii(chip, port, lane,
- state);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
-int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- u16 bmcr;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, &bmcr);
- if (err)
- return err;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR,
- bmcr | BMCR_ANRESTART);
-}
-
-int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- int lane, int speed, int duplex)
-{
- u16 val, bmcr;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, &val);
- if (err)
- return err;
-
- bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
- switch (speed) {
- case SPEED_2500:
- case SPEED_1000:
- bmcr |= BMCR_SPEED1000;
- break;
- case SPEED_100:
- bmcr |= BMCR_SPEED100;
- break;
- case SPEED_10:
- break;
- }
-
- if (duplex == DUPLEX_FULL)
- bmcr |= BMCR_FULLDPLX;
-
- if (bmcr == val)
- return 0;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMCR, bmcr);
-}
-
-static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
- int port, int lane)
-{
- u16 bmsr;
- int err;
-
- /* If the link has dropped, we want to know about it. */
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_BMSR, &bmsr);
- if (err) {
- dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
- return;
- }
-
- dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
-}
-
-static void mv88e6393x_serdes_irq_link_10g(struct mv88e6xxx_chip *chip,
- int port, u8 lane)
-{
- u16 status;
- int err;
-
- /* If the link has dropped, we want to know about it. */
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_10G_STAT1, &status);
- if (err) {
- dev_err(chip->dev, "can't read Serdes STAT1: %d\n", err);
- return;
- }
-
- dsa_port_phylink_mac_change(chip->ds, port, !!(status & MDIO_STAT1_LSTATUS));
-}
-
-static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
- int lane, bool enable)
-{
- u16 val = 0;
-
- if (enable)
- val |= MV88E6390_SGMII_INT_LINK_DOWN |
- MV88E6390_SGMII_INT_LINK_UP;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_INT_ENABLE, val);
-}
-
-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable)
-{
- u8 cmode = chip->ports[port].cmode;
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
- }
-
- return 0;
-}
-
-static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
- int lane, u16 *status)
-{
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6390_SGMII_INT_STATUS, status);
-
- return err;
-}
-
-static int mv88e6393x_serdes_irq_enable_10g(struct mv88e6xxx_chip *chip,
- u8 lane, bool enable)
-{
- u16 val = 0;
-
- if (enable)
- val |= MV88E6393X_10G_INT_LINK_CHANGE;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_10G_INT_ENABLE, val);
-}
-
-int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
- int lane, bool enable)
-{
- u8 cmode = chip->ports[port].cmode;
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
- case MV88E6393X_PORT_STS_CMODE_5GBASER:
- case MV88E6393X_PORT_STS_CMODE_10GBASER:
- case MV88E6393X_PORT_STS_CMODE_USXGMII:
- return mv88e6393x_serdes_irq_enable_10g(chip, lane, enable);
- }
-
- return 0;
-}
-
-static int mv88e6393x_serdes_irq_status_10g(struct mv88e6xxx_chip *chip,
- u8 lane, u16 *status)
-{
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_10G_INT_STATUS, status);
-
- return err;
-}
-
-irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- u8 cmode = chip->ports[port].cmode;
- irqreturn_t ret = IRQ_NONE;
- u16 status;
- int err;
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
- if (err)
- return ret;
- if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
- MV88E6390_SGMII_INT_LINK_UP)) {
- ret = IRQ_HANDLED;
- mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
- }
- break;
- case MV88E6393X_PORT_STS_CMODE_5GBASER:
- case MV88E6393X_PORT_STS_CMODE_10GBASER:
- case MV88E6393X_PORT_STS_CMODE_USXGMII:
- err = mv88e6393x_serdes_irq_status_10g(chip, lane, &status);
- if (err)
- return err;
- if (status & MV88E6393X_10G_INT_LINK_CHANGE) {
- ret = IRQ_HANDLED;
- mv88e6393x_serdes_irq_link_10g(chip, port, lane);
- }
- break;
- }
-
- return ret;
-}
-
-irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane)
-{
- u8 cmode = chip->ports[port].cmode;
- irqreturn_t ret = IRQ_NONE;
- u16 status;
- int err;
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
- if (err)
- return ret;
- if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
- MV88E6390_SGMII_INT_LINK_UP)) {
- ret = IRQ_HANDLED;
- mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
- }
- }
-
- return ret;
-}
-
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
return irq_find_mapping(chip->g2_irq.domain, port);
@@ -1390,259 +546,3 @@ int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port,
return mv88e6352_serdes_write(chip, MV88E6352_SERDES_SPEC_CTRL2, ctrl);
}
-
-static int mv88e6393x_serdes_power_lane(struct mv88e6xxx_chip *chip, int lane,
- bool on)
-{
- u16 reg;
- int err;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_CTRL1, &reg);
- if (err)
- return err;
-
- if (on)
- reg &= ~(MV88E6393X_SERDES_CTRL1_TX_PDOWN |
- MV88E6393X_SERDES_CTRL1_RX_PDOWN);
- else
- reg |= MV88E6393X_SERDES_CTRL1_TX_PDOWN |
- MV88E6393X_SERDES_CTRL1_RX_PDOWN;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_CTRL1, reg);
-}
-
-static int mv88e6393x_serdes_erratum_4_6(struct mv88e6xxx_chip *chip, int lane)
-{
- u16 reg;
- int err;
-
- /* mv88e6393x family errata 4.6:
- * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD
- * mode or P0_mode is configured for [x]MII.
- * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1.
- *
- * It seems that after this workaround the SERDES is automatically
- * powered up (the bit is cleared), so power it down.
- */
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_POC, &reg);
- if (err)
- return err;
-
- reg &= ~MV88E6393X_SERDES_POC_PDOWN;
- reg |= MV88E6393X_SERDES_POC_RESET;
-
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_POC, reg);
- if (err)
- return err;
-
- err = mv88e6390_serdes_power_sgmii(chip, lane, false);
- if (err)
- return err;
-
- return mv88e6393x_serdes_power_lane(chip, lane, false);
-}
-
-int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip)
-{
- int err;
-
- err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT0_LANE);
- if (err)
- return err;
-
- err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT9_LANE);
- if (err)
- return err;
-
- return mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT10_LANE);
-}
-
-static int mv88e6393x_serdes_erratum_4_8(struct mv88e6xxx_chip *chip, int lane)
-{
- u16 reg, pcs;
- int err;
-
- /* mv88e6393x family errata 4.8:
- * When a SERDES port is operating in 1000BASE-X or SGMII mode link may
- * not come up after hardware reset or software reset of SERDES core.
- * Workaround is to write SERDES register 4.F074.14=1 for only those
- * modes and 0 in all other modes.
- */
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_POC, &pcs);
- if (err)
- return err;
-
- pcs &= MV88E6393X_SERDES_POC_PCS_MASK;
-
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_ERRATA_4_8_REG, &reg);
- if (err)
- return err;
-
- if (pcs == MV88E6393X_SERDES_POC_PCS_1000BASEX ||
- pcs == MV88E6393X_SERDES_POC_PCS_SGMII_PHY ||
- pcs == MV88E6393X_SERDES_POC_PCS_SGMII_MAC)
- reg |= MV88E6393X_ERRATA_4_8_BIT;
- else
- reg &= ~MV88E6393X_ERRATA_4_8_BIT;
-
- return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_ERRATA_4_8_REG, reg);
-}
-
-static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane,
- u8 cmode)
-{
- static const struct {
- u16 dev, reg, val, mask;
- } fixes[] = {
- { MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
- { MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
- { MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
- { MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
- { MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
- { MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
- { MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC,
- MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET },
- };
- int err, i;
- u16 reg;
-
- /* mv88e6393x family errata 5.2:
- * For optimal signal integrity the following sequence should be applied
- * to SERDES operating in 10G mode. These registers only apply to 10G
- * operation and have no effect on other speeds.
- */
- if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER &&
- cmode != MV88E6393X_PORT_STS_CMODE_USXGMII)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
- err = mv88e6390_serdes_read(chip, lane, fixes[i].dev,
- fixes[i].reg, &reg);
- if (err)
- return err;
-
- reg &= ~fixes[i].mask;
- reg |= fixes[i].val;
-
- err = mv88e6390_serdes_write(chip, lane, fixes[i].dev,
- fixes[i].reg, reg);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int mv88e6393x_serdes_fix_2500basex_an(struct mv88e6xxx_chip *chip,
- int lane, u8 cmode, bool on)
-{
- u16 reg;
- int err;
-
- if (cmode != MV88E6XXX_PORT_STS_CMODE_2500BASEX)
- return 0;
-
- /* Inband AN is broken on Amethyst in 2500base-x mode when set by
- * standard mechanism (via cmode).
- * We can get around this by configuring the PCS mode to 1000base-x
- * and then writing value 0x58 to register 1e.8000. (This must be done
- * while SerDes receiver and transmitter are disabled, which is, when
- * this function is called.)
- * It seem that when we do this configuration to 2500base-x mode (by
- * changing PCS mode to 1000base-x and frequency to 3.125 GHz from
- * 1.25 GHz) and then configure to sgmii or 1000base-x, the device
- * thinks that it already has SerDes at 1.25 GHz and does not change
- * the 1e.8000 register, leaving SerDes at 3.125 GHz.
- * To avoid this, change PCS mode back to 2500base-x when disabling
- * SerDes from 2500base-x mode.
- */
- err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_POC, &reg);
- if (err)
- return err;
-
- reg &= ~(MV88E6393X_SERDES_POC_PCS_MASK | MV88E6393X_SERDES_POC_AN);
- if (on)
- reg |= MV88E6393X_SERDES_POC_PCS_1000BASEX |
- MV88E6393X_SERDES_POC_AN;
- else
- reg |= MV88E6393X_SERDES_POC_PCS_2500BASEX;
- reg |= MV88E6393X_SERDES_POC_RESET;
-
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
- MV88E6393X_SERDES_POC, reg);
- if (err)
- return err;
-
- err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_VEND1, 0x8000, 0x58);
- if (err)
- return err;
-
- return 0;
-}
-
-int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool on)
-{
- u8 cmode = chip->ports[port].cmode;
- int err;
-
- if (port != 0 && port != 9 && port != 10)
- return -EOPNOTSUPP;
-
- if (on) {
- err = mv88e6393x_serdes_erratum_4_8(chip, lane);
- if (err)
- return err;
-
- err = mv88e6393x_serdes_erratum_5_2(chip, lane, cmode);
- if (err)
- return err;
-
- err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
- true);
- if (err)
- return err;
-
- err = mv88e6393x_serdes_power_lane(chip, lane, true);
- if (err)
- return err;
- }
-
- switch (cmode) {
- case MV88E6XXX_PORT_STS_CMODE_SGMII:
- case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
- case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
- err = mv88e6390_serdes_power_sgmii(chip, lane, on);
- break;
- case MV88E6393X_PORT_STS_CMODE_5GBASER:
- case MV88E6393X_PORT_STS_CMODE_10GBASER:
- case MV88E6393X_PORT_STS_CMODE_USXGMII:
- err = mv88e6390_serdes_power_10g(chip, lane, on);
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- if (err)
- return err;
-
- if (!on) {
- err = mv88e6393x_serdes_power_lane(chip, lane, false);
- if (err)
- return err;
-
- err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
- false);
- }
-
- return err;
-}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index e245687ddb1d..aac95cab46e3 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -12,6 +12,8 @@
#include "chip.h"
+struct phylink_link_state;
+
#define MV88E6352_ADDR_SERDES 0x0f
#define MV88E6352_SERDES_PAGE_FIBER 0x01
#define MV88E6352_SERDES_IRQ 0x0b
@@ -44,6 +46,10 @@
/* 10GBASE-R and 10GBASE-X4/X2 */
#define MV88E6390_10G_CTRL1 (0x1000 + MDIO_CTRL1)
#define MV88E6390_10G_STAT1 (0x1000 + MDIO_STAT1)
+#define MV88E6390_10G_INT_ENABLE 0x9001
+#define MV88E6390_10G_INT_LINK_DOWN BIT(3)
+#define MV88E6390_10G_INT_LINK_UP BIT(2)
+#define MV88E6390_10G_INT_STATUS 0x9003
#define MV88E6393X_10G_INT_ENABLE 0x9000
#define MV88E6393X_10G_INT_LINK_CHANGE BIT(2)
#define MV88E6393X_10G_INT_STATUS 0x9001
@@ -107,65 +113,17 @@
#define MV88E6393X_ERRATA_4_8_REG 0xF074
#define MV88E6393X_ERRATA_4_8_BIT BIT(14)
-int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
+int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa,
+ u16 status, struct phylink_link_state *state);
+
int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
-int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- int lane, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise);
-int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
- int lane, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertise);
-int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state);
-int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state);
-int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state);
-int mv88e6393x_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
- int lane, struct phylink_link_state *state);
-int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- int lane);
-int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
- int lane);
-int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- int lane, int speed, int duplex);
-int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
- int lane, int speed, int duplex);
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
-int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool up);
-int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool on);
-int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool on);
-int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
- bool on);
-int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip);
-int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable);
-int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable);
-int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
- bool enable);
-int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
- int lane, bool enable);
-irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane);
-irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane);
-irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane);
-irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
- int lane);
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);
@@ -195,24 +153,6 @@ static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
return chip->info->ops->serdes_get_lane(chip, port);
}
-static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip,
- int port, int lane)
-{
- if (!chip->info->ops->serdes_power)
- return -EOPNOTSUPP;
-
- return chip->info->ops->serdes_power(chip, port, lane, true);
-}
-
-static inline int mv88e6xxx_serdes_power_down(struct mv88e6xxx_chip *chip,
- int port, int lane)
-{
- if (!chip->info->ops->serdes_power)
- return -EOPNOTSUPP;
-
- return chip->info->ops->serdes_power(chip, port, lane, false);
-}
-
static inline unsigned int
mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
@@ -222,31 +162,9 @@ mv88e6xxx_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
return chip->info->ops->serdes_irq_mapping(chip, port);
}
-static inline int mv88e6xxx_serdes_irq_enable(struct mv88e6xxx_chip *chip,
- int port, int lane)
-{
- if (!chip->info->ops->serdes_irq_enable)
- return -EOPNOTSUPP;
-
- return chip->info->ops->serdes_irq_enable(chip, port, lane, true);
-}
-
-static inline int mv88e6xxx_serdes_irq_disable(struct mv88e6xxx_chip *chip,
- int port, int lane)
-{
- if (!chip->info->ops->serdes_irq_enable)
- return -EOPNOTSUPP;
-
- return chip->info->ops->serdes_irq_enable(chip, port, lane, false);
-}
-
-static inline irqreturn_t
-mv88e6xxx_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, int lane)
-{
- if (!chip->info->ops->serdes_irq_status)
- return IRQ_NONE;
-
- return chip->info->ops->serdes_irq_status(chip, port, lane);
-}
+extern const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops;
+extern const struct mv88e6xxx_pcs_ops mv88e6352_pcs_ops;
+extern const struct mv88e6xxx_pcs_ops mv88e6390_pcs_ops;
+extern const struct mv88e6xxx_pcs_ops mv88e6393x_pcs_ops;
#endif
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index bef879c6d500..9a3e5ec16972 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1042,12 +1042,6 @@ static void felix_phylink_get_caps(struct dsa_switch *ds, int port,
{
struct ocelot *ocelot = ds->priv;
- /* This driver does not make use of the speed, duplex, pause or the
- * advertisement in its mac_config, so it is safe to mark this driver
- * as non-legacy.
- */
- config->legacy_pre_march2020 = false;
-
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000FD |
MAC_2500FD;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 1c113957fcf4..3c5509e75a54 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -16,6 +16,7 @@
#include <net/pkt_sched.h>
#include <linux/iopoll.h>
#include <linux/mdio.h>
+#include <linux/of.h>
#include <linux/pci.h>
#include <linux/time.h>
#include "felix.h"
@@ -1069,6 +1070,9 @@ static u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns)
if (gate_len_ns == U64_MAX)
return U64_MAX;
+ if (gate_len_ns < VSC9959_TAS_MIN_GATE_LEN_NS)
+ return 0;
+
return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC;
}
@@ -1745,10 +1749,10 @@ static int vsc9959_stream_identify(struct flow_cls_offload *f,
struct flow_dissector *dissector = rule->match.dissector;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)))
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS)))
return -EOPNOTSUPP;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 15003b2af264..8f912bda120b 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -2,13 +2,14 @@
/* Distributed Switch Architecture VSC9953 driver
* Copyright (C) 2020, Maxim Kochetkov <fido_max@inbox.ru>
*/
+#include <linux/platform_device.h>
#include <linux/types.h>
#include <soc/mscc/ocelot_vcap.h>
#include <soc/mscc/ocelot_sys.h>
#include <soc/mscc/ocelot.h>
#include <linux/mdio/mdio-mscc-miim.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
#include <linux/pcs-lynx.h>
#include <linux/dsa/ocelot.h>
#include <linux/iopoll.h>
diff --git a/drivers/net/dsa/qca/ar9331.c b/drivers/net/dsa/qca/ar9331.c
index 3b0937031499..8d9d271ac3af 100644
--- a/drivers/net/dsa/qca/ar9331.c
+++ b/drivers/net/dsa/qca/ar9331.c
@@ -1012,7 +1012,7 @@ static const struct regmap_config ar9331_mdio_regmap_config = {
.wr_table = &ar9331_register_set,
.rd_table = &ar9331_register_set,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static struct regmap_bus ar9331_sw_bus = {
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index efe9380d4a15..de1dc22cf683 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1400,8 +1400,6 @@ static void qca8k_phylink_get_caps(struct dsa_switch *ds, int port,
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000FD;
-
- config->legacy_pre_march2020 = false;
}
static void
@@ -1758,11 +1756,52 @@ static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
return 0;
}
+static void qca8k_setup_hol_fixup(struct qca8k_priv *priv, int port)
+{
+ u32 mask;
+
+ switch (port) {
+ /* The 2 CPU port and port 5 requires some different
+ * priority than any other ports.
+ */
+ case 0:
+ case 5:
+ case 6:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
+ break;
+ default:
+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
+ }
+ regmap_write(priv->regmap, QCA8K_REG_PORT_HOL_CTRL0(port), mask);
+
+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN;
+ regmap_update_bits(priv->regmap, QCA8K_REG_PORT_HOL_CTRL1(port),
+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK |
+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+ QCA8K_PORT_HOL_CTRL1_WRED_EN,
+ mask);
+}
+
static int
qca8k_setup(struct dsa_switch *ds)
{
struct qca8k_priv *priv = ds->priv;
- int cpu_port, ret, i;
+ struct dsa_port *dp;
+ int cpu_port, ret;
u32 mask;
cpu_port = qca8k_find_cpu_port(ds);
@@ -1817,27 +1856,27 @@ qca8k_setup(struct dsa_switch *ds)
dev_warn(priv->dev, "mib init failed");
/* Initial setup of all ports */
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ dsa_switch_for_each_port(dp, ds) {
/* Disable forwarding by default on all ports */
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(dp->index),
QCA8K_PORT_LOOKUP_MEMBER, 0);
if (ret)
return ret;
+ }
- /* Enable QCA header mode on all cpu ports */
- if (dsa_is_cpu_port(ds, i)) {
- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i),
- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
- if (ret) {
- dev_err(priv->dev, "failed enabling QCA header mode");
- return ret;
- }
+ /* Disable MAC by default on all user ports */
+ dsa_switch_for_each_user_port(dp, ds)
+ qca8k_port_set_status(priv, dp->index, 0);
+
+ /* Enable QCA header mode on all cpu ports */
+ dsa_switch_for_each_cpu_port(dp, ds) {
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(dp->index),
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
+ if (ret) {
+ dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index);
+ return ret;
}
-
- /* Disable MAC by default on all user ports */
- if (dsa_is_user_port(ds, i))
- qca8k_port_set_status(priv, i, 0);
}
/* Forward all unknown frames to CPU port for Linux processing
@@ -1852,92 +1891,55 @@ qca8k_setup(struct dsa_switch *ds)
if (ret)
return ret;
+ /* CPU port gets connected to all user ports of the switch */
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+ if (ret)
+ return ret;
+
/* Setup connection between CPU port & user ports
- * Configure specific switch configuration for ports
+ * Individual user ports get connected to CPU port only
*/
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
- /* CPU port gets connected to all user ports of the switch */
- if (dsa_is_cpu_port(ds, i)) {
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
- if (ret)
- return ret;
- }
+ dsa_switch_for_each_user_port(dp, ds) {
+ u8 port = dp->index;
- /* Individual user ports get connected to CPU port only */
- if (dsa_is_user_port(ds, i)) {
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_MEMBER,
- BIT(cpu_port));
- if (ret)
- return ret;
-
- /* Enable ARP Auto-learning by default */
- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
- QCA8K_PORT_LOOKUP_LEARN);
- if (ret)
- return ret;
-
- /* For port based vlans to work we need to set the
- * default egress vid
- */
- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
- QCA8K_EGREES_VLAN_PORT_MASK(i),
- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF));
- if (ret)
- return ret;
-
- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i),
- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
- if (ret)
- return ret;
- }
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER,
+ BIT(cpu_port));
+ if (ret)
+ return ret;
- /* The port 5 of the qca8337 have some problem in flood condition. The
- * original legacy driver had some specific buffer and priority settings
- * for the different port suggested by the QCA switch team. Add this
- * missing settings to improve switch stability under load condition.
- * This problem is limited to qca8337 and other qca8k switch are not affected.
+ ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_LEARN);
+ if (ret)
+ return ret;
+
+ /* For port based vlans to work we need to set the
+ * default egress vid
*/
- if (priv->switch_id == QCA8K_ID_QCA8337) {
- switch (i) {
- /* The 2 CPU port and port 5 requires some different
- * priority than any other ports.
- */
- case 0:
- case 5:
- case 6:
- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e);
- break;
- default:
- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
- }
- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask);
-
- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) |
- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
- QCA8K_PORT_HOL_CTRL1_WRED_EN;
- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i),
- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK |
- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
- QCA8K_PORT_HOL_CTRL1_WRED_EN,
- mask);
- }
+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
+ QCA8K_EGREES_VLAN_PORT_MASK(port),
+ QCA8K_EGREES_VLAN_PORT(port, QCA8K_PORT_VID_DEF));
+ if (ret)
+ return ret;
+
+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF));
+ if (ret)
+ return ret;
}
+ /* The port 5 of the qca8337 have some problem in flood condition. The
+ * original legacy driver had some specific buffer and priority settings
+ * for the different port suggested by the QCA switch team. Add this
+ * missing settings to improve switch stability under load condition.
+ * This problem is limited to qca8337 and other qca8k switch are not affected.
+ */
+ if (priv->switch_id == QCA8K_ID_QCA8337)
+ dsa_switch_for_each_available_port(dp, ds)
+ qca8k_setup_hol_fixup(priv, dp->index);
+
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
if (priv->switch_id == QCA8K_ID_QCA8327) {
mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
@@ -1980,6 +1982,8 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
.port_change_mtu = qca8k_port_change_mtu,
.port_max_mtu = qca8k_port_max_mtu,
.port_stp_state_set = qca8k_port_stp_state_set,
+ .port_pre_bridge_flags = qca8k_port_pre_bridge_flags,
+ .port_bridge_flags = qca8k_port_bridge_flags,
.port_bridge_join = qca8k_port_bridge_join,
.port_bridge_leave = qca8k_port_bridge_leave,
.port_fast_age = qca8k_port_fast_age,
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 13b8452ce5b2..fce04ce12cf9 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -565,9 +565,26 @@ int qca8k_get_mac_eee(struct dsa_switch *ds, int port,
return 0;
}
+static int qca8k_port_configure_learning(struct dsa_switch *ds, int port,
+ bool learning)
+{
+ struct qca8k_priv *priv = ds->priv;
+
+ if (learning)
+ return regmap_set_bits(priv->regmap,
+ QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_LEARN);
+ else
+ return regmap_clear_bits(priv->regmap,
+ QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_LEARN);
+}
+
void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{
+ struct dsa_port *dp = dsa_to_port(ds, port);
struct qca8k_priv *priv = ds->priv;
+ bool learning = false;
u32 stp_state;
switch (state) {
@@ -582,8 +599,11 @@ void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
break;
case BR_STATE_LEARNING:
stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
+ learning = dp->learning;
break;
case BR_STATE_FORWARDING:
+ learning = dp->learning;
+ fallthrough;
default:
stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
break;
@@ -591,6 +611,34 @@ void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
+
+ qca8k_port_configure_learning(ds, port, learning);
+}
+
+int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack)
+{
+ if (flags.mask & ~BR_LEARNING)
+ return -EINVAL;
+
+ return 0;
+}
+
+int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack)
+{
+ int ret;
+
+ if (flags.mask & BR_LEARNING) {
+ ret = qca8k_port_configure_learning(ds, port,
+ flags.val & BR_LEARNING);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c
index 1261e0bb21ef..e8c16e76e34b 100644
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/property.h>
#include <linux/regmap.h>
#include <net/dsa.h>
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index c5cc8a172d65..8f88b7db384d 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -522,6 +522,12 @@ int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
/* Common bridge function */
void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
+int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack);
+int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack);
int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge,
bool *tx_fwd_offload,
diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c
index 5a8fe707ca25..292e6d087e8b 100644
--- a/drivers/net/dsa/realtek/realtek-mdio.c
+++ b/drivers/net/dsa/realtek/realtek-mdio.c
@@ -20,7 +20,7 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/regmap.h>
@@ -276,7 +276,7 @@ MODULE_DEVICE_TABLE(of, realtek_mdio_of_match);
static struct mdio_driver realtek_mdio_driver = {
.mdiodrv.driver = {
.name = "realtek-mdio",
- .of_match_table = of_match_ptr(realtek_mdio_of_match),
+ .of_match_table = realtek_mdio_of_match,
},
.probe = realtek_mdio_probe,
.remove = realtek_mdio_remove,
diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c
index 1b447d96b9c4..ff13563059c5 100644
--- a/drivers/net/dsa/realtek/realtek-smi.c
+++ b/drivers/net/dsa/realtek/realtek-smi.c
@@ -31,7 +31,6 @@
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -557,7 +556,7 @@ MODULE_DEVICE_TABLE(of, realtek_smi_of_match);
static struct platform_driver realtek_smi_driver = {
.driver = {
.name = "realtek-smi",
- .of_match_table = of_match_ptr(realtek_smi_of_match),
+ .of_match_table = realtek_smi_of_match,
},
.probe = realtek_smi_probe,
.remove = realtek_smi_remove,
diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c
index 25f88022b9e4..7868ef237f6c 100644
--- a/drivers/net/dsa/realtek/rtl8366rb.c
+++ b/drivers/net/dsa/realtek/rtl8366rb.c
@@ -1049,6 +1049,32 @@ static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,
return DSA_TAG_PROTO_RTL4_A;
}
+static void rtl8366rb_phylink_get_caps(struct dsa_switch *ds, int port,
+ struct phylink_config *config)
+{
+ unsigned long *interfaces = config->supported_interfaces;
+ struct realtek_priv *priv = ds->priv;
+
+ if (port == priv->cpu_port) {
+ __set_bit(PHY_INTERFACE_MODE_MII, interfaces);
+ __set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
+ /* REVMII only supports 100M FD */
+ __set_bit(PHY_INTERFACE_MODE_REVMII, interfaces);
+ /* RGMII only supports 1G FD */
+ phy_interface_set_rgmii(interfaces);
+
+ config->mac_capabilities = MAC_1000 | MAC_100 |
+ MAC_SYM_PAUSE;
+ } else {
+ /* RSGMII port, but we don't have that, and we don't
+ * specify in DT, so phylib uses the default of GMII
+ */
+ __set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
+ config->mac_capabilities = MAC_1000 | MAC_100 | MAC_10 |
+ MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+ }
+}
+
static void
rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface, struct phy_device *phydev,
@@ -1796,6 +1822,7 @@ static int rtl8366rb_detect(struct realtek_priv *priv)
static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = {
.get_tag_protocol = rtl8366_get_tag_protocol,
.setup = rtl8366rb_setup,
+ .phylink_get_caps = rtl8366rb_phylink_get_caps,
.phylink_mac_link_up = rtl8366rb_mac_link_up,
.phylink_mac_link_down = rtl8366rb_mac_link_down,
.get_strings = rtl8366_get_strings,
@@ -1821,6 +1848,7 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops_mdio = {
.setup = rtl8366rb_setup,
.phy_read = rtl8366rb_dsa_phy_read,
.phy_write = rtl8366rb_dsa_phy_write,
+ .phylink_get_caps = rtl8366rb_phylink_get_caps,
.phylink_mac_link_up = rtl8366rb_mac_link_up,
.phylink_mac_link_down = rtl8366rb_mac_link_down,
.get_strings = rtl8366_get_strings,
diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c
index c37d2e537230..2eda10b33f2e 100644
--- a/drivers/net/dsa/rzn1_a5psw.c
+++ b/drivers/net/dsa/rzn1_a5psw.c
@@ -331,13 +331,9 @@ static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
A5PSW_MCAST_DEF_MASK};
int i;
- if (set)
- a5psw->bridged_ports |= BIT(port);
- else
- a5psw->bridged_ports &= ~BIT(port);
-
for (i = 0; i < ARRAY_SIZE(offsets); i++)
- a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports);
+ a5psw_reg_rmw(a5psw, offsets[i], BIT(port),
+ set ? BIT(port) : 0);
}
static void a5psw_port_set_standalone(struct a5psw *a5psw, int port,
@@ -365,6 +361,8 @@ static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
a5psw->br_dev = bridge.dev;
a5psw_port_set_standalone(a5psw, port, false);
+ a5psw->bridged_ports |= BIT(port);
+
return 0;
}
@@ -373,6 +371,8 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
{
struct a5psw *a5psw = ds->priv;
+ a5psw->bridged_ports &= ~BIT(port);
+
a5psw_port_set_standalone(a5psw, port, true);
/* No more ports bridged */
@@ -380,9 +380,63 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
a5psw->br_dev = NULL;
}
+static int a5psw_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack)
+{
+ if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
+ BR_BCAST_FLOOD))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+a5psw_port_bridge_flags(struct dsa_switch *ds, int port,
+ struct switchdev_brport_flags flags,
+ struct netlink_ext_ack *extack)
+{
+ struct a5psw *a5psw = ds->priv;
+ u32 val;
+
+ /* If a port is set as standalone, we do not want to be able to
+ * configure flooding nor learning which would result in joining the
+ * unique bridge. This can happen when a port leaves the bridge, in
+ * which case the DSA core will try to "clear" all flags for the
+ * standalone port (ie enable flooding, disable learning). In that case
+ * do not fail but do not apply the flags.
+ */
+ if (!(a5psw->bridged_ports & BIT(port)))
+ return 0;
+
+ if (flags.mask & BR_LEARNING) {
+ val = flags.val & BR_LEARNING ? 0 : A5PSW_INPUT_LEARN_DIS(port);
+ a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN,
+ A5PSW_INPUT_LEARN_DIS(port), val);
+ }
+
+ if (flags.mask & BR_FLOOD) {
+ val = flags.val & BR_FLOOD ? BIT(port) : 0;
+ a5psw_reg_rmw(a5psw, A5PSW_UCAST_DEF_MASK, BIT(port), val);
+ }
+
+ if (flags.mask & BR_MCAST_FLOOD) {
+ val = flags.val & BR_MCAST_FLOOD ? BIT(port) : 0;
+ a5psw_reg_rmw(a5psw, A5PSW_MCAST_DEF_MASK, BIT(port), val);
+ }
+
+ if (flags.mask & BR_BCAST_FLOOD) {
+ val = flags.val & BR_BCAST_FLOOD ? BIT(port) : 0;
+ a5psw_reg_rmw(a5psw, A5PSW_BCAST_DEF_MASK, BIT(port), val);
+ }
+
+ return 0;
+}
+
static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{
bool learning_enabled, rx_enabled, tx_enabled;
+ struct dsa_port *dp = dsa_to_port(ds, port);
struct a5psw *a5psw = ds->priv;
switch (state) {
@@ -396,12 +450,12 @@ static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
case BR_STATE_LEARNING:
rx_enabled = false;
tx_enabled = false;
- learning_enabled = true;
+ learning_enabled = dp->learning;
break;
case BR_STATE_FORWARDING:
rx_enabled = true;
tx_enabled = true;
- learning_enabled = true;
+ learning_enabled = dp->learning;
break;
default:
dev_err(ds->dev, "invalid STP state: %d\n", state);
@@ -585,6 +639,140 @@ out_unlock:
return ret;
}
+static int a5psw_port_vlan_filtering(struct dsa_switch *ds, int port,
+ bool vlan_filtering,
+ struct netlink_ext_ack *extack)
+{
+ u32 mask = BIT(port + A5PSW_VLAN_VERI_SHIFT) |
+ BIT(port + A5PSW_VLAN_DISC_SHIFT);
+ u32 val = vlan_filtering ? mask : 0;
+ struct a5psw *a5psw = ds->priv;
+
+ /* Disable/enable vlan tagging */
+ a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE_ENA, BIT(port),
+ vlan_filtering ? BIT(port) : 0);
+
+ /* Disable/enable vlan input filtering */
+ a5psw_reg_rmw(a5psw, A5PSW_VLAN_VERIFY, mask, val);
+
+ return 0;
+}
+
+static int a5psw_find_vlan_entry(struct a5psw *a5psw, u16 vid)
+{
+ u32 vlan_res;
+ int i;
+
+ /* Find vlan for this port */
+ for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
+ vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
+ if (FIELD_GET(A5PSW_VLAN_RES_VLANID, vlan_res) == vid)
+ return i;
+ }
+
+ return -1;
+}
+
+static int a5psw_new_vlan_res_entry(struct a5psw *a5psw, u16 newvid)
+{
+ u32 vlan_res;
+ int i;
+
+ /* Find a free VLAN entry */
+ for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
+ vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
+ if (!(FIELD_GET(A5PSW_VLAN_RES_PORTMASK, vlan_res))) {
+ vlan_res = FIELD_PREP(A5PSW_VLAN_RES_VLANID, newvid);
+ a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(i), vlan_res);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void a5psw_port_vlan_tagged_cfg(struct a5psw *a5psw,
+ unsigned int vlan_res_id, int port,
+ bool set)
+{
+ u32 mask = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_RD_TAGMASK |
+ BIT(port);
+ u32 vlan_res_off = A5PSW_VLAN_RES(vlan_res_id);
+ u32 val = A5PSW_VLAN_RES_WR_TAGMASK, reg;
+
+ if (set)
+ val |= BIT(port);
+
+ /* Toggle tag mask read */
+ a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
+ reg = a5psw_reg_readl(a5psw, vlan_res_off);
+ a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
+
+ reg &= ~mask;
+ reg |= val;
+ a5psw_reg_writel(a5psw, vlan_res_off, reg);
+}
+
+static void a5psw_port_vlan_cfg(struct a5psw *a5psw, unsigned int vlan_res_id,
+ int port, bool set)
+{
+ u32 mask = A5PSW_VLAN_RES_WR_TAGMASK | BIT(port);
+ u32 reg = A5PSW_VLAN_RES_WR_PORTMASK;
+
+ if (set)
+ reg |= BIT(port);
+
+ a5psw_reg_rmw(a5psw, A5PSW_VLAN_RES(vlan_res_id), mask, reg);
+}
+
+static int a5psw_port_vlan_add(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct netlink_ext_ack *extack)
+{
+ bool tagged = !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+ struct a5psw *a5psw = ds->priv;
+ u16 vid = vlan->vid;
+ int vlan_res_id;
+
+ vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
+ if (vlan_res_id < 0) {
+ vlan_res_id = a5psw_new_vlan_res_entry(a5psw, vid);
+ if (vlan_res_id < 0)
+ return -ENOSPC;
+ }
+
+ a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, true);
+ if (tagged)
+ a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, true);
+
+ /* Configure port to tag with corresponding VID, but do not enable it
+ * yet: wait for vlan filtering to be enabled to enable vlan port
+ * tagging
+ */
+ if (pvid)
+ a5psw_reg_writel(a5psw, A5PSW_SYSTEM_TAGINFO(port), vid);
+
+ return 0;
+}
+
+static int a5psw_port_vlan_del(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ struct a5psw *a5psw = ds->priv;
+ u16 vid = vlan->vid;
+ int vlan_res_id;
+
+ vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
+ if (vlan_res_id < 0)
+ return -EINVAL;
+
+ a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, false);
+ a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, false);
+
+ return 0;
+}
+
static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port)
{
u32 reg_lo, reg_hi;
@@ -702,6 +890,27 @@ static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
ctrl_stats->MACControlFramesReceived = stat;
}
+static void a5psw_vlan_setup(struct a5psw *a5psw, int port)
+{
+ u32 reg;
+
+ /* Enable TAG always mode for the port, this is actually controlled
+ * by VLAN_IN_MODE_ENA field which will be used for PVID insertion
+ */
+ reg = A5PSW_VLAN_IN_MODE_TAG_ALWAYS;
+ reg <<= A5PSW_VLAN_IN_MODE_PORT_SHIFT(port);
+ a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE, A5PSW_VLAN_IN_MODE_PORT(port),
+ reg);
+
+ /* Set transparent mode for output frame manipulation, this will depend
+ * on the VLAN_RES configuration mode
+ */
+ reg = A5PSW_VLAN_OUT_MODE_TRANSPARENT;
+ reg <<= A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port);
+ a5psw_reg_rmw(a5psw, A5PSW_VLAN_OUT_MODE,
+ A5PSW_VLAN_OUT_MODE_PORT(port), reg);
+}
+
static int a5psw_setup(struct dsa_switch *ds)
{
struct a5psw *a5psw = ds->priv;
@@ -776,6 +985,8 @@ static int a5psw_setup(struct dsa_switch *ds)
/* Enable standalone mode for user ports */
if (dsa_port_is_user(dp))
a5psw_port_set_standalone(a5psw, port, true);
+
+ a5psw_vlan_setup(a5psw, port);
}
return 0;
@@ -801,8 +1012,13 @@ static const struct dsa_switch_ops a5psw_switch_ops = {
.set_ageing_time = a5psw_set_ageing_time,
.port_bridge_join = a5psw_port_bridge_join,
.port_bridge_leave = a5psw_port_bridge_leave,
+ .port_pre_bridge_flags = a5psw_port_pre_bridge_flags,
+ .port_bridge_flags = a5psw_port_bridge_flags,
.port_stp_state_set = a5psw_port_stp_state_set,
.port_fast_age = a5psw_port_fast_age,
+ .port_vlan_filtering = a5psw_port_vlan_filtering,
+ .port_vlan_add = a5psw_port_vlan_add,
+ .port_vlan_del = a5psw_port_vlan_del,
.port_fdb_add = a5psw_port_fdb_add,
.port_fdb_del = a5psw_port_fdb_del,
.port_fdb_dump = a5psw_port_fdb_dump,
@@ -992,6 +1208,8 @@ static int a5psw_probe(struct platform_device *pdev)
if (IS_ERR(a5psw->base))
return PTR_ERR(a5psw->base);
+ a5psw->bridged_ports = BIT(A5PSW_CPU_PORT);
+
ret = a5psw_pcs_get(a5psw);
if (ret)
return ret;
@@ -1090,7 +1308,7 @@ MODULE_DEVICE_TABLE(of, a5psw_of_mtable);
static struct platform_driver a5psw_driver = {
.driver = {
.name = "rzn1_a5psw",
- .of_match_table = of_match_ptr(a5psw_of_mtable),
+ .of_match_table = a5psw_of_mtable,
},
.probe = a5psw_probe,
.remove = a5psw_remove,
diff --git a/drivers/net/dsa/rzn1_a5psw.h b/drivers/net/dsa/rzn1_a5psw.h
index b869192eef3f..d54acedac194 100644
--- a/drivers/net/dsa/rzn1_a5psw.h
+++ b/drivers/net/dsa/rzn1_a5psw.h
@@ -51,7 +51,9 @@
#define A5PSW_VLAN_IN_MODE_TAG_ALWAYS 0x2
#define A5PSW_VLAN_OUT_MODE 0x2C
-#define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << ((port) * 2))
+#define A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port) ((port) * 2)
+#define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << \
+ A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port))
#define A5PSW_VLAN_OUT_MODE_DIS 0x0
#define A5PSW_VLAN_OUT_MODE_STRIP 0x1
#define A5PSW_VLAN_OUT_MODE_TAG_THROUGH 0x2
@@ -60,7 +62,7 @@
#define A5PSW_VLAN_IN_MODE_ENA 0x30
#define A5PSW_VLAN_TAG_ID 0x34
-#define A5PSW_SYSTEM_TAGINFO(port) (0x200 + A5PSW_PORT_OFFSET(port))
+#define A5PSW_SYSTEM_TAGINFO(port) (0x200 + 4 * (port))
#define A5PSW_AUTH_PORT(port) (0x240 + 4 * (port))
#define A5PSW_AUTH_PORT_AUTHORIZED BIT(0)
@@ -69,7 +71,7 @@
#define A5PSW_VLAN_RES_WR_PORTMASK BIT(30)
#define A5PSW_VLAN_RES_WR_TAGMASK BIT(29)
#define A5PSW_VLAN_RES_RD_TAGMASK BIT(28)
-#define A5PSW_VLAN_RES_ID GENMASK(16, 5)
+#define A5PSW_VLAN_RES_VLANID GENMASK(16, 5)
#define A5PSW_VLAN_RES_PORTMASK GENMASK(4, 0)
#define A5PSW_RXMATCH_CONFIG(port) (0x3e80 + 4 * (port))
diff --git a/drivers/net/dsa/sja1105/sja1105_flower.c b/drivers/net/dsa/sja1105/sja1105_flower.c
index fad5afe3819c..9e8ca182c722 100644
--- a/drivers/net/dsa/sja1105/sja1105_flower.c
+++ b/drivers/net/dsa/sja1105/sja1105_flower.c
@@ -205,10 +205,10 @@ static int sja1105_flower_parse_key(struct sja1105_private *priv,
u16 pcp = U16_MAX;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported keys used");
return -EOPNOTSUPP;
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 3529a565b4aa..331bb1c6676a 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
-#include <linux/of_device.h>
#include <linux/pcs/pcs-xpcs.h>
#include <linux/netdev_features.h>
#include <linux/netdevice.h>
@@ -1396,12 +1395,6 @@ static void sja1105_phylink_get_caps(struct dsa_switch *ds, int port,
struct sja1105_xmii_params_entry *mii;
phy_interface_t phy_mode;
- /* This driver does not make use of the speed, duplex, pause or the
- * advertisement in its mac_config, so it is safe to mark this driver
- * as non-legacy.
- */
- config->legacy_pre_march2020 = false;
-
phy_mode = priv->phy_mode[port];
if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
phy_mode == PHY_INTERFACE_MODE_2500BASEX) {
diff --git a/drivers/net/dsa/vitesse-vsc73xx-core.c b/drivers/net/dsa/vitesse-vsc73xx-core.c
index ef1a4a7c47b2..4f09e7438f3b 100644
--- a/drivers/net/dsa/vitesse-vsc73xx-core.c
+++ b/drivers/net/dsa/vitesse-vsc73xx-core.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/bitops.h>
#include <linux/if_bridge.h>
diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c
index fa622639d640..753fef757f11 100644
--- a/drivers/net/dsa/xrs700x/xrs700x.c
+++ b/drivers/net/dsa/xrs700x/xrs700x.c
@@ -7,7 +7,7 @@
#include <net/dsa.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/netdev_features.h>
#include <linux/if_hsr.h>
#include "xrs700x.h"
diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c
index 2c6bd36d2f31..65f56a98c0a0 100644
--- a/drivers/net/ethernet/8390/ne2k-pci.c
+++ b/drivers/net/ethernet/8390/ne2k-pci.c
@@ -731,18 +731,4 @@ static struct pci_driver ne2k_driver = {
.id_table = ne2k_pci_tbl,
.driver.pm = &ne2k_pci_pm_ops,
};
-
-
-static int __init ne2k_pci_init(void)
-{
- return pci_register_driver(&ne2k_driver);
-}
-
-
-static void __exit ne2k_pci_cleanup(void)
-{
- pci_unregister_driver(&ne2k_driver);
-}
-
-module_init(ne2k_pci_init);
-module_exit(ne2k_pci_cleanup);
+module_pci_driver(ne2k_driver);
diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c
index f5c2d7a9abc1..1c009b485188 100644
--- a/drivers/net/ethernet/adi/adin1110.c
+++ b/drivers/net/ethernet/adi/adin1110.c
@@ -739,7 +739,7 @@ static int adin1110_broadcasts_filter(struct adin1110_port_priv *port_priv,
u32 port_rules = 0;
u8 mask[ETH_ALEN];
- memset(mask, 0xFF, ETH_ALEN);
+ eth_broadcast_addr(mask);
if (accept_broadcast && port_priv->state == BR_STATE_FORWARDING)
port_rules = adin1110_port_rules(port_priv, true, true);
@@ -760,7 +760,7 @@ static int adin1110_set_mac_address(struct net_device *netdev,
return -EADDRNOTAVAIL;
eth_hw_addr_set(netdev, dev_addr);
- memset(mask, 0xFF, ETH_ALEN);
+ eth_broadcast_addr(mask);
mac_slot = (!port_priv->nr) ? ADIN_MAC_P1_ADDR_SLOT : ADIN_MAC_P2_ADDR_SLOT;
port_rules = adin1110_port_rules(port_priv, true, false);
@@ -1271,7 +1271,7 @@ static int adin1110_port_set_blocking_state(struct adin1110_port_priv *port_priv
goto out;
/* Allow only BPDUs to be passed to the CPU */
- memset(mask, 0xFF, ETH_ALEN);
+ eth_broadcast_addr(mask);
port_rules = adin1110_port_rules(port_priv, true, false);
ret = adin1110_write_mac_address(port_priv, mac_slot, mac,
mask, port_rules);
@@ -1386,7 +1386,7 @@ static int adin1110_fdb_add(struct adin1110_port_priv *port_priv,
other_port = priv->ports[!port_priv->nr];
port_rules = adin1110_port_rules(port_priv, false, true);
- memset(mask, 0xFF, ETH_ALEN);
+ eth_broadcast_addr(mask);
return adin1110_write_mac_address(other_port, mac_nr, (u8 *)fdb->addr,
mask, port_rules);
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index aa0d2f3aaeaa..597a02c75d52 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -29,9 +29,9 @@
#include <linux/io.h>
#include <linux/crc32.h>
#include <linux/mii.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c
index 5fab589b3ddf..3d9220f9c9fe 100644
--- a/drivers/net/ethernet/agere/et131x.c
+++ b/drivers/net/ethernet/agere/et131x.c
@@ -3982,8 +3982,7 @@ static int et131x_pci_setup(struct pci_dev *pdev,
}
adapter->mii_bus->name = "et131x_eth_mii";
- snprintf(adapter->mii_bus->id, MII_BUS_ID_SIZE, "%x",
- (adapter->pdev->bus->number << 8) | adapter->pdev->devfn);
+ snprintf(adapter->mii_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(adapter->pdev));
adapter->mii_bus->priv = netdev;
adapter->mii_bus->read = et131x_mdio_read;
adapter->mii_bus->write = et131x_mdio_write;
diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c
index a30d0f172986..78231c85234d 100644
--- a/drivers/net/ethernet/alacritech/slicoss.c
+++ b/drivers/net/ethernet/alacritech/slicoss.c
@@ -1520,10 +1520,8 @@ static void slic_get_ethtool_stats(struct net_device *dev,
static void slic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
- if (stringset == ETH_SS_STATS) {
+ if (stringset == ETH_SS_STATS)
memcpy(data, slic_stats_strings, sizeof(slic_stats_strings));
- data += sizeof(slic_stats_strings);
- }
}
static void slic_get_drvinfo(struct net_device *dev,
diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig
index 17985319088c..4ef819a9a1ad 100644
--- a/drivers/net/ethernet/altera/Kconfig
+++ b/drivers/net/ethernet/altera/Kconfig
@@ -2,6 +2,7 @@
config ALTERA_TSE
tristate "Altera Triple-Speed Ethernet MAC support"
depends on HAS_DMA
+ depends on HAS_IOMEM
select PHYLIB
select PHYLINK
select PCS_LYNX
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index d19593fae226..ad32ca81f7ef 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -3267,7 +3267,7 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pd
host_info = ena_dev->host_attr.host_info;
- host_info->bdf = (pdev->bus->number << 8) | pdev->devfn;
+ host_info->bdf = pci_dev_id(pdev);
host_info->os_type = ENA_ADMIN_OS_LINUX;
host_info->kernel_ver = LINUX_VERSION_CODE;
strscpy(host_info->kernel_ver_str, utsname()->version,
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index 248b715b4d68..33c923e1261a 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+#include <net/xdp.h>
#include <uapi/linux/bpf.h>
#include "ena_com.h"
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index ec704222925d..751454d305c6 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -367,7 +367,7 @@ static void *slow_memcpy( void *dst, const void *src, size_t len )
}
-struct net_device * __init atarilance_probe(void)
+static struct net_device * __init atarilance_probe(void)
{
int i;
static int found;
diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
index 561af8e5b3ea..6787a5fae908 100644
--- a/drivers/net/ethernet/amd/pds_core/auxbus.c
+++ b/drivers/net/ethernet/amd/pds_core/auxbus.c
@@ -11,7 +11,7 @@
* @pf_pdev: ptr to the PF driver struct
* @devname: name that includes service into, e.g. pds_core.vDPA
*
- * Return: 0 on success, or
+ * Return: positive client ID (ci) on success, or
* negative for error
*/
int pds_client_register(struct pci_dev *pf_pdev, char *devname)
diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
index f2c79456d745..36f9b932b9e2 100644
--- a/drivers/net/ethernet/amd/pds_core/core.c
+++ b/drivers/net/ethernet/amd/pds_core/core.c
@@ -464,7 +464,8 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
{
int i;
- pdsc_devcmd_reset(pdsc);
+ if (!pdsc->pdev->is_virtfn)
+ pdsc_devcmd_reset(pdsc);
pdsc_qcq_free(pdsc, &pdsc->notifyqcq);
pdsc_qcq_free(pdsc, &pdsc->adminqcq);
@@ -524,7 +525,8 @@ static void pdsc_fw_down(struct pdsc *pdsc)
}
/* Notify clients of fw_down */
- devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc);
+ if (pdsc->fw_reporter)
+ devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc);
pdsc_notify(PDS_EVENT_RESET, &reset_event);
pdsc_stop(pdsc);
@@ -554,8 +556,9 @@ static void pdsc_fw_up(struct pdsc *pdsc)
/* Notify clients of fw_up */
pdsc->fw_recoveries++;
- devlink_health_reporter_state_update(pdsc->fw_reporter,
- DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
+ if (pdsc->fw_reporter)
+ devlink_health_reporter_state_update(pdsc->fw_reporter,
+ DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
pdsc_notify(PDS_EVENT_RESET, &reset_event);
return;
diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c
index debe5216fe29..f77cd9f5a2fd 100644
--- a/drivers/net/ethernet/amd/pds_core/dev.c
+++ b/drivers/net/ethernet/amd/pds_core/dev.c
@@ -121,7 +121,7 @@ static const char *pdsc_devcmd_str(int opcode)
}
}
-static int pdsc_devcmd_wait(struct pdsc *pdsc, int max_seconds)
+static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
{
struct device *dev = pdsc->dev;
unsigned long start_time;
@@ -131,9 +131,6 @@ static int pdsc_devcmd_wait(struct pdsc *pdsc, int max_seconds)
int done = 0;
int err = 0;
int status;
- int opcode;
-
- opcode = ioread8(&pdsc->cmd_regs->cmd.opcode);
start_time = jiffies;
max_wait = start_time + (max_seconds * HZ);
@@ -180,10 +177,10 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd));
pdsc_devcmd_dbell(pdsc);
- err = pdsc_devcmd_wait(pdsc, max_seconds);
+ err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds);
memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
- if (err == -ENXIO || err == -ETIMEDOUT)
+ if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq)
queue_work(pdsc->wq, &pdsc->health_work);
return err;
diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
index 9c6b3653c1c7..d9607033bbf2 100644
--- a/drivers/net/ethernet/amd/pds_core/devlink.c
+++ b/drivers/net/ethernet/amd/pds_core/devlink.c
@@ -10,6 +10,9 @@ pdsc_viftype *pdsc_dl_find_viftype_by_id(struct pdsc *pdsc,
{
int vt;
+ if (!pdsc->viftype_status)
+ return NULL;
+
for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) {
if (pdsc->viftype_status[vt].dl_id == dl_id)
return &pdsc->viftype_status[vt];
diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
index 672757932246..3a45bf474a19 100644
--- a/drivers/net/ethernet/amd/pds_core/main.c
+++ b/drivers/net/ethernet/amd/pds_core/main.c
@@ -367,14 +367,13 @@ static int pdsc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pdsc_init_vf(pdsc);
if (err) {
dev_err(dev, "Cannot init device: %pe\n", ERR_PTR(err));
- goto err_out_clear_master;
+ goto err_out_disable_device;
}
clear_bit(PDSC_S_INITING_DRIVER, &pdsc->state);
return 0;
-err_out_clear_master:
- pci_clear_master(pdev);
+err_out_disable_device:
pci_disable_device(pdev);
err_out_free_ida:
ida_free(&pdsc_ida, pdsc->uid);
@@ -439,7 +438,6 @@ static void pdsc_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
}
- pci_clear_master(pdev);
pci_disable_device(pdev);
ida_free(&pdsc_ida, pdsc->uid);
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index 68ca1225eedc..33bb539ad70a 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -92,7 +92,7 @@ static char lancestr[] = "LANCE";
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/gfp.h>
#include <linux/pgtable.h>
diff --git a/drivers/net/ethernet/apm/xgene-v2/main.h b/drivers/net/ethernet/apm/xgene-v2/main.h
index b3985a7be59d..7be6f83e22fe 100644
--- a/drivers/net/ethernet/apm/xgene-v2/main.h
+++ b/drivers/net/ethernet/apm/xgene-v2/main.h
@@ -22,6 +22,7 @@
#include <linux/of_mdio.h>
#include <linux/prefetch.h>
#include <linux/phy.h>
+#include <linux/platform_device.h>
#include <net/ip.h>
#include "mac.h"
#include "enet.h"
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 390671640388..4d4140b7c450 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -1632,7 +1632,7 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
for (i = 0; i < max_irqs; i++) {
ret = platform_get_irq(pdev, i);
- if (ret <= 0) {
+ if (ret < 0) {
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
max_irqs = i;
pdata->rxq_cnt = max_irqs / 2;
@@ -1640,7 +1640,7 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
pdata->cq_cnt = max_irqs / 2;
break;
}
- return ret ? : -ENXIO;
+ return ret;
}
pdata->irqs[i] = ret;
}
@@ -2041,7 +2041,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
of_id = of_match_device(xgene_enet_of_match, &pdev->dev);
if (of_id) {
- pdata->enet_id = (enum xgene_enet_id)of_id->data;
+ pdata->enet_id = (uintptr_t)of_id->data;
}
#ifdef CONFIG_ACPI
else {
diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c
index 8fcaf1639920..8775c3234e91 100644
--- a/drivers/net/ethernet/apple/macmace.c
+++ b/drivers/net/ethernet/apple/macmace.c
@@ -77,7 +77,7 @@ struct mace_frame {
u8 pad4;
u32 pad5;
u32 pad6;
- u8 data[1];
+ DECLARE_FLEX_ARRAY(u8, data);
/* And frame continues.. */
};
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
index 5dfc751572ed..220400a633f5 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c
@@ -93,7 +93,7 @@ static u32 hw_atl2_sem_act_rslvr_get(struct aq_hw_s *self)
static int hw_atl2_hw_reset(struct aq_hw_s *self)
{
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
+ struct hw_atl2_priv *priv = self->priv;
int err;
err = hw_atl2_utils_soft_reset(self);
@@ -378,8 +378,8 @@ static int hw_atl2_hw_init_tx_path(struct aq_hw_s *self)
static void hw_atl2_hw_init_new_rx_filters(struct aq_hw_s *self)
{
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
u8 *prio_tc_map = self->aq_nic_cfg->prio_tc_map;
+ struct hw_atl2_priv *priv = self->priv;
u16 action;
u8 index;
int i;
@@ -433,7 +433,7 @@ static void hw_atl2_hw_new_rx_filter_vlan_promisc(struct aq_hw_s *self,
u16 off_action = (!promisc &&
!hw_atl_rpfl2promiscuous_mode_en_get(self)) ?
HW_ATL2_ACTION_DROP : HW_ATL2_ACTION_DISABLE;
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
+ struct hw_atl2_priv *priv = self->priv;
u8 index;
index = priv->art_base_index + HW_ATL2_RPF_VLAN_PROMISC_OFF_INDEX;
@@ -445,7 +445,7 @@ static void hw_atl2_hw_new_rx_filter_vlan_promisc(struct aq_hw_s *self,
static void hw_atl2_hw_new_rx_filter_promisc(struct aq_hw_s *self, bool promisc)
{
u16 off_action = promisc ? HW_ATL2_ACTION_DISABLE : HW_ATL2_ACTION_DROP;
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
+ struct hw_atl2_priv *priv = self->priv;
bool vlan_promisc_enable;
u8 index;
@@ -539,8 +539,8 @@ static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr)
[AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U },
};
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg;
+ struct hw_atl2_priv *priv = self->priv;
u8 base_index, count;
int err;
@@ -770,7 +770,7 @@ static struct aq_stats_s *hw_atl2_utils_get_hw_stats(struct aq_hw_s *self)
static int hw_atl2_hw_vlan_set(struct aq_hw_s *self,
struct aq_rx_filter_vlan *aq_vlans)
{
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
+ struct hw_atl2_priv *priv = self->priv;
u32 queue;
u8 index;
int i;
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
index 674683b54304..52e2070a4a2f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
@@ -413,8 +413,8 @@ do { \
static int aq_a2_fw_update_stats(struct aq_hw_s *self)
{
- struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
struct aq_stats_s *cs = &self->curr_stats;
+ struct hw_atl2_priv *priv = self->priv;
struct statistics_s stats;
struct version_s version;
int err;
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 2b427d8a1831..31ee477dd131 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -15,11 +15,11 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
#include "emac.h"
diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c
index ff1a5edf8df1..009e0b3066fa 100644
--- a/drivers/net/ethernet/atheros/ag71xx.c
+++ b/drivers/net/ethernet/atheros/ag71xx.c
@@ -29,9 +29,10 @@
#include <linux/if_vlan.h>
#include <linux/mfd/syscon.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/phylink.h>
#include <linux/regmap.h>
#include <linux/reset.h>
diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c
index b716adacd815..7f6b69a52367 100644
--- a/drivers/net/ethernet/atheros/alx/ethtool.c
+++ b/drivers/net/ethernet/atheros/alx/ethtool.c
@@ -292,9 +292,8 @@ static void alx_get_ethtool_stats(struct net_device *netdev,
spin_lock(&alx->stats_lock);
alx_update_hw_stats(hw);
- BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) <
- ALX_NUM_STATS * sizeof(u64));
- memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64));
+ BUILD_BUG_ON(sizeof(hw->stats) != ALX_NUM_STATS * sizeof(u64));
+ memcpy(data, &hw->stats, sizeof(hw->stats));
spin_unlock(&alx->stats_lock);
}
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 948586bf1b5b..75ca3ddda1f5 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -255,4 +255,16 @@ config BNXT_HWMON
Say Y if you want to expose the thermal sensor data on NetXtreme-C/E
devices, via the hwmon sysfs interface.
+config BCMASP
+ tristate "Broadcom ASP 2.0 Ethernet support"
+ depends on ARCH_BRCMSTB || COMPILE_TEST
+ default ARCH_BRCMSTB
+ depends on OF
+ select MII
+ select PHYLIB
+ select MDIO_BCM_UNIMAC
+ help
+ This configuration enables the Broadcom ASP 2.0 Ethernet controller
+ driver which is present in Broadcom STB SoCs such as 72165.
+
endif # NET_VENDOR_BROADCOM
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 0ddfb5b5d53c..bac5cb6ad0cd 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_BGMAC_BCMA) += bgmac-bcma.o bgmac-bcma-mdio.o
obj-$(CONFIG_BGMAC_PLATFORM) += bgmac-platform.o
obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
obj-$(CONFIG_BNXT) += bnxt/
+obj-$(CONFIG_BCMASP) += asp2/
diff --git a/drivers/net/ethernet/broadcom/asp2/Makefile b/drivers/net/ethernet/broadcom/asp2/Makefile
new file mode 100644
index 000000000000..e07550315f83
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BCMASP) += bcm-asp.o
+bcm-asp-objs := bcmasp.o bcmasp_intf.o bcmasp_ethtool.o
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
new file mode 100644
index 000000000000..d63d321f3e7b
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
@@ -0,0 +1,1437 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Broadcom STB ASP 2.0 Driver
+ *
+ * Copyright (c) 2023 Broadcom
+ */
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+
+#include "bcmasp.h"
+#include "bcmasp_intf_defs.h"
+
+static void _intr2_mask_clear(struct bcmasp_priv *priv, u32 mask)
+{
+ intr2_core_wl(priv, mask, ASP_INTR2_MASK_CLEAR);
+ priv->irq_mask &= ~mask;
+}
+
+static void _intr2_mask_set(struct bcmasp_priv *priv, u32 mask)
+{
+ intr2_core_wl(priv, mask, ASP_INTR2_MASK_SET);
+ priv->irq_mask |= mask;
+}
+
+void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en)
+{
+ struct bcmasp_priv *priv = intf->parent;
+
+ if (en)
+ _intr2_mask_clear(priv, ASP_INTR2_TX_DESC(intf->channel));
+ else
+ _intr2_mask_set(priv, ASP_INTR2_TX_DESC(intf->channel));
+}
+EXPORT_SYMBOL_GPL(bcmasp_enable_tx_irq);
+
+void bcmasp_enable_rx_irq(struct bcmasp_intf *intf, int en)
+{
+ struct bcmasp_priv *priv = intf->parent;
+
+ if (en)
+ _intr2_mask_clear(priv, ASP_INTR2_RX_ECH(intf->channel));
+ else
+ _intr2_mask_set(priv, ASP_INTR2_RX_ECH(intf->channel));
+}
+EXPORT_SYMBOL_GPL(bcmasp_enable_rx_irq);
+
+static void bcmasp_intr2_mask_set_all(struct bcmasp_priv *priv)
+{
+ _intr2_mask_set(priv, 0xffffffff);
+ priv->irq_mask = 0xffffffff;
+}
+
+static void bcmasp_intr2_clear_all(struct bcmasp_priv *priv)
+{
+ intr2_core_wl(priv, 0xffffffff, ASP_INTR2_CLEAR);
+}
+
+static void bcmasp_intr2_handling(struct bcmasp_intf *intf, u32 status)
+{
+ if (status & ASP_INTR2_RX_ECH(intf->channel)) {
+ if (likely(napi_schedule_prep(&intf->rx_napi))) {
+ bcmasp_enable_rx_irq(intf, 0);
+ __napi_schedule_irqoff(&intf->rx_napi);
+ }
+ }
+
+ if (status & ASP_INTR2_TX_DESC(intf->channel)) {
+ if (likely(napi_schedule_prep(&intf->tx_napi))) {
+ bcmasp_enable_tx_irq(intf, 0);
+ __napi_schedule_irqoff(&intf->tx_napi);
+ }
+ }
+}
+
+static irqreturn_t bcmasp_isr(int irq, void *data)
+{
+ struct bcmasp_priv *priv = data;
+ struct bcmasp_intf *intf;
+ u32 status;
+
+ status = intr2_core_rl(priv, ASP_INTR2_STATUS) &
+ ~intr2_core_rl(priv, ASP_INTR2_MASK_STATUS);
+
+ intr2_core_wl(priv, status, ASP_INTR2_CLEAR);
+
+ if (unlikely(status == 0)) {
+ dev_warn(&priv->pdev->dev, "l2 spurious interrupt\n");
+ return IRQ_NONE;
+ }
+
+ /* Handle intferfaces */
+ list_for_each_entry(intf, &priv->intfs, list)
+ bcmasp_intr2_handling(intf, status);
+
+ return IRQ_HANDLED;
+}
+
+void bcmasp_flush_rx_port(struct bcmasp_intf *intf)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ u32 mask;
+
+ switch (intf->port) {
+ case 0:
+ mask = ASP_CTRL_UMAC0_FLUSH_MASK;
+ break;
+ case 1:
+ mask = ASP_CTRL_UMAC1_FLUSH_MASK;
+ break;
+ case 2:
+ mask = ASP_CTRL_SPB_FLUSH_MASK;
+ break;
+ default:
+ /* Not valid port */
+ return;
+ }
+
+ rx_ctrl_core_wl(priv, mask, priv->hw_info->rx_ctrl_flush);
+}
+
+static void bcmasp_netfilt_hw_en_wake(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt)
+{
+ rx_filter_core_wl(priv, ASP_RX_FILTER_NET_OFFSET_L3_1(64),
+ ASP_RX_FILTER_NET_OFFSET(nfilt->hw_index));
+
+ rx_filter_core_wl(priv, ASP_RX_FILTER_NET_OFFSET_L2(32) |
+ ASP_RX_FILTER_NET_OFFSET_L3_0(32) |
+ ASP_RX_FILTER_NET_OFFSET_L3_1(96) |
+ ASP_RX_FILTER_NET_OFFSET_L4(32),
+ ASP_RX_FILTER_NET_OFFSET(nfilt->hw_index + 1));
+
+ rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->port + 8) |
+ ASP_RX_FILTER_NET_CFG_EN |
+ ASP_RX_FILTER_NET_CFG_L2_EN |
+ ASP_RX_FILTER_NET_CFG_L3_EN |
+ ASP_RX_FILTER_NET_CFG_L4_EN |
+ ASP_RX_FILTER_NET_CFG_L3_FRM(2) |
+ ASP_RX_FILTER_NET_CFG_L4_FRM(2) |
+ ASP_RX_FILTER_NET_CFG_UMC(nfilt->port),
+ ASP_RX_FILTER_NET_CFG(nfilt->hw_index));
+
+ rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->port + 8) |
+ ASP_RX_FILTER_NET_CFG_EN |
+ ASP_RX_FILTER_NET_CFG_L2_EN |
+ ASP_RX_FILTER_NET_CFG_L3_EN |
+ ASP_RX_FILTER_NET_CFG_L4_EN |
+ ASP_RX_FILTER_NET_CFG_L3_FRM(2) |
+ ASP_RX_FILTER_NET_CFG_L4_FRM(2) |
+ ASP_RX_FILTER_NET_CFG_UMC(nfilt->port),
+ ASP_RX_FILTER_NET_CFG(nfilt->hw_index + 1));
+}
+
+#define MAX_WAKE_FILTER_SIZE 256
+enum asp_netfilt_reg_type {
+ ASP_NETFILT_MATCH = 0,
+ ASP_NETFILT_MASK,
+ ASP_NETFILT_MAX
+};
+
+static int bcmasp_netfilt_get_reg_offset(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ enum asp_netfilt_reg_type reg_type,
+ u32 offset)
+{
+ u32 block_index, filter_sel;
+
+ if (offset < 32) {
+ block_index = ASP_RX_FILTER_NET_L2;
+ filter_sel = nfilt->hw_index;
+ } else if (offset < 64) {
+ block_index = ASP_RX_FILTER_NET_L2;
+ filter_sel = nfilt->hw_index + 1;
+ } else if (offset < 96) {
+ block_index = ASP_RX_FILTER_NET_L3_0;
+ filter_sel = nfilt->hw_index;
+ } else if (offset < 128) {
+ block_index = ASP_RX_FILTER_NET_L3_0;
+ filter_sel = nfilt->hw_index + 1;
+ } else if (offset < 160) {
+ block_index = ASP_RX_FILTER_NET_L3_1;
+ filter_sel = nfilt->hw_index;
+ } else if (offset < 192) {
+ block_index = ASP_RX_FILTER_NET_L3_1;
+ filter_sel = nfilt->hw_index + 1;
+ } else if (offset < 224) {
+ block_index = ASP_RX_FILTER_NET_L4;
+ filter_sel = nfilt->hw_index;
+ } else if (offset < 256) {
+ block_index = ASP_RX_FILTER_NET_L4;
+ filter_sel = nfilt->hw_index + 1;
+ } else {
+ return -EINVAL;
+ }
+
+ switch (reg_type) {
+ case ASP_NETFILT_MATCH:
+ return ASP_RX_FILTER_NET_PAT(filter_sel, block_index,
+ (offset % 32));
+ case ASP_NETFILT_MASK:
+ return ASP_RX_FILTER_NET_MASK(filter_sel, block_index,
+ (offset % 32));
+ default:
+ return -EINVAL;
+ }
+}
+
+static void bcmasp_netfilt_wr(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ enum asp_netfilt_reg_type reg_type,
+ u32 val, u32 offset)
+{
+ int reg_offset;
+
+ /* HW only accepts 4 byte aligned writes */
+ if (!IS_ALIGNED(offset, 4) || offset > MAX_WAKE_FILTER_SIZE)
+ return;
+
+ reg_offset = bcmasp_netfilt_get_reg_offset(priv, nfilt, reg_type,
+ offset);
+
+ rx_filter_core_wl(priv, val, reg_offset);
+}
+
+static u32 bcmasp_netfilt_rd(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ enum asp_netfilt_reg_type reg_type,
+ u32 offset)
+{
+ int reg_offset;
+
+ /* HW only accepts 4 byte aligned writes */
+ if (!IS_ALIGNED(offset, 4) || offset > MAX_WAKE_FILTER_SIZE)
+ return 0;
+
+ reg_offset = bcmasp_netfilt_get_reg_offset(priv, nfilt, reg_type,
+ offset);
+
+ return rx_filter_core_rl(priv, reg_offset);
+}
+
+static int bcmasp_netfilt_wr_m_wake(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ u32 offset, void *match, void *mask,
+ size_t size)
+{
+ u32 shift, mask_val = 0, match_val = 0;
+ bool first_byte = true;
+
+ if ((offset + size) > MAX_WAKE_FILTER_SIZE)
+ return -EINVAL;
+
+ while (size--) {
+ /* The HW only accepts 4 byte aligned writes, so if we
+ * begin unaligned or if remaining bytes less than 4,
+ * we need to read then write to avoid losing current
+ * register state
+ */
+ if (first_byte && (!IS_ALIGNED(offset, 4) || size < 3)) {
+ match_val = bcmasp_netfilt_rd(priv, nfilt,
+ ASP_NETFILT_MATCH,
+ ALIGN_DOWN(offset, 4));
+ mask_val = bcmasp_netfilt_rd(priv, nfilt,
+ ASP_NETFILT_MASK,
+ ALIGN_DOWN(offset, 4));
+ }
+
+ shift = (3 - (offset % 4)) * 8;
+ match_val &= ~GENMASK(shift + 7, shift);
+ mask_val &= ~GENMASK(shift + 7, shift);
+ match_val |= (u32)(*((u8 *)match) << shift);
+ mask_val |= (u32)(*((u8 *)mask) << shift);
+
+ /* If last byte or last byte of word, write to reg */
+ if (!size || ((offset % 4) == 3)) {
+ bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MATCH,
+ match_val, ALIGN_DOWN(offset, 4));
+ bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MASK,
+ mask_val, ALIGN_DOWN(offset, 4));
+ first_byte = true;
+ } else {
+ first_byte = false;
+ }
+
+ offset++;
+ match++;
+ mask++;
+ }
+
+ return 0;
+}
+
+static void bcmasp_netfilt_reset_hw(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt)
+{
+ int i;
+
+ for (i = 0; i < MAX_WAKE_FILTER_SIZE; i += 4) {
+ bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MATCH, 0, i);
+ bcmasp_netfilt_wr(priv, nfilt, ASP_NETFILT_MASK, 0, i);
+ }
+}
+
+static void bcmasp_netfilt_tcpip4_wr(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ struct ethtool_tcpip4_spec *match,
+ struct ethtool_tcpip4_spec *mask,
+ u32 offset)
+{
+ __be16 val_16, mask_16;
+
+ val_16 = htons(ETH_P_IP);
+ mask_16 = htons(0xFFFF);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
+ &val_16, &mask_16, sizeof(val_16));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 1,
+ &match->tos, &mask->tos,
+ sizeof(match->tos));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 12,
+ &match->ip4src, &mask->ip4src,
+ sizeof(match->ip4src));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 16,
+ &match->ip4dst, &mask->ip4dst,
+ sizeof(match->ip4dst));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 20,
+ &match->psrc, &mask->psrc,
+ sizeof(match->psrc));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 22,
+ &match->pdst, &mask->pdst,
+ sizeof(match->pdst));
+}
+
+static void bcmasp_netfilt_tcpip6_wr(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt,
+ struct ethtool_tcpip6_spec *match,
+ struct ethtool_tcpip6_spec *mask,
+ u32 offset)
+{
+ __be16 val_16, mask_16;
+
+ val_16 = htons(ETH_P_IPV6);
+ mask_16 = htons(0xFFFF);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
+ &val_16, &mask_16, sizeof(val_16));
+ val_16 = htons(match->tclass << 4);
+ mask_16 = htons(mask->tclass << 4);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset,
+ &val_16, &mask_16, sizeof(val_16));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 8,
+ &match->ip6src, &mask->ip6src,
+ sizeof(match->ip6src));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 24,
+ &match->ip6dst, &mask->ip6dst,
+ sizeof(match->ip6dst));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 40,
+ &match->psrc, &mask->psrc,
+ sizeof(match->psrc));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 42,
+ &match->pdst, &mask->pdst,
+ sizeof(match->pdst));
+}
+
+static int bcmasp_netfilt_wr_to_hw(struct bcmasp_priv *priv,
+ struct bcmasp_net_filter *nfilt)
+{
+ struct ethtool_rx_flow_spec *fs = &nfilt->fs;
+ unsigned int offset = 0;
+ __be16 val_16, mask_16;
+ u8 val_8, mask_8;
+
+ /* Currently only supports wake filters */
+ if (!nfilt->wake_filter)
+ return -EINVAL;
+
+ bcmasp_netfilt_reset_hw(priv, nfilt);
+
+ if (fs->flow_type & FLOW_MAC_EXT) {
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, 0, &fs->h_ext.h_dest,
+ &fs->m_ext.h_dest,
+ sizeof(fs->h_ext.h_dest));
+ }
+
+ if ((fs->flow_type & FLOW_EXT) &&
+ (fs->m_ext.vlan_etype || fs->m_ext.vlan_tci)) {
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2),
+ &fs->h_ext.vlan_etype,
+ &fs->m_ext.vlan_etype,
+ sizeof(fs->h_ext.vlan_etype));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ((ETH_ALEN * 2) + 2),
+ &fs->h_ext.vlan_tci,
+ &fs->m_ext.vlan_tci,
+ sizeof(fs->h_ext.vlan_tci));
+ offset += VLAN_HLEN;
+ }
+
+ switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+ case ETHER_FLOW:
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, 0,
+ &fs->h_u.ether_spec.h_dest,
+ &fs->m_u.ether_spec.h_dest,
+ sizeof(fs->h_u.ether_spec.h_dest));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_ALEN,
+ &fs->h_u.ether_spec.h_source,
+ &fs->m_u.ether_spec.h_source,
+ sizeof(fs->h_u.ether_spec.h_source));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
+ &fs->h_u.ether_spec.h_proto,
+ &fs->m_u.ether_spec.h_proto,
+ sizeof(fs->h_u.ether_spec.h_proto));
+
+ break;
+ case IP_USER_FLOW:
+ val_16 = htons(ETH_P_IP);
+ mask_16 = htons(0xFFFF);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, (ETH_ALEN * 2) + offset,
+ &val_16, &mask_16, sizeof(val_16));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 1,
+ &fs->h_u.usr_ip4_spec.tos,
+ &fs->m_u.usr_ip4_spec.tos,
+ sizeof(fs->h_u.usr_ip4_spec.tos));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
+ &fs->h_u.usr_ip4_spec.proto,
+ &fs->m_u.usr_ip4_spec.proto,
+ sizeof(fs->h_u.usr_ip4_spec.proto));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 12,
+ &fs->h_u.usr_ip4_spec.ip4src,
+ &fs->m_u.usr_ip4_spec.ip4src,
+ sizeof(fs->h_u.usr_ip4_spec.ip4src));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 16,
+ &fs->h_u.usr_ip4_spec.ip4dst,
+ &fs->m_u.usr_ip4_spec.ip4dst,
+ sizeof(fs->h_u.usr_ip4_spec.ip4dst));
+ if (!fs->m_u.usr_ip4_spec.l4_4_bytes)
+ break;
+
+ /* Only supports 20 byte IPv4 header */
+ val_8 = 0x45;
+ mask_8 = 0xFF;
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset,
+ &val_8, &mask_8, sizeof(val_8));
+ bcmasp_netfilt_wr_m_wake(priv, nfilt,
+ ETH_HLEN + 20 + offset,
+ &fs->h_u.usr_ip4_spec.l4_4_bytes,
+ &fs->m_u.usr_ip4_spec.l4_4_bytes,
+ sizeof(fs->h_u.usr_ip4_spec.l4_4_bytes)
+ );
+ break;
+ case TCP_V4_FLOW:
+ val_8 = IPPROTO_TCP;
+ mask_8 = 0xFF;
+ bcmasp_netfilt_tcpip4_wr(priv, nfilt, &fs->h_u.tcp_ip4_spec,
+ &fs->m_u.tcp_ip4_spec, offset);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
+ &val_8, &mask_8, sizeof(val_8));
+ break;
+ case UDP_V4_FLOW:
+ val_8 = IPPROTO_UDP;
+ mask_8 = 0xFF;
+ bcmasp_netfilt_tcpip4_wr(priv, nfilt, &fs->h_u.udp_ip4_spec,
+ &fs->m_u.udp_ip4_spec, offset);
+
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 9,
+ &val_8, &mask_8, sizeof(val_8));
+ break;
+ case TCP_V6_FLOW:
+ val_8 = IPPROTO_TCP;
+ mask_8 = 0xFF;
+ bcmasp_netfilt_tcpip6_wr(priv, nfilt, &fs->h_u.tcp_ip6_spec,
+ &fs->m_u.tcp_ip6_spec, offset);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 6,
+ &val_8, &mask_8, sizeof(val_8));
+ break;
+ case UDP_V6_FLOW:
+ val_8 = IPPROTO_UDP;
+ mask_8 = 0xFF;
+ bcmasp_netfilt_tcpip6_wr(priv, nfilt, &fs->h_u.udp_ip6_spec,
+ &fs->m_u.udp_ip6_spec, offset);
+ bcmasp_netfilt_wr_m_wake(priv, nfilt, ETH_HLEN + offset + 6,
+ &val_8, &mask_8, sizeof(val_8));
+ break;
+ }
+
+ bcmasp_netfilt_hw_en_wake(priv, nfilt);
+
+ return 0;
+}
+
+void bcmasp_netfilt_suspend(struct bcmasp_intf *intf)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ bool write = false;
+ int ret, i;
+
+ /* Write all filters to HW */
+ for (i = 0; i < NUM_NET_FILTERS; i++) {
+ /* If the filter does not match the port, skip programming. */
+ if (!priv->net_filters[i].claimed ||
+ priv->net_filters[i].port != intf->port)
+ continue;
+
+ if (i > 0 && (i % 2) &&
+ priv->net_filters[i].wake_filter &&
+ priv->net_filters[i - 1].wake_filter)
+ continue;
+
+ ret = bcmasp_netfilt_wr_to_hw(priv, &priv->net_filters[i]);
+ if (!ret)
+ write = true;
+ }
+
+ /* Successfully programmed at least one wake filter
+ * so enable top level wake config
+ */
+ if (write)
+ rx_filter_core_wl(priv, (ASP_RX_FILTER_OPUT_EN |
+ ASP_RX_FILTER_LNR_MD |
+ ASP_RX_FILTER_GEN_WK_EN |
+ ASP_RX_FILTER_NT_FLT_EN),
+ ASP_RX_FILTER_BLK_CTRL);
+}
+
+void bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
+ u32 *rule_cnt)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ int j = 0, i;
+
+ for (i = 0; i < NUM_NET_FILTERS; i++) {
+ if (!priv->net_filters[i].claimed ||
+ priv->net_filters[i].port != intf->port)
+ continue;
+
+ if (i > 0 && (i % 2) &&
+ priv->net_filters[i].wake_filter &&
+ priv->net_filters[i - 1].wake_filter)
+ continue;
+
+ rule_locs[j++] = priv->net_filters[i].fs.location;
+ }
+
+ *rule_cnt = j;
+}
+
+int bcmasp_netfilt_get_active(struct bcmasp_intf *intf)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ int cnt = 0, i;
+
+ for (i = 0; i < NUM_NET_FILTERS; i++) {
+ if (!priv->net_filters[i].claimed ||
+ priv->net_filters[i].port != intf->port)
+ continue;
+
+ /* Skip over a wake filter pair */
+ if (i > 0 && (i % 2) &&
+ priv->net_filters[i].wake_filter &&
+ priv->net_filters[i - 1].wake_filter)
+ continue;
+
+ cnt++;
+ }
+
+ return cnt;
+}
+
+bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
+ struct ethtool_rx_flow_spec *fs)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ struct ethtool_rx_flow_spec *cur;
+ size_t fs_size = 0;
+ int i;
+
+ for (i = 0; i < NUM_NET_FILTERS; i++) {
+ if (!priv->net_filters[i].claimed ||
+ priv->net_filters[i].port != intf->port)
+ continue;
+
+ cur = &priv->net_filters[i].fs;
+
+ if (cur->flow_type != fs->flow_type ||
+ cur->ring_cookie != fs->ring_cookie)
+ continue;
+
+ switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+ case ETHER_FLOW:
+ fs_size = sizeof(struct ethhdr);
+ break;
+ case IP_USER_FLOW:
+ fs_size = sizeof(struct ethtool_usrip4_spec);
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ fs_size = sizeof(struct ethtool_tcpip6_spec);
+ break;
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ fs_size = sizeof(struct ethtool_tcpip4_spec);
+ break;
+ default:
+ continue;
+ }
+
+ if (memcmp(&cur->h_u, &fs->h_u, fs_size) ||
+ memcmp(&cur->m_u, &fs->m_u, fs_size))
+ continue;
+
+ if (cur->flow_type & FLOW_EXT) {
+ if (cur->h_ext.vlan_etype != fs->h_ext.vlan_etype ||
+ cur->m_ext.vlan_etype != fs->m_ext.vlan_etype ||
+ cur->h_ext.vlan_tci != fs->h_ext.vlan_tci ||
+ cur->m_ext.vlan_tci != fs->m_ext.vlan_tci ||
+ cur->h_ext.data[0] != fs->h_ext.data[0])
+ continue;
+ }
+ if (cur->flow_type & FLOW_MAC_EXT) {
+ if (memcmp(&cur->h_ext.h_dest,
+ &fs->h_ext.h_dest, ETH_ALEN) ||
+ memcmp(&cur->m_ext.h_dest,
+ &fs->m_ext.h_dest, ETH_ALEN))
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/* If no network filter found, return open filter.
+ * If no more open filters return NULL
+ */
+struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
+ u32 loc, bool wake_filter,
+ bool init)
+{
+ struct bcmasp_net_filter *nfilter = NULL;
+ struct bcmasp_priv *priv = intf->parent;
+ int i, open_index = -1;
+
+ /* Check whether we exceed the filter table capacity */
+ if (loc != RX_CLS_LOC_ANY && loc >= NUM_NET_FILTERS)
+ return ERR_PTR(-EINVAL);
+
+ /* If the filter location is busy (already claimed) and we are initializing
+ * the filter (insertion), return a busy error code.
+ */
+ if (loc != RX_CLS_LOC_ANY && init && priv->net_filters[loc].claimed)
+ return ERR_PTR(-EBUSY);
+
+ /* We need two filters for wake-up, so we cannot use an odd filter */
+ if (wake_filter && loc != RX_CLS_LOC_ANY && (loc % 2))
+ return ERR_PTR(-EINVAL);
+
+ /* Initialize the loop index based on the desired location or from 0 */
+ i = loc == RX_CLS_LOC_ANY ? 0 : loc;
+
+ for ( ; i < NUM_NET_FILTERS; i++) {
+ /* Found matching network filter */
+ if (!init &&
+ priv->net_filters[i].claimed &&
+ priv->net_filters[i].hw_index == i &&
+ priv->net_filters[i].port == intf->port)
+ return &priv->net_filters[i];
+
+ /* If we don't need a new filter or new filter already found */
+ if (!init || open_index >= 0)
+ continue;
+
+ /* Wake filter conslidates two filters to cover more bytes
+ * Wake filter is open if...
+ * 1. It is an even filter
+ * 2. The current and next filter is not claimed
+ */
+ if (wake_filter && !(i % 2) && !priv->net_filters[i].claimed &&
+ !priv->net_filters[i + 1].claimed)
+ open_index = i;
+ else if (!priv->net_filters[i].claimed)
+ open_index = i;
+ }
+
+ if (open_index >= 0) {
+ nfilter = &priv->net_filters[open_index];
+ nfilter->claimed = true;
+ nfilter->port = intf->port;
+ nfilter->hw_index = open_index;
+ }
+
+ if (wake_filter && open_index >= 0) {
+ /* Claim next filter */
+ priv->net_filters[open_index + 1].claimed = true;
+ priv->net_filters[open_index + 1].wake_filter = true;
+ nfilter->wake_filter = true;
+ }
+
+ return nfilter ? nfilter : ERR_PTR(-EINVAL);
+}
+
+void bcmasp_netfilt_release(struct bcmasp_intf *intf,
+ struct bcmasp_net_filter *nfilt)
+{
+ struct bcmasp_priv *priv = intf->parent;
+
+ if (nfilt->wake_filter) {
+ memset(&priv->net_filters[nfilt->hw_index + 1], 0,
+ sizeof(struct bcmasp_net_filter));
+ }
+
+ memset(nfilt, 0, sizeof(struct bcmasp_net_filter));
+}
+
+static void bcmasp_addr_to_uint(unsigned char *addr, u32 *high, u32 *low)
+{
+ *high = (u32)(addr[0] << 8 | addr[1]);
+ *low = (u32)(addr[2] << 24 | addr[3] << 16 | addr[4] << 8 |
+ addr[5]);
+}
+
+static void bcmasp_set_mda_filter(struct bcmasp_intf *intf,
+ const unsigned char *addr,
+ unsigned char *mask,
+ unsigned int i)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ u32 addr_h, addr_l, mask_h, mask_l;
+
+ /* Set local copy */
+ ether_addr_copy(priv->mda_filters[i].mask, mask);
+ ether_addr_copy(priv->mda_filters[i].addr, addr);
+
+ /* Write to HW */
+ bcmasp_addr_to_uint(priv->mda_filters[i].mask, &mask_h, &mask_l);
+ bcmasp_addr_to_uint(priv->mda_filters[i].addr, &addr_h, &addr_l);
+ rx_filter_core_wl(priv, addr_h, ASP_RX_FILTER_MDA_PAT_H(i));
+ rx_filter_core_wl(priv, addr_l, ASP_RX_FILTER_MDA_PAT_L(i));
+ rx_filter_core_wl(priv, mask_h, ASP_RX_FILTER_MDA_MSK_H(i));
+ rx_filter_core_wl(priv, mask_l, ASP_RX_FILTER_MDA_MSK_L(i));
+}
+
+static void bcmasp_en_mda_filter(struct bcmasp_intf *intf, bool en,
+ unsigned int i)
+{
+ struct bcmasp_priv *priv = intf->parent;
+
+ if (priv->mda_filters[i].en == en)
+ return;
+
+ priv->mda_filters[i].en = en;
+ priv->mda_filters[i].port = intf->port;
+
+ rx_filter_core_wl(priv, ((intf->channel + 8) |
+ (en << ASP_RX_FILTER_MDA_CFG_EN_SHIFT) |
+ ASP_RX_FILTER_MDA_CFG_UMC_SEL(intf->port)),
+ ASP_RX_FILTER_MDA_CFG(i));
+}
+
+/* There are 32 MDA filters shared between all ports, we reserve 4 filters per
+ * port for the following.
+ * - Promisc: Filter to allow all packets when promisc is enabled
+ * - All Multicast
+ * - Broadcast
+ * - Own address
+ *
+ * The reserved filters are identified as so.
+ * - Promisc: (index * 4) + 0
+ * - All Multicast: (index * 4) + 1
+ * - Broadcast: (index * 4) + 2
+ * - Own address: (index * 4) + 3
+ */
+enum asp_rx_filter_id {
+ ASP_RX_FILTER_MDA_PROMISC = 0,
+ ASP_RX_FILTER_MDA_ALLMULTI,
+ ASP_RX_FILTER_MDA_BROADCAST,
+ ASP_RX_FILTER_MDA_OWN_ADDR,
+ ASP_RX_FILTER_MDA_RES_MAX,
+};
+
+#define ASP_RX_FILT_MDA(intf, name) (((intf)->index * \
+ ASP_RX_FILTER_MDA_RES_MAX) \
+ + ASP_RX_FILTER_MDA_##name)
+
+static int bcmasp_total_res_mda_cnt(struct bcmasp_priv *priv)
+{
+ return list_count_nodes(&priv->intfs) * ASP_RX_FILTER_MDA_RES_MAX;
+}
+
+void bcmasp_set_promisc(struct bcmasp_intf *intf, bool en)
+{
+ unsigned int i = ASP_RX_FILT_MDA(intf, PROMISC);
+ unsigned char promisc[ETH_ALEN];
+
+ eth_zero_addr(promisc);
+ /* Set mask to 00:00:00:00:00:00 to match all packets */
+ bcmasp_set_mda_filter(intf, promisc, promisc, i);
+ bcmasp_en_mda_filter(intf, en, i);
+}
+
+void bcmasp_set_allmulti(struct bcmasp_intf *intf, bool en)
+{
+ unsigned char allmulti[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned int i = ASP_RX_FILT_MDA(intf, ALLMULTI);
+
+ /* Set mask to 01:00:00:00:00:00 to match all multicast */
+ bcmasp_set_mda_filter(intf, allmulti, allmulti, i);
+ bcmasp_en_mda_filter(intf, en, i);
+}
+
+void bcmasp_set_broad(struct bcmasp_intf *intf, bool en)
+{
+ unsigned int i = ASP_RX_FILT_MDA(intf, BROADCAST);
+ unsigned char addr[ETH_ALEN];
+
+ eth_broadcast_addr(addr);
+ bcmasp_set_mda_filter(intf, addr, addr, i);
+ bcmasp_en_mda_filter(intf, en, i);
+}
+
+void bcmasp_set_oaddr(struct bcmasp_intf *intf, const unsigned char *addr,
+ bool en)
+{
+ unsigned char mask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned int i = ASP_RX_FILT_MDA(intf, OWN_ADDR);
+
+ bcmasp_set_mda_filter(intf, addr, mask, i);
+ bcmasp_en_mda_filter(intf, en, i);
+}
+
+void bcmasp_disable_all_filters(struct bcmasp_intf *intf)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ unsigned int i;
+ int res_count;
+
+ res_count = bcmasp_total_res_mda_cnt(intf->parent);
+
+ /* Disable all filters held by this port */
+ for (i = res_count; i < NUM_MDA_FILTERS; i++) {
+ if (priv->mda_filters[i].en &&
+ priv->mda_filters[i].port == intf->port)
+ bcmasp_en_mda_filter(intf, 0, i);
+ }
+}
+
+static int bcmasp_combine_set_filter(struct bcmasp_intf *intf,
+ unsigned char *addr, unsigned char *mask,
+ int i)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ u64 addr1, addr2, mask1, mask2, mask3;
+
+ /* Switch to u64 to help with the calculations */
+ addr1 = ether_addr_to_u64(priv->mda_filters[i].addr);
+ mask1 = ether_addr_to_u64(priv->mda_filters[i].mask);
+ addr2 = ether_addr_to_u64(addr);
+ mask2 = ether_addr_to_u64(mask);
+
+ /* Check if one filter resides within the other */
+ mask3 = mask1 & mask2;
+ if (mask3 == mask1 && ((addr1 & mask1) == (addr2 & mask1))) {
+ /* Filter 2 resides within filter 1, so everything is good */
+ return 0;
+ } else if (mask3 == mask2 && ((addr1 & mask2) == (addr2 & mask2))) {
+ /* Filter 1 resides within filter 2, so swap filters */
+ bcmasp_set_mda_filter(intf, addr, mask, i);
+ return 0;
+ }
+
+ /* Unable to combine */
+ return -EINVAL;
+}
+
+int bcmasp_set_en_mda_filter(struct bcmasp_intf *intf, unsigned char *addr,
+ unsigned char *mask)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ int ret, res_count;
+ unsigned int i;
+
+ res_count = bcmasp_total_res_mda_cnt(intf->parent);
+
+ for (i = res_count; i < NUM_MDA_FILTERS; i++) {
+ /* If filter not enabled or belongs to another port skip */
+ if (!priv->mda_filters[i].en ||
+ priv->mda_filters[i].port != intf->port)
+ continue;
+
+ /* Attempt to combine filters */
+ ret = bcmasp_combine_set_filter(intf, addr, mask, i);
+ if (!ret) {
+ intf->mib.filters_combine_cnt++;
+ return 0;
+ }
+ }
+
+ /* Create new filter if possible */
+ for (i = res_count; i < NUM_MDA_FILTERS; i++) {
+ if (priv->mda_filters[i].en)
+ continue;
+
+ bcmasp_set_mda_filter(intf, addr, mask, i);
+ bcmasp_en_mda_filter(intf, 1, i);
+ return 0;
+ }
+
+ /* No room for new filter */
+ return -EINVAL;
+}
+
+static void bcmasp_core_init_filters(struct bcmasp_priv *priv)
+{
+ unsigned int i;
+
+ /* Disable all filters and reset software view since the HW
+ * can lose context while in deep sleep suspend states
+ */
+ for (i = 0; i < NUM_MDA_FILTERS; i++) {
+ rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_MDA_CFG(i));
+ priv->mda_filters[i].en = 0;
+ }
+
+ for (i = 0; i < NUM_NET_FILTERS; i++)
+ rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_NET_CFG(i));
+
+ /* Top level filter enable bit should be enabled at all times, set
+ * GEN_WAKE_CLEAR to clear the network filter wake-up which would
+ * otherwise be sticky
+ */
+ rx_filter_core_wl(priv, (ASP_RX_FILTER_OPUT_EN |
+ ASP_RX_FILTER_MDA_EN |
+ ASP_RX_FILTER_GEN_WK_CLR |
+ ASP_RX_FILTER_NT_FLT_EN),
+ ASP_RX_FILTER_BLK_CTRL);
+}
+
+/* ASP core initialization */
+static void bcmasp_core_init(struct bcmasp_priv *priv)
+{
+ tx_analytics_core_wl(priv, 0x0, ASP_TX_ANALYTICS_CTRL);
+ rx_analytics_core_wl(priv, 0x4, ASP_RX_ANALYTICS_CTRL);
+
+ rx_edpkt_core_wl(priv, (ASP_EDPKT_HDR_SZ_128 << ASP_EDPKT_HDR_SZ_SHIFT),
+ ASP_EDPKT_HDR_CFG);
+ rx_edpkt_core_wl(priv,
+ (ASP_EDPKT_ENDI_BT_SWP_WD << ASP_EDPKT_ENDI_DESC_SHIFT),
+ ASP_EDPKT_ENDI);
+
+ rx_edpkt_core_wl(priv, 0x1b, ASP_EDPKT_BURST_BUF_PSCAL_TOUT);
+ rx_edpkt_core_wl(priv, 0x3e8, ASP_EDPKT_BURST_BUF_WRITE_TOUT);
+ rx_edpkt_core_wl(priv, 0x3e8, ASP_EDPKT_BURST_BUF_READ_TOUT);
+
+ rx_edpkt_core_wl(priv, ASP_EDPKT_ENABLE_EN, ASP_EDPKT_ENABLE);
+
+ /* Disable and clear both UniMAC's wake-up interrupts to avoid
+ * sticky interrupts.
+ */
+ _intr2_mask_set(priv, ASP_INTR2_UMC0_WAKE | ASP_INTR2_UMC1_WAKE);
+ intr2_core_wl(priv, ASP_INTR2_UMC0_WAKE | ASP_INTR2_UMC1_WAKE,
+ ASP_INTR2_CLEAR);
+}
+
+static void bcmasp_core_clock_select(struct bcmasp_priv *priv, bool slow)
+{
+ u32 reg;
+
+ reg = ctrl_core_rl(priv, ASP_CTRL_CORE_CLOCK_SELECT);
+ if (slow)
+ reg &= ~ASP_CTRL_CORE_CLOCK_SELECT_MAIN;
+ else
+ reg |= ASP_CTRL_CORE_CLOCK_SELECT_MAIN;
+ ctrl_core_wl(priv, reg, ASP_CTRL_CORE_CLOCK_SELECT);
+}
+
+static void bcmasp_core_clock_set_ll(struct bcmasp_priv *priv, u32 clr, u32 set)
+{
+ u32 reg;
+
+ reg = ctrl_core_rl(priv, ASP_CTRL_CLOCK_CTRL);
+ reg &= ~clr;
+ reg |= set;
+ ctrl_core_wl(priv, reg, ASP_CTRL_CLOCK_CTRL);
+
+ reg = ctrl_core_rl(priv, ASP_CTRL_SCRATCH_0);
+ reg &= ~clr;
+ reg |= set;
+ ctrl_core_wl(priv, reg, ASP_CTRL_SCRATCH_0);
+}
+
+static void bcmasp_core_clock_set(struct bcmasp_priv *priv, u32 clr, u32 set)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->clk_lock, flags);
+ bcmasp_core_clock_set_ll(priv, clr, set);
+ spin_unlock_irqrestore(&priv->clk_lock, flags);
+}
+
+void bcmasp_core_clock_set_intf(struct bcmasp_intf *intf, bool en)
+{
+ u32 intf_mask = ASP_CTRL_CLOCK_CTRL_ASP_RGMII_DIS(intf->port);
+ struct bcmasp_priv *priv = intf->parent;
+ unsigned long flags;
+ u32 reg;
+
+ /* When enabling an interface, if the RX or TX clocks were not enabled,
+ * enable them. Conversely, while disabling an interface, if this is
+ * the last one enabled, we can turn off the shared RX and TX clocks as
+ * well. We control enable bits which is why we test for equality on
+ * the RGMII clock bit mask.
+ */
+ spin_lock_irqsave(&priv->clk_lock, flags);
+ if (en) {
+ intf_mask |= ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE |
+ ASP_CTRL_CLOCK_CTRL_ASP_RX_DISABLE;
+ bcmasp_core_clock_set_ll(priv, intf_mask, 0);
+ } else {
+ reg = ctrl_core_rl(priv, ASP_CTRL_SCRATCH_0) | intf_mask;
+ if ((reg & ASP_CTRL_CLOCK_CTRL_ASP_RGMII_MASK) ==
+ ASP_CTRL_CLOCK_CTRL_ASP_RGMII_MASK)
+ intf_mask |= ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE |
+ ASP_CTRL_CLOCK_CTRL_ASP_RX_DISABLE;
+ bcmasp_core_clock_set_ll(priv, 0, intf_mask);
+ }
+ spin_unlock_irqrestore(&priv->clk_lock, flags);
+}
+
+static irqreturn_t bcmasp_isr_wol(int irq, void *data)
+{
+ struct bcmasp_priv *priv = data;
+ u32 status;
+
+ /* No L3 IRQ, so we good */
+ if (priv->wol_irq <= 0)
+ goto irq_handled;
+
+ status = wakeup_intr2_core_rl(priv, ASP_WAKEUP_INTR2_STATUS) &
+ ~wakeup_intr2_core_rl(priv, ASP_WAKEUP_INTR2_MASK_STATUS);
+ wakeup_intr2_core_wl(priv, status, ASP_WAKEUP_INTR2_CLEAR);
+
+irq_handled:
+ pm_wakeup_event(&priv->pdev->dev, 0);
+ return IRQ_HANDLED;
+}
+
+static int bcmasp_get_and_request_irq(struct bcmasp_priv *priv, int i)
+{
+ struct platform_device *pdev = priv->pdev;
+ int irq, ret;
+
+ irq = platform_get_irq_optional(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, bcmasp_isr_wol, 0,
+ pdev->name, priv);
+ if (ret)
+ return ret;
+
+ return irq;
+}
+
+static void bcmasp_init_wol_shared(struct bcmasp_priv *priv)
+{
+ struct platform_device *pdev = priv->pdev;
+ struct device *dev = &pdev->dev;
+ int irq;
+
+ irq = bcmasp_get_and_request_irq(priv, 1);
+ if (irq < 0) {
+ dev_warn(dev, "Failed to init WoL irq: %d\n", irq);
+ return;
+ }
+
+ priv->wol_irq = irq;
+ priv->wol_irq_enabled_mask = 0;
+ device_set_wakeup_capable(&pdev->dev, 1);
+}
+
+static void bcmasp_enable_wol_shared(struct bcmasp_intf *intf, bool en)
+{
+ struct bcmasp_priv *priv = intf->parent;
+ struct device *dev = &priv->pdev->dev;
+
+ if (en) {
+ if (priv->wol_irq_enabled_mask) {
+ set_bit(intf->port, &priv->wol_irq_enabled_mask);
+ return;
+ }
+
+ /* First enable */
+ set_bit(intf->port, &priv->wol_irq_enabled_mask);
+ enable_irq_wake(priv->wol_irq);
+ device_set_wakeup_enable(dev, 1);
+ } else {
+ if (!priv->wol_irq_enabled_mask)
+ return;
+
+ clear_bit(intf->port, &priv->wol_irq_enabled_mask);
+ if (priv->wol_irq_enabled_mask)
+ return;
+
+ /* Last disable */
+ disable_irq_wake(priv->wol_irq);
+ device_set_wakeup_enable(dev, 0);
+ }
+}
+
+static void bcmasp_wol_irq_destroy_shared(struct bcmasp_priv *priv)
+{
+ if (priv->wol_irq > 0)
+ free_irq(priv->wol_irq, priv);
+}
+
+static void bcmasp_init_wol_per_intf(struct bcmasp_priv *priv)
+{
+ struct platform_device *pdev = priv->pdev;
+ struct device *dev = &pdev->dev;
+ struct bcmasp_intf *intf;
+ int irq;
+
+ list_for_each_entry(intf, &priv->intfs, list) {
+ irq = bcmasp_get_and_request_irq(priv, intf->port + 1);
+ if (irq < 0) {
+ dev_warn(dev, "Failed to init WoL irq(port %d): %d\n",
+ intf->port, irq);
+ continue;
+ }
+
+ intf->wol_irq = irq;
+ intf->wol_irq_enabled = false;
+ device_set_wakeup_capable(&pdev->dev, 1);
+ }
+}
+
+static void bcmasp_enable_wol_per_intf(struct bcmasp_intf *intf, bool en)
+{
+ struct device *dev = &intf->parent->pdev->dev;
+
+ if (en ^ intf->wol_irq_enabled)
+ irq_set_irq_wake(intf->wol_irq, en);
+
+ intf->wol_irq_enabled = en;
+ device_set_wakeup_enable(dev, en);
+}
+
+static void bcmasp_wol_irq_destroy_per_intf(struct bcmasp_priv *priv)
+{
+ struct bcmasp_intf *intf;
+
+ list_for_each_entry(intf, &priv->intfs, list) {
+ if (intf->wol_irq > 0)
+ free_irq(intf->wol_irq, priv);
+ }
+}
+
+static struct bcmasp_hw_info v20_hw_info = {
+ .rx_ctrl_flush = ASP_RX_CTRL_FLUSH,
+ .umac2fb = UMAC2FB_OFFSET,
+ .rx_ctrl_fb_out_frame_count = ASP_RX_CTRL_FB_OUT_FRAME_COUNT,
+ .rx_ctrl_fb_filt_out_frame_count = ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT,
+ .rx_ctrl_fb_rx_fifo_depth = ASP_RX_CTRL_FB_RX_FIFO_DEPTH,
+};
+
+static const struct bcmasp_plat_data v20_plat_data = {
+ .init_wol = bcmasp_init_wol_per_intf,
+ .enable_wol = bcmasp_enable_wol_per_intf,
+ .destroy_wol = bcmasp_wol_irq_destroy_per_intf,
+ .hw_info = &v20_hw_info,
+};
+
+static struct bcmasp_hw_info v21_hw_info = {
+ .rx_ctrl_flush = ASP_RX_CTRL_FLUSH_2_1,
+ .umac2fb = UMAC2FB_OFFSET_2_1,
+ .rx_ctrl_fb_out_frame_count = ASP_RX_CTRL_FB_OUT_FRAME_COUNT_2_1,
+ .rx_ctrl_fb_filt_out_frame_count =
+ ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT_2_1,
+ .rx_ctrl_fb_rx_fifo_depth = ASP_RX_CTRL_FB_RX_FIFO_DEPTH_2_1,
+};
+
+static const struct bcmasp_plat_data v21_plat_data = {
+ .init_wol = bcmasp_init_wol_shared,
+ .enable_wol = bcmasp_enable_wol_shared,
+ .destroy_wol = bcmasp_wol_irq_destroy_shared,
+ .hw_info = &v21_hw_info,
+};
+
+static const struct of_device_id bcmasp_of_match[] = {
+ { .compatible = "brcm,asp-v2.0", .data = &v20_plat_data },
+ { .compatible = "brcm,asp-v2.1", .data = &v21_plat_data },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, bcmasp_of_match);
+
+static const struct of_device_id bcmasp_mdio_of_match[] = {
+ { .compatible = "brcm,asp-v2.1-mdio", },
+ { .compatible = "brcm,asp-v2.0-mdio", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, bcmasp_mdio_of_match);
+
+static void bcmasp_remove_intfs(struct bcmasp_priv *priv)
+{
+ struct bcmasp_intf *intf, *n;
+
+ list_for_each_entry_safe(intf, n, &priv->intfs, list) {
+ list_del(&intf->list);
+ bcmasp_interface_destroy(intf);
+ }
+}
+
+static int bcmasp_probe(struct platform_device *pdev)
+{
+ struct device_node *ports_node, *intf_node;
+ const struct bcmasp_plat_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct bcmasp_priv *priv;
+ struct bcmasp_intf *intf;
+ int ret = 0, count = 0;
+ unsigned int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ priv->clk = devm_clk_get_optional_enabled(dev, "sw_asp");
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "failed to request clock\n");
+
+ /* Base from parent node */
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return dev_err_probe(dev, PTR_ERR(priv->base), "failed to iomap\n");
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to set DMA mask: %d\n", ret);
+
+ dev_set_drvdata(&pdev->dev, priv);
+ priv->pdev = pdev;
+ spin_lock_init(&priv->mda_lock);
+ spin_lock_init(&priv->clk_lock);
+ mutex_init(&priv->wol_lock);
+ mutex_init(&priv->net_lock);
+ INIT_LIST_HEAD(&priv->intfs);
+
+ pdata = device_get_match_data(&pdev->dev);
+ if (!pdata)
+ return dev_err_probe(dev, -EINVAL, "unable to find platform data\n");
+
+ priv->init_wol = pdata->init_wol;
+ priv->enable_wol = pdata->enable_wol;
+ priv->destroy_wol = pdata->destroy_wol;
+ priv->hw_info = pdata->hw_info;
+
+ /* Enable all clocks to ensure successful probing */
+ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
+
+ /* Switch to the main clock */
+ bcmasp_core_clock_select(priv, false);
+
+ bcmasp_intr2_mask_set_all(priv);
+ bcmasp_intr2_clear_all(priv);
+
+ ret = devm_request_irq(&pdev->dev, priv->irq, bcmasp_isr, 0,
+ pdev->name, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request ASP interrupt: %d", ret);
+
+ /* Register mdio child nodes */
+ of_platform_populate(dev->of_node, bcmasp_mdio_of_match, NULL, dev);
+
+ /* ASP specific initialization, Needs to be done regardless of
+ * how many interfaces come up.
+ */
+ bcmasp_core_init(priv);
+ bcmasp_core_init_filters(priv);
+
+ ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports");
+ if (!ports_node) {
+ dev_warn(dev, "No ports found\n");
+ return -EINVAL;
+ }
+
+ i = 0;
+ for_each_available_child_of_node(ports_node, intf_node) {
+ intf = bcmasp_interface_create(priv, intf_node, i);
+ if (!intf) {
+ dev_err(dev, "Cannot create eth interface %d\n", i);
+ bcmasp_remove_intfs(priv);
+ goto of_put_exit;
+ }
+ list_add_tail(&intf->list, &priv->intfs);
+ i++;
+ }
+
+ /* Check and enable WoL */
+ priv->init_wol(priv);
+
+ /* Drop the clock reference count now and let ndo_open()/ndo_close()
+ * manage it for us from now on.
+ */
+ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
+
+ clk_disable_unprepare(priv->clk);
+
+ /* Now do the registration of the network ports which will take care
+ * of managing the clock properly.
+ */
+ list_for_each_entry(intf, &priv->intfs, list) {
+ ret = register_netdev(intf->ndev);
+ if (ret) {
+ netdev_err(intf->ndev,
+ "failed to register net_device: %d\n", ret);
+ priv->destroy_wol(priv);
+ bcmasp_remove_intfs(priv);
+ goto of_put_exit;
+ }
+ count++;
+ }
+
+ dev_info(dev, "Initialized %d port(s)\n", count);
+
+of_put_exit:
+ of_node_put(ports_node);
+ return ret;
+}
+
+static int bcmasp_remove(struct platform_device *pdev)
+{
+ struct bcmasp_priv *priv = dev_get_drvdata(&pdev->dev);
+
+ if (!priv)
+ return 0;
+
+ priv->destroy_wol(priv);
+ bcmasp_remove_intfs(priv);
+
+ return 0;
+}
+
+static void bcmasp_shutdown(struct platform_device *pdev)
+{
+ bcmasp_remove(pdev);
+}
+
+static int __maybe_unused bcmasp_suspend(struct device *d)
+{
+ struct bcmasp_priv *priv = dev_get_drvdata(d);
+ struct bcmasp_intf *intf;
+ int ret;
+
+ list_for_each_entry(intf, &priv->intfs, list) {
+ ret = bcmasp_interface_suspend(intf);
+ if (ret)
+ break;
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ /* Whether Wake-on-LAN is enabled or not, we can always disable
+ * the shared TX clock
+ */
+ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE);
+
+ bcmasp_core_clock_select(priv, true);
+
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int __maybe_unused bcmasp_resume(struct device *d)
+{
+ struct bcmasp_priv *priv = dev_get_drvdata(d);
+ struct bcmasp_intf *intf;
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ /* Switch to the main clock domain */
+ bcmasp_core_clock_select(priv, false);
+
+ /* Re-enable all clocks for re-initialization */
+ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
+
+ bcmasp_core_init(priv);
+ bcmasp_core_init_filters(priv);
+
+ /* And disable them to let the network devices take care of them */
+ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
+
+ clk_disable_unprepare(priv->clk);
+
+ list_for_each_entry(intf, &priv->intfs, list) {
+ ret = bcmasp_interface_resume(intf);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(bcmasp_pm_ops,
+ bcmasp_suspend, bcmasp_resume);
+
+static struct platform_driver bcmasp_driver = {
+ .probe = bcmasp_probe,
+ .remove = bcmasp_remove,
+ .shutdown = bcmasp_shutdown,
+ .driver = {
+ .name = "brcm,asp-v2",
+ .of_match_table = bcmasp_of_match,
+ .pm = &bcmasp_pm_ops,
+ },
+};
+module_platform_driver(bcmasp_driver);
+
+MODULE_DESCRIPTION("Broadcom ASP 2.0 Ethernet controller driver");
+MODULE_ALIAS("platform:brcm,asp-v2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h
new file mode 100644
index 000000000000..5b512f7f5e94
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h
@@ -0,0 +1,586 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BCMASP_H
+#define __BCMASP_H
+
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
+#include <uapi/linux/ethtool.h>
+
+#define ASP_INTR2_OFFSET 0x1000
+#define ASP_INTR2_STATUS 0x0
+#define ASP_INTR2_SET 0x4
+#define ASP_INTR2_CLEAR 0x8
+#define ASP_INTR2_MASK_STATUS 0xc
+#define ASP_INTR2_MASK_SET 0x10
+#define ASP_INTR2_MASK_CLEAR 0x14
+
+#define ASP_INTR2_RX_ECH(intr) BIT(intr)
+#define ASP_INTR2_TX_DESC(intr) BIT((intr) + 14)
+#define ASP_INTR2_UMC0_WAKE BIT(22)
+#define ASP_INTR2_UMC1_WAKE BIT(28)
+
+#define ASP_WAKEUP_INTR2_OFFSET 0x1200
+#define ASP_WAKEUP_INTR2_STATUS 0x0
+#define ASP_WAKEUP_INTR2_SET 0x4
+#define ASP_WAKEUP_INTR2_CLEAR 0x8
+#define ASP_WAKEUP_INTR2_MASK_STATUS 0xc
+#define ASP_WAKEUP_INTR2_MASK_SET 0x10
+#define ASP_WAKEUP_INTR2_MASK_CLEAR 0x14
+#define ASP_WAKEUP_INTR2_MPD_0 BIT(0)
+#define ASP_WAKEUP_INTR2_MPD_1 BIT(1)
+#define ASP_WAKEUP_INTR2_FILT_0 BIT(2)
+#define ASP_WAKEUP_INTR2_FILT_1 BIT(3)
+#define ASP_WAKEUP_INTR2_FW BIT(4)
+
+#define ASP_TX_ANALYTICS_OFFSET 0x4c000
+#define ASP_TX_ANALYTICS_CTRL 0x0
+
+#define ASP_RX_ANALYTICS_OFFSET 0x98000
+#define ASP_RX_ANALYTICS_CTRL 0x0
+
+#define ASP_RX_CTRL_OFFSET 0x9f000
+#define ASP_RX_CTRL_UMAC_0_FRAME_COUNT 0x8
+#define ASP_RX_CTRL_UMAC_1_FRAME_COUNT 0xc
+#define ASP_RX_CTRL_FB_0_FRAME_COUNT 0x14
+#define ASP_RX_CTRL_FB_1_FRAME_COUNT 0x18
+#define ASP_RX_CTRL_FB_8_FRAME_COUNT 0x1c
+/* asp2.1 diverges offsets here */
+/* ASP2.0 */
+#define ASP_RX_CTRL_FB_OUT_FRAME_COUNT 0x20
+#define ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT 0x24
+#define ASP_RX_CTRL_FLUSH 0x28
+#define ASP_CTRL_UMAC0_FLUSH_MASK (BIT(0) | BIT(12))
+#define ASP_CTRL_UMAC1_FLUSH_MASK (BIT(1) | BIT(13))
+#define ASP_CTRL_SPB_FLUSH_MASK (BIT(8) | BIT(20))
+#define ASP_RX_CTRL_FB_RX_FIFO_DEPTH 0x30
+/* ASP2.1 */
+#define ASP_RX_CTRL_FB_9_FRAME_COUNT_2_1 0x20
+#define ASP_RX_CTRL_FB_10_FRAME_COUNT_2_1 0x24
+#define ASP_RX_CTRL_FB_OUT_FRAME_COUNT_2_1 0x28
+#define ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT_2_1 0x2c
+#define ASP_RX_CTRL_FLUSH_2_1 0x30
+#define ASP_RX_CTRL_FB_RX_FIFO_DEPTH_2_1 0x38
+
+#define ASP_RX_FILTER_OFFSET 0x80000
+#define ASP_RX_FILTER_BLK_CTRL 0x0
+#define ASP_RX_FILTER_OPUT_EN BIT(0)
+#define ASP_RX_FILTER_MDA_EN BIT(1)
+#define ASP_RX_FILTER_LNR_MD BIT(2)
+#define ASP_RX_FILTER_GEN_WK_EN BIT(3)
+#define ASP_RX_FILTER_GEN_WK_CLR BIT(4)
+#define ASP_RX_FILTER_NT_FLT_EN BIT(5)
+#define ASP_RX_FILTER_MDA_CFG(sel) (((sel) * 0x14) + 0x100)
+#define ASP_RX_FILTER_MDA_CFG_EN_SHIFT 8
+#define ASP_RX_FILTER_MDA_CFG_UMC_SEL(sel) ((sel) > 1 ? BIT(17) : \
+ BIT((sel) + 9))
+#define ASP_RX_FILTER_MDA_PAT_H(sel) (((sel) * 0x14) + 0x104)
+#define ASP_RX_FILTER_MDA_PAT_L(sel) (((sel) * 0x14) + 0x108)
+#define ASP_RX_FILTER_MDA_MSK_H(sel) (((sel) * 0x14) + 0x10c)
+#define ASP_RX_FILTER_MDA_MSK_L(sel) (((sel) * 0x14) + 0x110)
+#define ASP_RX_FILTER_MDA_CFG(sel) (((sel) * 0x14) + 0x100)
+#define ASP_RX_FILTER_MDA_PAT_H(sel) (((sel) * 0x14) + 0x104)
+#define ASP_RX_FILTER_MDA_PAT_L(sel) (((sel) * 0x14) + 0x108)
+#define ASP_RX_FILTER_MDA_MSK_H(sel) (((sel) * 0x14) + 0x10c)
+#define ASP_RX_FILTER_MDA_MSK_L(sel) (((sel) * 0x14) + 0x110)
+#define ASP_RX_FILTER_NET_CFG(sel) (((sel) * 0xa04) + 0x400)
+#define ASP_RX_FILTER_NET_CFG_CH(sel) ((sel) << 0)
+#define ASP_RX_FILTER_NET_CFG_EN BIT(9)
+#define ASP_RX_FILTER_NET_CFG_L2_EN BIT(10)
+#define ASP_RX_FILTER_NET_CFG_L3_EN BIT(11)
+#define ASP_RX_FILTER_NET_CFG_L4_EN BIT(12)
+#define ASP_RX_FILTER_NET_CFG_L3_FRM(sel) ((sel) << 13)
+#define ASP_RX_FILTER_NET_CFG_L4_FRM(sel) ((sel) << 15)
+#define ASP_RX_FILTER_NET_CFG_UMC(sel) BIT((sel) + 19)
+#define ASP_RX_FILTER_NET_CFG_DMA_EN BIT(27)
+
+#define ASP_RX_FILTER_NET_OFFSET_MAX 32
+#define ASP_RX_FILTER_NET_PAT(sel, block, off) \
+ (((sel) * 0xa04) + ((block) * 0x200) + (off) + 0x600)
+#define ASP_RX_FILTER_NET_MASK(sel, block, off) \
+ (((sel) * 0xa04) + ((block) * 0x200) + (off) + 0x700)
+
+#define ASP_RX_FILTER_NET_OFFSET(sel) (((sel) * 0xa04) + 0xe00)
+#define ASP_RX_FILTER_NET_OFFSET_L2(val) ((val) << 0)
+#define ASP_RX_FILTER_NET_OFFSET_L3_0(val) ((val) << 8)
+#define ASP_RX_FILTER_NET_OFFSET_L3_1(val) ((val) << 16)
+#define ASP_RX_FILTER_NET_OFFSET_L4(val) ((val) << 24)
+
+enum asp_rx_net_filter_block {
+ ASP_RX_FILTER_NET_L2 = 0,
+ ASP_RX_FILTER_NET_L3_0,
+ ASP_RX_FILTER_NET_L3_1,
+ ASP_RX_FILTER_NET_L4,
+ ASP_RX_FILTER_NET_BLOCK_MAX
+};
+
+#define ASP_EDPKT_OFFSET 0x9c000
+#define ASP_EDPKT_ENABLE 0x4
+#define ASP_EDPKT_ENABLE_EN BIT(0)
+#define ASP_EDPKT_HDR_CFG 0xc
+#define ASP_EDPKT_HDR_SZ_SHIFT 2
+#define ASP_EDPKT_HDR_SZ_32 0
+#define ASP_EDPKT_HDR_SZ_64 1
+#define ASP_EDPKT_HDR_SZ_96 2
+#define ASP_EDPKT_HDR_SZ_128 3
+#define ASP_EDPKT_BURST_BUF_PSCAL_TOUT 0x10
+#define ASP_EDPKT_BURST_BUF_WRITE_TOUT 0x14
+#define ASP_EDPKT_BURST_BUF_READ_TOUT 0x18
+#define ASP_EDPKT_RX_TS_COUNTER 0x38
+#define ASP_EDPKT_ENDI 0x48
+#define ASP_EDPKT_ENDI_DESC_SHIFT 8
+#define ASP_EDPKT_ENDI_NO_BT_SWP 0
+#define ASP_EDPKT_ENDI_BT_SWP_WD 1
+#define ASP_EDPKT_RX_PKT_CNT 0x138
+#define ASP_EDPKT_HDR_EXTR_CNT 0x13c
+#define ASP_EDPKT_HDR_OUT_CNT 0x140
+
+#define ASP_CTRL 0x101000
+#define ASP_CTRL_ASP_SW_INIT 0x04
+#define ASP_CTRL_ASP_SW_INIT_ACPUSS_CORE BIT(0)
+#define ASP_CTRL_ASP_SW_INIT_ASP_TX BIT(1)
+#define ASP_CTRL_ASP_SW_INIT_AS_RX BIT(2)
+#define ASP_CTRL_ASP_SW_INIT_ASP_RGMII_UMAC0 BIT(3)
+#define ASP_CTRL_ASP_SW_INIT_ASP_RGMII_UMAC1 BIT(4)
+#define ASP_CTRL_ASP_SW_INIT_ASP_XMEMIF BIT(5)
+#define ASP_CTRL_CLOCK_CTRL 0x04
+#define ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE BIT(0)
+#define ASP_CTRL_CLOCK_CTRL_ASP_RX_DISABLE BIT(1)
+#define ASP_CTRL_CLOCK_CTRL_ASP_RGMII_SHIFT 2
+#define ASP_CTRL_CLOCK_CTRL_ASP_RGMII_MASK (0x7 << ASP_CTRL_CLOCK_CTRL_ASP_RGMII_SHIFT)
+#define ASP_CTRL_CLOCK_CTRL_ASP_RGMII_DIS(x) BIT(ASP_CTRL_CLOCK_CTRL_ASP_RGMII_SHIFT + (x))
+#define ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE GENMASK(4, 0)
+#define ASP_CTRL_CORE_CLOCK_SELECT 0x08
+#define ASP_CTRL_CORE_CLOCK_SELECT_MAIN BIT(0)
+#define ASP_CTRL_SCRATCH_0 0x0c
+
+struct bcmasp_tx_cb {
+ struct sk_buff *skb;
+ unsigned int bytes_sent;
+ bool last;
+
+ DEFINE_DMA_UNMAP_ADDR(dma_addr);
+ DEFINE_DMA_UNMAP_LEN(dma_len);
+};
+
+struct bcmasp_res {
+ /* Per interface resources */
+ /* Port */
+ void __iomem *umac;
+ void __iomem *umac2fb;
+ void __iomem *rgmii;
+
+ /* TX slowpath/configuration */
+ void __iomem *tx_spb_ctrl;
+ void __iomem *tx_spb_top;
+ void __iomem *tx_epkt_core;
+ void __iomem *tx_pause_ctrl;
+};
+
+#define DESC_ADDR(x) ((x) & GENMASK_ULL(39, 0))
+#define DESC_FLAGS(x) ((x) & GENMASK_ULL(63, 40))
+
+struct bcmasp_desc {
+ u64 buf;
+ #define DESC_CHKSUM BIT_ULL(40)
+ #define DESC_CRC_ERR BIT_ULL(41)
+ #define DESC_RX_SYM_ERR BIT_ULL(42)
+ #define DESC_NO_OCT_ALN BIT_ULL(43)
+ #define DESC_PKT_TRUC BIT_ULL(44)
+ /* 39:0 (TX/RX) bits 0-39 of buf addr
+ * 40 (RX) checksum
+ * 41 (RX) crc_error
+ * 42 (RX) rx_symbol_error
+ * 43 (RX) non_octet_aligned
+ * 44 (RX) pkt_truncated
+ * 45 Reserved
+ * 56:46 (RX) mac_filter_id
+ * 60:57 (RX) rx_port_num (0-unicmac0, 1-unimac1)
+ * 61 Reserved
+ * 63:62 (TX) forward CRC, overwrite CRC
+ */
+ u32 size;
+ u32 flags;
+ #define DESC_INT_EN BIT(0)
+ #define DESC_SOF BIT(1)
+ #define DESC_EOF BIT(2)
+ #define DESC_EPKT_CMD BIT(3)
+ #define DESC_SCRAM_ST BIT(8)
+ #define DESC_SCRAM_END BIT(9)
+ #define DESC_PCPP BIT(10)
+ #define DESC_PPPP BIT(11)
+ /* 0 (TX) tx_int_en
+ * 1 (TX/RX) SOF
+ * 2 (TX/RX) EOF
+ * 3 (TX) epkt_command
+ * 6:4 (TX) PA
+ * 7 (TX) pause at desc end
+ * 8 (TX) scram_start
+ * 9 (TX) scram_end
+ * 10 (TX) PCPP
+ * 11 (TX) PPPP
+ * 14:12 Reserved
+ * 15 (TX) pid ch Valid
+ * 19:16 (TX) data_pkt_type
+ * 32:20 (TX) pid_channel (RX) nw_filter_id
+ */
+};
+
+struct bcmasp_intf;
+
+struct bcmasp_intf_stats64 {
+ /* Rx Stats */
+ u64_stats_t rx_packets;
+ u64_stats_t rx_bytes;
+ u64_stats_t rx_errors;
+ u64_stats_t rx_dropped;
+ u64_stats_t rx_crc_errs;
+ u64_stats_t rx_sym_errs;
+
+ /* Tx Stats*/
+ u64_stats_t tx_packets;
+ u64_stats_t tx_bytes;
+
+ struct u64_stats_sync syncp;
+};
+
+struct bcmasp_mib_counters {
+ u32 edpkt_ts;
+ u32 edpkt_rx_pkt_cnt;
+ u32 edpkt_hdr_ext_cnt;
+ u32 edpkt_hdr_out_cnt;
+ u32 umac_frm_cnt;
+ u32 fb_frm_cnt;
+ u32 fb_rx_fifo_depth;
+ u32 fb_out_frm_cnt;
+ u32 fb_filt_out_frm_cnt;
+ u32 alloc_rx_skb_failed;
+ u32 tx_dma_failed;
+ u32 mc_filters_full_cnt;
+ u32 uc_filters_full_cnt;
+ u32 filters_combine_cnt;
+ u32 promisc_filters_cnt;
+ u32 tx_realloc_offload_failed;
+ u32 tx_timeout_cnt;
+};
+
+struct bcmasp_intf_ops {
+ unsigned long (*rx_desc_read)(struct bcmasp_intf *intf);
+ void (*rx_buffer_write)(struct bcmasp_intf *intf, dma_addr_t addr);
+ void (*rx_desc_write)(struct bcmasp_intf *intf, dma_addr_t addr);
+ unsigned long (*tx_read)(struct bcmasp_intf *intf);
+ void (*tx_write)(struct bcmasp_intf *intf, dma_addr_t addr);
+};
+
+struct bcmasp_priv;
+
+struct bcmasp_intf {
+ struct list_head list;
+ struct net_device *ndev;
+ struct bcmasp_priv *parent;
+
+ /* ASP Ch */
+ int channel;
+ int port;
+ const struct bcmasp_intf_ops *ops;
+
+ /* Used for splitting shared resources */
+ int index;
+
+ struct napi_struct tx_napi;
+ /* TX ring, starts on a new cacheline boundary */
+ void __iomem *tx_spb_dma;
+ int tx_spb_index;
+ int tx_spb_clean_index;
+ struct bcmasp_desc *tx_spb_cpu;
+ dma_addr_t tx_spb_dma_addr;
+ dma_addr_t tx_spb_dma_valid;
+ dma_addr_t tx_spb_dma_read;
+ struct bcmasp_tx_cb *tx_cbs;
+
+ /* RX ring, starts on a new cacheline boundary */
+ void __iomem *rx_edpkt_cfg;
+ void __iomem *rx_edpkt_dma;
+ int rx_edpkt_index;
+ int rx_buf_order;
+ struct bcmasp_desc *rx_edpkt_cpu;
+ dma_addr_t rx_edpkt_dma_addr;
+ dma_addr_t rx_edpkt_dma_read;
+
+ /* RX buffer prefetcher ring*/
+ void *rx_ring_cpu;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t rx_ring_dma_valid;
+ struct napi_struct rx_napi;
+
+ struct bcmasp_res res;
+ unsigned int crc_fwd;
+
+ /* PHY device */
+ struct device_node *phy_dn;
+ struct device_node *ndev_dn;
+ phy_interface_t phy_interface;
+ bool internal_phy;
+ int old_pause;
+ int old_link;
+ int old_duplex;
+
+ u32 msg_enable;
+
+ /* Statistics */
+ struct bcmasp_intf_stats64 stats64;
+ struct bcmasp_mib_counters mib;
+
+ u32 wolopts;
+ u8 sopass[SOPASS_MAX];
+ /* Used if per intf wol irq */
+ int wol_irq;
+ unsigned int wol_irq_enabled:1;
+
+ struct ethtool_eee eee;
+};
+
+#define NUM_NET_FILTERS 32
+struct bcmasp_net_filter {
+ struct ethtool_rx_flow_spec fs;
+
+ bool claimed;
+ bool wake_filter;
+
+ int port;
+ unsigned int hw_index;
+};
+
+#define NUM_MDA_FILTERS 32
+struct bcmasp_mda_filter {
+ /* Current owner of this filter */
+ int port;
+ bool en;
+ u8 addr[ETH_ALEN];
+ u8 mask[ETH_ALEN];
+};
+
+struct bcmasp_hw_info {
+ u32 rx_ctrl_flush;
+ u32 umac2fb;
+ u32 rx_ctrl_fb_out_frame_count;
+ u32 rx_ctrl_fb_filt_out_frame_count;
+ u32 rx_ctrl_fb_rx_fifo_depth;
+};
+
+struct bcmasp_plat_data {
+ void (*init_wol)(struct bcmasp_priv *priv);
+ void (*enable_wol)(struct bcmasp_intf *intf, bool en);
+ void (*destroy_wol)(struct bcmasp_priv *priv);
+ struct bcmasp_hw_info *hw_info;
+};
+
+struct bcmasp_priv {
+ struct platform_device *pdev;
+ struct clk *clk;
+
+ int irq;
+ u32 irq_mask;
+
+ /* Used if shared wol irq */
+ struct mutex wol_lock;
+ int wol_irq;
+ unsigned long wol_irq_enabled_mask;
+
+ void (*init_wol)(struct bcmasp_priv *priv);
+ void (*enable_wol)(struct bcmasp_intf *intf, bool en);
+ void (*destroy_wol)(struct bcmasp_priv *priv);
+
+ void __iomem *base;
+ struct bcmasp_hw_info *hw_info;
+
+ struct list_head intfs;
+
+ struct bcmasp_mda_filter mda_filters[NUM_MDA_FILTERS];
+
+ /* MAC destination address filters lock */
+ spinlock_t mda_lock;
+
+ /* Protects accesses to ASP_CTRL_CLOCK_CTRL */
+ spinlock_t clk_lock;
+
+ struct bcmasp_net_filter net_filters[NUM_NET_FILTERS];
+
+ /* Network filter lock */
+ struct mutex net_lock;
+};
+
+static inline unsigned long bcmasp_intf_rx_desc_read(struct bcmasp_intf *intf)
+{
+ return intf->ops->rx_desc_read(intf);
+}
+
+static inline void bcmasp_intf_rx_buffer_write(struct bcmasp_intf *intf,
+ dma_addr_t addr)
+{
+ intf->ops->rx_buffer_write(intf, addr);
+}
+
+static inline void bcmasp_intf_rx_desc_write(struct bcmasp_intf *intf,
+ dma_addr_t addr)
+{
+ intf->ops->rx_desc_write(intf, addr);
+}
+
+static inline unsigned long bcmasp_intf_tx_read(struct bcmasp_intf *intf)
+{
+ return intf->ops->tx_read(intf);
+}
+
+static inline void bcmasp_intf_tx_write(struct bcmasp_intf *intf,
+ dma_addr_t addr)
+{
+ intf->ops->tx_write(intf, addr);
+}
+
+#define __BCMASP_IO_MACRO(name, m) \
+static inline u32 name##_rl(struct bcmasp_intf *intf, u32 off) \
+{ \
+ u32 reg = readl_relaxed(intf->m + off); \
+ return reg; \
+} \
+static inline void name##_wl(struct bcmasp_intf *intf, u32 val, u32 off)\
+{ \
+ writel_relaxed(val, intf->m + off); \
+}
+
+#define BCMASP_IO_MACRO(name) __BCMASP_IO_MACRO(name, res.name)
+#define BCMASP_FP_IO_MACRO(name) __BCMASP_IO_MACRO(name, name)
+
+BCMASP_IO_MACRO(umac);
+BCMASP_IO_MACRO(umac2fb);
+BCMASP_IO_MACRO(rgmii);
+BCMASP_FP_IO_MACRO(tx_spb_dma);
+BCMASP_IO_MACRO(tx_spb_ctrl);
+BCMASP_IO_MACRO(tx_spb_top);
+BCMASP_IO_MACRO(tx_epkt_core);
+BCMASP_IO_MACRO(tx_pause_ctrl);
+BCMASP_FP_IO_MACRO(rx_edpkt_dma);
+BCMASP_FP_IO_MACRO(rx_edpkt_cfg);
+
+#define __BCMASP_FP_IO_MACRO_Q(name, m) \
+static inline u64 name##_rq(struct bcmasp_intf *intf, u32 off) \
+{ \
+ u64 reg = readq_relaxed(intf->m + off); \
+ return reg; \
+} \
+static inline void name##_wq(struct bcmasp_intf *intf, u64 val, u32 off)\
+{ \
+ writeq_relaxed(val, intf->m + off); \
+}
+
+#define BCMASP_FP_IO_MACRO_Q(name) __BCMASP_FP_IO_MACRO_Q(name, name)
+
+BCMASP_FP_IO_MACRO_Q(tx_spb_dma);
+BCMASP_FP_IO_MACRO_Q(rx_edpkt_dma);
+BCMASP_FP_IO_MACRO_Q(rx_edpkt_cfg);
+
+#define PKT_OFFLOAD_NOP (0 << 28)
+#define PKT_OFFLOAD_HDR_OP (1 << 28)
+#define PKT_OFFLOAD_HDR_WRBACK BIT(19)
+#define PKT_OFFLOAD_HDR_COUNT(x) ((x) << 16)
+#define PKT_OFFLOAD_HDR_SIZE_1(x) ((x) << 4)
+#define PKT_OFFLOAD_HDR_SIZE_2(x) (x)
+#define PKT_OFFLOAD_HDR2_SIZE_2(x) ((x) << 24)
+#define PKT_OFFLOAD_HDR2_SIZE_3(x) ((x) << 12)
+#define PKT_OFFLOAD_HDR2_SIZE_4(x) (x)
+#define PKT_OFFLOAD_EPKT_OP (2 << 28)
+#define PKT_OFFLOAD_EPKT_WRBACK BIT(23)
+#define PKT_OFFLOAD_EPKT_IP(x) ((x) << 21)
+#define PKT_OFFLOAD_EPKT_TP(x) ((x) << 19)
+#define PKT_OFFLOAD_EPKT_LEN(x) ((x) << 16)
+#define PKT_OFFLOAD_EPKT_CSUM_L3 BIT(15)
+#define PKT_OFFLOAD_EPKT_CSUM_L2 BIT(14)
+#define PKT_OFFLOAD_EPKT_ID(x) ((x) << 12)
+#define PKT_OFFLOAD_EPKT_SEQ(x) ((x) << 10)
+#define PKT_OFFLOAD_EPKT_TS(x) ((x) << 8)
+#define PKT_OFFLOAD_EPKT_BLOC(x) (x)
+#define PKT_OFFLOAD_END_OP (7 << 28)
+
+struct bcmasp_pkt_offload {
+ __be32 nop;
+ __be32 header;
+ __be32 header2;
+ __be32 epkt;
+ __be32 end;
+};
+
+#define BCMASP_CORE_IO_MACRO(name, offset) \
+static inline u32 name##_core_rl(struct bcmasp_priv *priv, \
+ u32 off) \
+{ \
+ u32 reg = readl_relaxed(priv->base + (offset) + off); \
+ return reg; \
+} \
+static inline void name##_core_wl(struct bcmasp_priv *priv, \
+ u32 val, u32 off) \
+{ \
+ writel_relaxed(val, priv->base + (offset) + off); \
+}
+
+BCMASP_CORE_IO_MACRO(intr2, ASP_INTR2_OFFSET);
+BCMASP_CORE_IO_MACRO(wakeup_intr2, ASP_WAKEUP_INTR2_OFFSET);
+BCMASP_CORE_IO_MACRO(tx_analytics, ASP_TX_ANALYTICS_OFFSET);
+BCMASP_CORE_IO_MACRO(rx_analytics, ASP_RX_ANALYTICS_OFFSET);
+BCMASP_CORE_IO_MACRO(rx_ctrl, ASP_RX_CTRL_OFFSET);
+BCMASP_CORE_IO_MACRO(rx_filter, ASP_RX_FILTER_OFFSET);
+BCMASP_CORE_IO_MACRO(rx_edpkt, ASP_EDPKT_OFFSET);
+BCMASP_CORE_IO_MACRO(ctrl, ASP_CTRL);
+
+struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
+ struct device_node *ndev_dn, int i);
+
+void bcmasp_interface_destroy(struct bcmasp_intf *intf);
+
+void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en);
+
+void bcmasp_enable_rx_irq(struct bcmasp_intf *intf, int en);
+
+void bcmasp_flush_rx_port(struct bcmasp_intf *intf);
+
+extern const struct ethtool_ops bcmasp_ethtool_ops;
+
+int bcmasp_interface_suspend(struct bcmasp_intf *intf);
+
+int bcmasp_interface_resume(struct bcmasp_intf *intf);
+
+void bcmasp_set_promisc(struct bcmasp_intf *intf, bool en);
+
+void bcmasp_set_allmulti(struct bcmasp_intf *intf, bool en);
+
+void bcmasp_set_broad(struct bcmasp_intf *intf, bool en);
+
+void bcmasp_set_oaddr(struct bcmasp_intf *intf, const unsigned char *addr,
+ bool en);
+
+int bcmasp_set_en_mda_filter(struct bcmasp_intf *intf, unsigned char *addr,
+ unsigned char *mask);
+
+void bcmasp_disable_all_filters(struct bcmasp_intf *intf);
+
+void bcmasp_core_clock_set_intf(struct bcmasp_intf *intf, bool en);
+
+struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf,
+ u32 loc, bool wake_filter,
+ bool init);
+
+bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf,
+ struct ethtool_rx_flow_spec *fs);
+
+void bcmasp_netfilt_release(struct bcmasp_intf *intf,
+ struct bcmasp_net_filter *nfilt);
+
+int bcmasp_netfilt_get_active(struct bcmasp_intf *intf);
+
+void bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
+ u32 *rule_cnt);
+
+void bcmasp_netfilt_suspend(struct bcmasp_intf *intf);
+
+void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable);
+#endif
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c
new file mode 100644
index 000000000000..c4f1604d5ab3
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+#define pr_fmt(fmt) "bcmasp_ethtool: " fmt
+
+#include <asm-generic/unaligned.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#include "bcmasp.h"
+#include "bcmasp_intf_defs.h"
+
+enum bcmasp_stat_type {
+ BCMASP_STAT_RX_EDPKT,
+ BCMASP_STAT_RX_CTRL,
+ BCMASP_STAT_RX_CTRL_PER_INTF,
+ BCMASP_STAT_SOFT,
+};
+
+struct bcmasp_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ enum bcmasp_stat_type type;
+ u32 reg_offset;
+};
+
+#define STAT_BCMASP_SOFT_MIB(str) { \
+ .stat_string = str, \
+ .type = BCMASP_STAT_SOFT, \
+}
+
+#define STAT_BCMASP_OFFSET(str, _type, offset) { \
+ .stat_string = str, \
+ .type = _type, \
+ .reg_offset = offset, \
+}
+
+#define STAT_BCMASP_RX_EDPKT(str, offset) \
+ STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_EDPKT, offset)
+#define STAT_BCMASP_RX_CTRL(str, offset) \
+ STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset)
+#define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \
+ STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL_PER_INTF, offset)
+
+/* Must match the order of struct bcmasp_mib_counters */
+static const struct bcmasp_stats bcmasp_gstrings_stats[] = {
+ /* EDPKT counters */
+ STAT_BCMASP_RX_EDPKT("RX Time Stamp", ASP_EDPKT_RX_TS_COUNTER),
+ STAT_BCMASP_RX_EDPKT("RX PKT Count", ASP_EDPKT_RX_PKT_CNT),
+ STAT_BCMASP_RX_EDPKT("RX PKT Buffered", ASP_EDPKT_HDR_EXTR_CNT),
+ STAT_BCMASP_RX_EDPKT("RX PKT Pushed to DRAM", ASP_EDPKT_HDR_OUT_CNT),
+ /* ASP RX control */
+ STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac",
+ ASP_RX_CTRL_UMAC_0_FRAME_COUNT),
+ STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Port",
+ ASP_RX_CTRL_FB_0_FRAME_COUNT),
+ STAT_BCMASP_RX_CTRL_PER_INTF("RX Buffer FIFO Depth",
+ ASP_RX_CTRL_FB_RX_FIFO_DEPTH),
+ STAT_BCMASP_RX_CTRL("Frames Out(Buffer)",
+ ASP_RX_CTRL_FB_OUT_FRAME_COUNT),
+ STAT_BCMASP_RX_CTRL("Frames Out(Filters)",
+ ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT),
+ /* Software maintained statistics */
+ STAT_BCMASP_SOFT_MIB("RX SKB Alloc Failed"),
+ STAT_BCMASP_SOFT_MIB("TX DMA Failed"),
+ STAT_BCMASP_SOFT_MIB("Multicast Filters Full"),
+ STAT_BCMASP_SOFT_MIB("Unicast Filters Full"),
+ STAT_BCMASP_SOFT_MIB("MDA Filters Combined"),
+ STAT_BCMASP_SOFT_MIB("Promisc Filter Set"),
+ STAT_BCMASP_SOFT_MIB("TX Realloc For Offload Failed"),
+ STAT_BCMASP_SOFT_MIB("Tx Timeout Count"),
+};
+
+#define BCMASP_STATS_LEN ARRAY_SIZE(bcmasp_gstrings_stats)
+
+static u16 bcmasp_stat_fixup_offset(struct bcmasp_intf *intf,
+ const struct bcmasp_stats *s)
+{
+ struct bcmasp_priv *priv = intf->parent;
+
+ if (!strcmp("Frames Out(Buffer)", s->stat_string))
+ return priv->hw_info->rx_ctrl_fb_out_frame_count;
+
+ if (!strcmp("Frames Out(Filters)", s->stat_string))
+ return priv->hw_info->rx_ctrl_fb_filt_out_frame_count;
+
+ if (!strcmp("RX Buffer FIFO Depth", s->stat_string))
+ return priv->hw_info->rx_ctrl_fb_rx_fifo_depth;
+
+ return s->reg_offset;
+}
+
+static int bcmasp_get_sset_count(struct net_device *dev, int string_set)
+{
+ switch (string_set) {
+ case ETH_SS_STATS:
+ return BCMASP_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void bcmasp_get_strings(struct net_device *dev, u32 stringset,
+ u8 *data)
+{
+ 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);
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+static void bcmasp_update_mib_counters(struct bcmasp_intf *intf)
+{
+ unsigned int i;
+
+ for (i = 0; i < BCMASP_STATS_LEN; i++) {
+ const struct bcmasp_stats *s;
+ u32 offset, val;
+ char *p;
+
+ s = &bcmasp_gstrings_stats[i];
+ offset = bcmasp_stat_fixup_offset(intf, s);
+ switch (s->type) {
+ case BCMASP_STAT_SOFT:
+ continue;
+ case BCMASP_STAT_RX_EDPKT:
+ val = rx_edpkt_core_rl(intf->parent, offset);
+ break;
+ case BCMASP_STAT_RX_CTRL:
+ val = rx_ctrl_core_rl(intf->parent, offset);
+ break;
+ case BCMASP_STAT_RX_CTRL_PER_INTF:
+ offset += sizeof(u32) * intf->port;
+ val = rx_ctrl_core_rl(intf->parent, offset);
+ break;
+ default:
+ continue;
+ }
+ p = (char *)(&intf->mib) + (i * sizeof(u32));
+ put_unaligned(val, (u32 *)p);
+ }
+}
+
+static void bcmasp_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ unsigned int i;
+ char *p;
+
+ if (netif_running(dev))
+ bcmasp_update_mib_counters(intf);
+
+ for (i = 0; i < BCMASP_STATS_LEN; i++) {
+ p = (char *)(&intf->mib) + (i * sizeof(u32));
+ data[i] = *(u32 *)p;
+ }
+}
+
+static void bcmasp_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strscpy(info->driver, "bcmasp", sizeof(info->driver));
+ strscpy(info->bus_info, dev_name(dev->dev.parent),
+ sizeof(info->bus_info));
+}
+
+static u32 bcmasp_get_msglevel(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ return intf->msg_enable;
+}
+
+static void bcmasp_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ intf->msg_enable = level;
+}
+
+#define BCMASP_SUPPORTED_WAKE (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_FILTER)
+static void bcmasp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ wol->supported = BCMASP_SUPPORTED_WAKE;
+ wol->wolopts = intf->wolopts;
+ memset(wol->sopass, 0, sizeof(wol->sopass));
+
+ if (wol->wolopts & WAKE_MAGICSECURE)
+ memcpy(wol->sopass, intf->sopass, sizeof(intf->sopass));
+}
+
+static int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct bcmasp_priv *priv = intf->parent;
+ struct device *kdev = &priv->pdev->dev;
+
+ if (!device_can_wakeup(kdev))
+ return -EOPNOTSUPP;
+
+ /* Interface Specific */
+ intf->wolopts = wol->wolopts;
+ if (intf->wolopts & WAKE_MAGICSECURE)
+ memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass));
+
+ mutex_lock(&priv->wol_lock);
+ priv->enable_wol(intf, !!intf->wolopts);
+ mutex_unlock(&priv->wol_lock);
+
+ return 0;
+}
+
+static int bcmasp_flow_insert(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct bcmasp_net_filter *nfilter;
+ u32 loc = cmd->fs.location;
+ bool wake = false;
+
+ if (cmd->fs.ring_cookie == RX_CLS_FLOW_WAKE)
+ wake = true;
+
+ /* Currently only supports WAKE filters */
+ if (!wake)
+ return -EOPNOTSUPP;
+
+ switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+ case ETHER_FLOW:
+ case IP_USER_FLOW:
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Check if filter already exists */
+ if (bcmasp_netfilt_check_dup(intf, &cmd->fs))
+ return -EINVAL;
+
+ nfilter = bcmasp_netfilt_get_init(intf, loc, wake, true);
+ if (IS_ERR(nfilter))
+ return PTR_ERR(nfilter);
+
+ /* Return the location where we did insert the filter */
+ cmd->fs.location = nfilter->hw_index;
+ memcpy(&nfilter->fs, &cmd->fs, sizeof(struct ethtool_rx_flow_spec));
+
+ /* Since we only support wake filters, defer register programming till
+ * suspend time.
+ */
+ return 0;
+}
+
+static int bcmasp_flow_delete(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct bcmasp_net_filter *nfilter;
+
+ nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
+ if (IS_ERR(nfilter))
+ return PTR_ERR(nfilter);
+
+ bcmasp_netfilt_release(intf, nfilter);
+
+ return 0;
+}
+
+static int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd)
+{
+ struct bcmasp_net_filter *nfilter;
+
+ nfilter = bcmasp_netfilt_get_init(intf, cmd->fs.location, false, false);
+ if (IS_ERR(nfilter))
+ return PTR_ERR(nfilter);
+
+ memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs));
+
+ cmd->data = NUM_NET_FILTERS;
+
+ return 0;
+}
+
+static int bcmasp_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ mutex_lock(&intf->parent->net_lock);
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXCLSRLINS:
+ ret = bcmasp_flow_insert(dev, cmd);
+ break;
+ case ETHTOOL_SRXCLSRLDEL:
+ ret = bcmasp_flow_delete(dev, cmd);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&intf->parent->net_lock);
+
+ return ret;
+}
+
+static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ int err = 0;
+
+ mutex_lock(&intf->parent->net_lock);
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXCLSRLCNT:
+ cmd->rule_cnt = bcmasp_netfilt_get_active(intf);
+ /* We support specifying rule locations */
+ cmd->data |= RX_CLS_LOC_SPECIAL;
+ break;
+ case ETHTOOL_GRXCLSRULE:
+ err = bcmasp_flow_get(intf, cmd);
+ break;
+ case ETHTOOL_GRXCLSRLALL:
+ bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt);
+ cmd->data = NUM_NET_FILTERS;
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ mutex_unlock(&intf->parent->net_lock);
+
+ return err;
+}
+
+void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable)
+{
+ u32 reg;
+
+ reg = umac_rl(intf, UMC_EEE_CTRL);
+ if (enable)
+ reg |= EEE_EN;
+ else
+ reg &= ~EEE_EN;
+ umac_wl(intf, reg, UMC_EEE_CTRL);
+
+ intf->eee.eee_enabled = enable;
+ intf->eee.eee_active = enable;
+}
+
+static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct ethtool_eee *p = &intf->eee;
+
+ if (!dev->phydev)
+ return -ENODEV;
+
+ e->eee_enabled = p->eee_enabled;
+ e->eee_active = p->eee_active;
+ e->tx_lpi_enabled = p->tx_lpi_enabled;
+ e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER);
+
+ return phy_ethtool_get_eee(dev->phydev, e);
+}
+
+static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct ethtool_eee *p = &intf->eee;
+ int ret;
+
+ if (!dev->phydev)
+ return -ENODEV;
+
+ if (!p->eee_enabled) {
+ bcmasp_eee_enable_set(intf, false);
+ } else {
+ ret = phy_init_eee(dev->phydev, 0);
+ if (ret) {
+ netif_err(intf, hw, dev,
+ "EEE initialization failed: %d\n", ret);
+ return ret;
+ }
+
+ umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER);
+ intf->eee.eee_active = ret >= 0;
+ intf->eee.tx_lpi_enabled = e->tx_lpi_enabled;
+ bcmasp_eee_enable_set(intf, true);
+ }
+
+ return phy_ethtool_set_eee(dev->phydev, e);
+}
+
+static void bcmasp_get_eth_mac_stats(struct net_device *dev,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ mac_stats->FramesTransmittedOK = umac_rl(intf, UMC_GTPOK);
+ mac_stats->SingleCollisionFrames = umac_rl(intf, UMC_GTSCL);
+ mac_stats->MultipleCollisionFrames = umac_rl(intf, UMC_GTMCL);
+ mac_stats->FramesReceivedOK = umac_rl(intf, UMC_GRPOK);
+ mac_stats->FrameCheckSequenceErrors = umac_rl(intf, UMC_GRFCS);
+ mac_stats->AlignmentErrors = umac_rl(intf, UMC_GRALN);
+ mac_stats->OctetsTransmittedOK = umac_rl(intf, UMC_GTBYT);
+ mac_stats->FramesWithDeferredXmissions = umac_rl(intf, UMC_GTDRF);
+ mac_stats->LateCollisions = umac_rl(intf, UMC_GTLCL);
+ mac_stats->FramesAbortedDueToXSColls = umac_rl(intf, UMC_GTXCL);
+ mac_stats->OctetsReceivedOK = umac_rl(intf, UMC_GRBYT);
+ mac_stats->MulticastFramesXmittedOK = umac_rl(intf, UMC_GTMCA);
+ mac_stats->BroadcastFramesXmittedOK = umac_rl(intf, UMC_GTBCA);
+ mac_stats->FramesWithExcessiveDeferral = umac_rl(intf, UMC_GTEDF);
+ mac_stats->MulticastFramesReceivedOK = umac_rl(intf, UMC_GRMCA);
+ mac_stats->BroadcastFramesReceivedOK = umac_rl(intf, UMC_GRBCA);
+}
+
+static const struct ethtool_rmon_hist_range bcmasp_rmon_ranges[] = {
+ { 0, 64},
+ { 65, 127},
+ { 128, 255},
+ { 256, 511},
+ { 512, 1023},
+ { 1024, 1518},
+ { 1519, 1522},
+ {}
+};
+
+static void bcmasp_get_rmon_stats(struct net_device *dev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ *ranges = bcmasp_rmon_ranges;
+
+ rmon_stats->undersize_pkts = umac_rl(intf, UMC_RRUND);
+ rmon_stats->oversize_pkts = umac_rl(intf, UMC_GROVR);
+ rmon_stats->fragments = umac_rl(intf, UMC_RRFRG);
+ rmon_stats->jabbers = umac_rl(intf, UMC_GRJBR);
+
+ rmon_stats->hist[0] = umac_rl(intf, UMC_GR64);
+ rmon_stats->hist[1] = umac_rl(intf, UMC_GR127);
+ rmon_stats->hist[2] = umac_rl(intf, UMC_GR255);
+ rmon_stats->hist[3] = umac_rl(intf, UMC_GR511);
+ rmon_stats->hist[4] = umac_rl(intf, UMC_GR1023);
+ rmon_stats->hist[5] = umac_rl(intf, UMC_GR1518);
+ rmon_stats->hist[6] = umac_rl(intf, UMC_GRMGV);
+
+ rmon_stats->hist_tx[0] = umac_rl(intf, UMC_TR64);
+ rmon_stats->hist_tx[1] = umac_rl(intf, UMC_TR127);
+ rmon_stats->hist_tx[2] = umac_rl(intf, UMC_TR255);
+ rmon_stats->hist_tx[3] = umac_rl(intf, UMC_TR511);
+ rmon_stats->hist_tx[4] = umac_rl(intf, UMC_TR1023);
+ rmon_stats->hist_tx[5] = umac_rl(intf, UMC_TR1518);
+ rmon_stats->hist_tx[6] = umac_rl(intf, UMC_TRMGV);
+}
+
+static void bcmasp_get_eth_ctrl_stats(struct net_device *dev,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ ctrl_stats->MACControlFramesTransmitted = umac_rl(intf, UMC_GTXCF);
+ ctrl_stats->MACControlFramesReceived = umac_rl(intf, UMC_GRXCF);
+ ctrl_stats->UnsupportedOpcodesReceived = umac_rl(intf, UMC_GRXUO);
+}
+
+const struct ethtool_ops bcmasp_ethtool_ops = {
+ .get_drvinfo = bcmasp_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_msglevel = bcmasp_get_msglevel,
+ .set_msglevel = bcmasp_set_msglevel,
+ .get_wol = bcmasp_get_wol,
+ .set_wol = bcmasp_set_wol,
+ .get_rxnfc = bcmasp_get_rxnfc,
+ .set_rxnfc = bcmasp_set_rxnfc,
+ .set_eee = bcmasp_set_eee,
+ .get_eee = bcmasp_get_eee,
+ .get_eth_mac_stats = bcmasp_get_eth_mac_stats,
+ .get_rmon_stats = bcmasp_get_rmon_stats,
+ .get_eth_ctrl_stats = bcmasp_get_eth_ctrl_stats,
+ .get_strings = bcmasp_get_strings,
+ .get_ethtool_stats = bcmasp_get_ethtool_stats,
+ .get_sset_count = bcmasp_get_sset_count,
+};
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
new file mode 100644
index 000000000000..53e542881255
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
@@ -0,0 +1,1415 @@
+// SPDX-License-Identifier: GPL-2.0
+#define pr_fmt(fmt) "bcmasp_intf: " fmt
+
+#include <asm/byteorder.h>
+#include <linux/brcmphy.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/ptp_classify.h>
+#include <linux/platform_device.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+
+#include "bcmasp.h"
+#include "bcmasp_intf_defs.h"
+
+static int incr_ring(int index, int ring_count)
+{
+ index++;
+ if (index == ring_count)
+ return 0;
+
+ return index;
+}
+
+/* Points to last byte of descriptor */
+static dma_addr_t incr_last_byte(dma_addr_t addr, dma_addr_t beg,
+ int ring_count)
+{
+ dma_addr_t end = beg + (ring_count * DESC_SIZE);
+
+ addr += DESC_SIZE;
+ if (addr > end)
+ return beg + DESC_SIZE - 1;
+
+ return addr;
+}
+
+/* Points to first byte of descriptor */
+static dma_addr_t incr_first_byte(dma_addr_t addr, dma_addr_t beg,
+ int ring_count)
+{
+ dma_addr_t end = beg + (ring_count * DESC_SIZE);
+
+ addr += DESC_SIZE;
+ if (addr >= end)
+ return beg;
+
+ return addr;
+}
+
+static void bcmasp_enable_tx(struct bcmasp_intf *intf, int en)
+{
+ if (en) {
+ tx_spb_ctrl_wl(intf, TX_SPB_CTRL_ENABLE_EN, TX_SPB_CTRL_ENABLE);
+ tx_epkt_core_wl(intf, (TX_EPKT_C_CFG_MISC_EN |
+ TX_EPKT_C_CFG_MISC_PT |
+ (intf->port << TX_EPKT_C_CFG_MISC_PS_SHIFT)),
+ TX_EPKT_C_CFG_MISC);
+ } else {
+ tx_spb_ctrl_wl(intf, 0x0, TX_SPB_CTRL_ENABLE);
+ tx_epkt_core_wl(intf, 0x0, TX_EPKT_C_CFG_MISC);
+ }
+}
+
+static void bcmasp_enable_rx(struct bcmasp_intf *intf, int en)
+{
+ if (en)
+ rx_edpkt_cfg_wl(intf, RX_EDPKT_CFG_ENABLE_EN,
+ RX_EDPKT_CFG_ENABLE);
+ else
+ rx_edpkt_cfg_wl(intf, 0x0, RX_EDPKT_CFG_ENABLE);
+}
+
+static void bcmasp_set_rx_mode(struct net_device *dev)
+{
+ unsigned char mask[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ int ret;
+
+ spin_lock_bh(&intf->parent->mda_lock);
+
+ bcmasp_disable_all_filters(intf);
+
+ if (dev->flags & IFF_PROMISC)
+ goto set_promisc;
+
+ bcmasp_set_promisc(intf, 0);
+
+ bcmasp_set_broad(intf, 1);
+
+ bcmasp_set_oaddr(intf, dev->dev_addr, 1);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ bcmasp_set_allmulti(intf, 1);
+ } else {
+ bcmasp_set_allmulti(intf, 0);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ ret = bcmasp_set_en_mda_filter(intf, ha->addr, mask);
+ if (ret) {
+ intf->mib.mc_filters_full_cnt++;
+ goto set_promisc;
+ }
+ }
+ }
+
+ netdev_for_each_uc_addr(ha, dev) {
+ ret = bcmasp_set_en_mda_filter(intf, ha->addr, mask);
+ if (ret) {
+ intf->mib.uc_filters_full_cnt++;
+ goto set_promisc;
+ }
+ }
+
+ spin_unlock_bh(&intf->parent->mda_lock);
+ return;
+
+set_promisc:
+ bcmasp_set_promisc(intf, 1);
+ intf->mib.promisc_filters_cnt++;
+
+ /* disable all filters used by this port */
+ bcmasp_disable_all_filters(intf);
+
+ spin_unlock_bh(&intf->parent->mda_lock);
+}
+
+static void bcmasp_clean_txcb(struct bcmasp_intf *intf, int index)
+{
+ struct bcmasp_tx_cb *txcb = &intf->tx_cbs[index];
+
+ txcb->skb = NULL;
+ dma_unmap_addr_set(txcb, dma_addr, 0);
+ dma_unmap_len_set(txcb, dma_len, 0);
+ txcb->last = false;
+}
+
+static int tx_spb_ring_full(struct bcmasp_intf *intf, int cnt)
+{
+ int next_index, i;
+
+ /* Check if we have enough room for cnt descriptors */
+ for (i = 0; i < cnt; i++) {
+ next_index = incr_ring(intf->tx_spb_index, DESC_RING_COUNT);
+ if (next_index == intf->tx_spb_clean_index)
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct sk_buff *bcmasp_csum_offload(struct net_device *dev,
+ struct sk_buff *skb,
+ bool *csum_hw)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ u32 header = 0, header2 = 0, epkt = 0;
+ struct bcmasp_pkt_offload *offload;
+ unsigned int header_cnt = 0;
+ u8 ip_proto;
+ int ret;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return skb;
+
+ ret = skb_cow_head(skb, sizeof(*offload));
+ if (ret < 0) {
+ intf->mib.tx_realloc_offload_failed++;
+ goto help;
+ }
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ header |= PKT_OFFLOAD_HDR_SIZE_2((ip_hdrlen(skb) >> 8) & 0xf);
+ header2 |= PKT_OFFLOAD_HDR2_SIZE_2(ip_hdrlen(skb) & 0xff);
+ epkt |= PKT_OFFLOAD_EPKT_IP(0) | PKT_OFFLOAD_EPKT_CSUM_L2;
+ ip_proto = ip_hdr(skb)->protocol;
+ header_cnt += 2;
+ break;
+ case htons(ETH_P_IPV6):
+ header |= PKT_OFFLOAD_HDR_SIZE_2((IP6_HLEN >> 8) & 0xf);
+ header2 |= PKT_OFFLOAD_HDR2_SIZE_2(IP6_HLEN & 0xff);
+ epkt |= PKT_OFFLOAD_EPKT_IP(1) | PKT_OFFLOAD_EPKT_CSUM_L2;
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ header_cnt += 2;
+ break;
+ default:
+ goto help;
+ }
+
+ switch (ip_proto) {
+ case IPPROTO_TCP:
+ header2 |= PKT_OFFLOAD_HDR2_SIZE_3(tcp_hdrlen(skb));
+ epkt |= PKT_OFFLOAD_EPKT_TP(0) | PKT_OFFLOAD_EPKT_CSUM_L3;
+ header_cnt++;
+ break;
+ case IPPROTO_UDP:
+ header2 |= PKT_OFFLOAD_HDR2_SIZE_3(UDP_HLEN);
+ epkt |= PKT_OFFLOAD_EPKT_TP(1) | PKT_OFFLOAD_EPKT_CSUM_L3;
+ header_cnt++;
+ break;
+ default:
+ goto help;
+ }
+
+ offload = (struct bcmasp_pkt_offload *)skb_push(skb, sizeof(*offload));
+
+ header |= PKT_OFFLOAD_HDR_OP | PKT_OFFLOAD_HDR_COUNT(header_cnt) |
+ PKT_OFFLOAD_HDR_SIZE_1(ETH_HLEN);
+ epkt |= PKT_OFFLOAD_EPKT_OP;
+
+ offload->nop = htonl(PKT_OFFLOAD_NOP);
+ offload->header = htonl(header);
+ offload->header2 = htonl(header2);
+ offload->epkt = htonl(epkt);
+ offload->end = htonl(PKT_OFFLOAD_END_OP);
+ *csum_hw = true;
+
+ return skb;
+
+help:
+ skb_checksum_help(skb);
+
+ return skb;
+}
+
+static unsigned long bcmasp_rx_edpkt_dma_rq(struct bcmasp_intf *intf)
+{
+ return rx_edpkt_dma_rq(intf, RX_EDPKT_DMA_VALID);
+}
+
+static void bcmasp_rx_edpkt_cfg_wq(struct bcmasp_intf *intf, dma_addr_t addr)
+{
+ rx_edpkt_cfg_wq(intf, addr, RX_EDPKT_RING_BUFFER_READ);
+}
+
+static void bcmasp_rx_edpkt_dma_wq(struct bcmasp_intf *intf, dma_addr_t addr)
+{
+ rx_edpkt_dma_wq(intf, addr, RX_EDPKT_DMA_READ);
+}
+
+static unsigned long bcmasp_tx_spb_dma_rq(struct bcmasp_intf *intf)
+{
+ return tx_spb_dma_rq(intf, TX_SPB_DMA_READ);
+}
+
+static void bcmasp_tx_spb_dma_wq(struct bcmasp_intf *intf, dma_addr_t addr)
+{
+ tx_spb_dma_wq(intf, addr, TX_SPB_DMA_VALID);
+}
+
+static const struct bcmasp_intf_ops bcmasp_intf_ops = {
+ .rx_desc_read = bcmasp_rx_edpkt_dma_rq,
+ .rx_buffer_write = bcmasp_rx_edpkt_cfg_wq,
+ .rx_desc_write = bcmasp_rx_edpkt_dma_wq,
+ .tx_read = bcmasp_tx_spb_dma_rq,
+ .tx_write = bcmasp_tx_spb_dma_wq,
+};
+
+static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ unsigned int total_bytes, size;
+ int spb_index, nr_frags, i, j;
+ struct bcmasp_tx_cb *txcb;
+ dma_addr_t mapping, valid;
+ struct bcmasp_desc *desc;
+ bool csum_hw = false;
+ struct device *kdev;
+ skb_frag_t *frag;
+
+ kdev = &intf->parent->pdev->dev;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ if (tx_spb_ring_full(intf, nr_frags + 1)) {
+ netif_stop_queue(dev);
+ if (net_ratelimit())
+ netdev_err(dev, "Tx Ring Full!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Save skb len before adding csum offload header */
+ total_bytes = skb->len;
+ skb = bcmasp_csum_offload(dev, skb, &csum_hw);
+ if (!skb)
+ return NETDEV_TX_OK;
+
+ spb_index = intf->tx_spb_index;
+ valid = intf->tx_spb_dma_valid;
+ for (i = 0; i <= nr_frags; i++) {
+ if (!i) {
+ size = skb_headlen(skb);
+ if (!nr_frags && size < (ETH_ZLEN + ETH_FCS_LEN)) {
+ if (skb_put_padto(skb, ETH_ZLEN + ETH_FCS_LEN))
+ return NETDEV_TX_OK;
+ size = skb->len;
+ }
+ mapping = dma_map_single(kdev, skb->data, size,
+ DMA_TO_DEVICE);
+ } else {
+ frag = &skb_shinfo(skb)->frags[i - 1];
+ size = skb_frag_size(frag);
+ mapping = skb_frag_dma_map(kdev, frag, 0, size,
+ DMA_TO_DEVICE);
+ }
+
+ if (dma_mapping_error(kdev, mapping)) {
+ intf->mib.tx_dma_failed++;
+ spb_index = intf->tx_spb_index;
+ for (j = 0; j < i; j++) {
+ bcmasp_clean_txcb(intf, spb_index);
+ spb_index = incr_ring(spb_index,
+ DESC_RING_COUNT);
+ }
+ /* Rewind so we do not have a hole */
+ spb_index = intf->tx_spb_index;
+ return NETDEV_TX_OK;
+ }
+
+ txcb = &intf->tx_cbs[spb_index];
+ desc = &intf->tx_spb_cpu[spb_index];
+ memset(desc, 0, sizeof(*desc));
+ txcb->skb = skb;
+ txcb->bytes_sent = total_bytes;
+ dma_unmap_addr_set(txcb, dma_addr, mapping);
+ dma_unmap_len_set(txcb, dma_len, size);
+ if (!i) {
+ desc->flags |= DESC_SOF;
+ if (csum_hw)
+ desc->flags |= DESC_EPKT_CMD;
+ }
+
+ if (i == nr_frags) {
+ desc->flags |= DESC_EOF;
+ txcb->last = true;
+ }
+
+ desc->buf = mapping;
+ desc->size = size;
+ desc->flags |= DESC_INT_EN;
+
+ netif_dbg(intf, tx_queued, dev,
+ "%s dma_buf=%pad dma_len=0x%x flags=0x%x index=0x%x\n",
+ __func__, &mapping, desc->size, desc->flags,
+ spb_index);
+
+ spb_index = incr_ring(spb_index, DESC_RING_COUNT);
+ valid = incr_last_byte(valid, intf->tx_spb_dma_addr,
+ DESC_RING_COUNT);
+ }
+
+ /* Ensure all descriptors have been written to DRAM for the
+ * hardware to see up-to-date contents.
+ */
+ wmb();
+
+ intf->tx_spb_index = spb_index;
+ intf->tx_spb_dma_valid = valid;
+ bcmasp_intf_tx_write(intf, intf->tx_spb_dma_valid);
+
+ if (tx_spb_ring_full(intf, MAX_SKB_FRAGS + 1))
+ netif_stop_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static void bcmasp_netif_start(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ bcmasp_set_rx_mode(dev);
+ napi_enable(&intf->tx_napi);
+ napi_enable(&intf->rx_napi);
+
+ bcmasp_enable_rx_irq(intf, 1);
+ bcmasp_enable_tx_irq(intf, 1);
+
+ phy_start(dev->phydev);
+}
+
+static void umac_reset(struct bcmasp_intf *intf)
+{
+ umac_wl(intf, 0x0, UMC_CMD);
+ umac_wl(intf, UMC_CMD_SW_RESET, UMC_CMD);
+ usleep_range(10, 100);
+ umac_wl(intf, 0x0, UMC_CMD);
+}
+
+static void umac_set_hw_addr(struct bcmasp_intf *intf,
+ const unsigned char *addr)
+{
+ u32 mac0 = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) |
+ addr[3];
+ u32 mac1 = (addr[4] << 8) | addr[5];
+
+ umac_wl(intf, mac0, UMC_MAC0);
+ umac_wl(intf, mac1, UMC_MAC1);
+}
+
+static void umac_enable_set(struct bcmasp_intf *intf, u32 mask,
+ unsigned int enable)
+{
+ u32 reg;
+
+ reg = umac_rl(intf, UMC_CMD);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ umac_wl(intf, reg, UMC_CMD);
+
+ /* UniMAC stops on a packet boundary, wait for a full-sized packet
+ * to be processed (1 msec).
+ */
+ if (enable == 0)
+ usleep_range(1000, 2000);
+}
+
+static void umac_init(struct bcmasp_intf *intf)
+{
+ umac_wl(intf, 0x800, UMC_FRM_LEN);
+ umac_wl(intf, 0xffff, UMC_PAUSE_CNTRL);
+ umac_wl(intf, 0x800, UMC_RX_MAX_PKT_SZ);
+ umac_enable_set(intf, UMC_CMD_PROMISC, 1);
+}
+
+static int bcmasp_tx_poll(struct napi_struct *napi, int budget)
+{
+ struct bcmasp_intf *intf =
+ container_of(napi, struct bcmasp_intf, tx_napi);
+ struct bcmasp_intf_stats64 *stats = &intf->stats64;
+ struct device *kdev = &intf->parent->pdev->dev;
+ unsigned long read, released = 0;
+ struct bcmasp_tx_cb *txcb;
+ struct bcmasp_desc *desc;
+ dma_addr_t mapping;
+
+ read = bcmasp_intf_tx_read(intf);
+ while (intf->tx_spb_dma_read != read) {
+ txcb = &intf->tx_cbs[intf->tx_spb_clean_index];
+ mapping = dma_unmap_addr(txcb, dma_addr);
+
+ dma_unmap_single(kdev, mapping,
+ dma_unmap_len(txcb, dma_len),
+ DMA_TO_DEVICE);
+
+ if (txcb->last) {
+ dev_consume_skb_any(txcb->skb);
+
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->tx_packets);
+ u64_stats_add(&stats->tx_bytes, txcb->bytes_sent);
+ u64_stats_update_end(&stats->syncp);
+ }
+
+ desc = &intf->tx_spb_cpu[intf->tx_spb_clean_index];
+
+ netif_dbg(intf, tx_done, intf->ndev,
+ "%s dma_buf=%pad dma_len=0x%x flags=0x%x c_index=0x%x\n",
+ __func__, &mapping, desc->size, desc->flags,
+ intf->tx_spb_clean_index);
+
+ bcmasp_clean_txcb(intf, intf->tx_spb_clean_index);
+ released++;
+
+ intf->tx_spb_clean_index = incr_ring(intf->tx_spb_clean_index,
+ DESC_RING_COUNT);
+ intf->tx_spb_dma_read = incr_first_byte(intf->tx_spb_dma_read,
+ intf->tx_spb_dma_addr,
+ DESC_RING_COUNT);
+ }
+
+ /* Ensure all descriptors have been written to DRAM for the hardware
+ * to see updated contents.
+ */
+ wmb();
+
+ napi_complete(&intf->tx_napi);
+
+ bcmasp_enable_tx_irq(intf, 1);
+
+ if (released)
+ netif_wake_queue(intf->ndev);
+
+ return 0;
+}
+
+static int bcmasp_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct bcmasp_intf *intf =
+ container_of(napi, struct bcmasp_intf, rx_napi);
+ struct bcmasp_intf_stats64 *stats = &intf->stats64;
+ struct device *kdev = &intf->parent->pdev->dev;
+ unsigned long processed = 0;
+ struct bcmasp_desc *desc;
+ struct sk_buff *skb;
+ dma_addr_t valid;
+ void *data;
+ u64 flags;
+ u32 len;
+
+ valid = bcmasp_intf_rx_desc_read(intf) + 1;
+ if (valid == intf->rx_edpkt_dma_addr + DESC_RING_SIZE)
+ valid = intf->rx_edpkt_dma_addr;
+
+ while ((processed < budget) && (valid != intf->rx_edpkt_dma_read)) {
+ desc = &intf->rx_edpkt_cpu[intf->rx_edpkt_index];
+
+ /* Ensure that descriptor has been fully written to DRAM by
+ * hardware before reading by the CPU
+ */
+ rmb();
+
+ /* Calculate virt addr by offsetting from physical addr */
+ data = intf->rx_ring_cpu +
+ (DESC_ADDR(desc->buf) - intf->rx_ring_dma);
+
+ flags = DESC_FLAGS(desc->buf);
+ if (unlikely(flags & (DESC_CRC_ERR | DESC_RX_SYM_ERR))) {
+ if (net_ratelimit()) {
+ netif_err(intf, rx_status, intf->ndev,
+ "flags=0x%llx\n", flags);
+ }
+
+ u64_stats_update_begin(&stats->syncp);
+ if (flags & DESC_CRC_ERR)
+ u64_stats_inc(&stats->rx_crc_errs);
+ if (flags & DESC_RX_SYM_ERR)
+ u64_stats_inc(&stats->rx_sym_errs);
+ u64_stats_update_end(&stats->syncp);
+
+ goto next;
+ }
+
+ dma_sync_single_for_cpu(kdev, DESC_ADDR(desc->buf), desc->size,
+ DMA_FROM_DEVICE);
+
+ len = desc->size;
+
+ skb = napi_alloc_skb(napi, len);
+ if (!skb) {
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_dropped);
+ u64_stats_update_end(&stats->syncp);
+ intf->mib.alloc_rx_skb_failed++;
+
+ goto next;
+ }
+
+ skb_put(skb, len);
+ memcpy(skb->data, data, len);
+
+ skb_pull(skb, 2);
+ len -= 2;
+ if (likely(intf->crc_fwd)) {
+ skb_trim(skb, len - ETH_FCS_LEN);
+ len -= ETH_FCS_LEN;
+ }
+
+ if ((intf->ndev->features & NETIF_F_RXCSUM) &&
+ (desc->buf & DESC_CHKSUM))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ skb->protocol = eth_type_trans(skb, intf->ndev);
+
+ napi_gro_receive(napi, skb);
+
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_packets);
+ u64_stats_add(&stats->rx_bytes, len);
+ u64_stats_update_end(&stats->syncp);
+
+next:
+ bcmasp_intf_rx_buffer_write(intf, (DESC_ADDR(desc->buf) +
+ desc->size));
+
+ processed++;
+ intf->rx_edpkt_dma_read =
+ incr_first_byte(intf->rx_edpkt_dma_read,
+ intf->rx_edpkt_dma_addr,
+ DESC_RING_COUNT);
+ intf->rx_edpkt_index = incr_ring(intf->rx_edpkt_index,
+ DESC_RING_COUNT);
+ }
+
+ bcmasp_intf_rx_desc_write(intf, intf->rx_edpkt_dma_read);
+
+ if (processed < budget) {
+ napi_complete_done(&intf->rx_napi, processed);
+ bcmasp_enable_rx_irq(intf, 1);
+ }
+
+ return processed;
+}
+
+static void bcmasp_adj_link(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct phy_device *phydev = dev->phydev;
+ u32 cmd_bits = 0, reg;
+ int changed = 0;
+
+ if (intf->old_link != phydev->link) {
+ changed = 1;
+ intf->old_link = phydev->link;
+ }
+
+ if (intf->old_duplex != phydev->duplex) {
+ changed = 1;
+ intf->old_duplex = phydev->duplex;
+ }
+
+ switch (phydev->speed) {
+ case SPEED_2500:
+ cmd_bits = UMC_CMD_SPEED_2500;
+ break;
+ case SPEED_1000:
+ cmd_bits = UMC_CMD_SPEED_1000;
+ break;
+ case SPEED_100:
+ cmd_bits = UMC_CMD_SPEED_100;
+ break;
+ case SPEED_10:
+ cmd_bits = UMC_CMD_SPEED_10;
+ break;
+ default:
+ break;
+ }
+ cmd_bits <<= UMC_CMD_SPEED_SHIFT;
+
+ if (phydev->duplex == DUPLEX_HALF)
+ cmd_bits |= UMC_CMD_HD_EN;
+
+ if (intf->old_pause != phydev->pause) {
+ changed = 1;
+ intf->old_pause = phydev->pause;
+ }
+
+ if (!phydev->pause)
+ cmd_bits |= UMC_CMD_RX_PAUSE_IGNORE | UMC_CMD_TX_PAUSE_IGNORE;
+
+ if (!changed)
+ return;
+
+ if (phydev->link) {
+ reg = umac_rl(intf, UMC_CMD);
+ reg &= ~((UMC_CMD_SPEED_MASK << UMC_CMD_SPEED_SHIFT) |
+ UMC_CMD_HD_EN | UMC_CMD_RX_PAUSE_IGNORE |
+ UMC_CMD_TX_PAUSE_IGNORE);
+ reg |= cmd_bits;
+ umac_wl(intf, reg, UMC_CMD);
+
+ intf->eee.eee_active = phy_init_eee(phydev, 0) >= 0;
+ bcmasp_eee_enable_set(intf, intf->eee.eee_active);
+ }
+
+ reg = rgmii_rl(intf, RGMII_OOB_CNTRL);
+ if (phydev->link)
+ reg |= RGMII_LINK;
+ else
+ reg &= ~RGMII_LINK;
+ rgmii_wl(intf, reg, RGMII_OOB_CNTRL);
+
+ if (changed)
+ phy_print_status(phydev);
+}
+
+static int bcmasp_init_rx(struct bcmasp_intf *intf)
+{
+ struct device *kdev = &intf->parent->pdev->dev;
+ struct page *buffer_pg;
+ dma_addr_t dma;
+ void *p;
+ u32 reg;
+ int ret;
+
+ intf->rx_buf_order = get_order(RING_BUFFER_SIZE);
+ buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order);
+
+ dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(kdev, dma)) {
+ __free_pages(buffer_pg, intf->rx_buf_order);
+ return -ENOMEM;
+ }
+ intf->rx_ring_cpu = page_to_virt(buffer_pg);
+ intf->rx_ring_dma = dma;
+ intf->rx_ring_dma_valid = intf->rx_ring_dma + RING_BUFFER_SIZE - 1;
+
+ p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->rx_edpkt_dma_addr,
+ GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto free_rx_ring;
+ }
+ intf->rx_edpkt_cpu = p;
+
+ netif_napi_add(intf->ndev, &intf->rx_napi, bcmasp_rx_poll);
+
+ intf->rx_edpkt_dma_read = intf->rx_edpkt_dma_addr;
+ intf->rx_edpkt_index = 0;
+
+ /* Make sure channels are disabled */
+ rx_edpkt_cfg_wl(intf, 0x0, RX_EDPKT_CFG_ENABLE);
+
+ /* Rx SPB */
+ rx_edpkt_cfg_wq(intf, intf->rx_ring_dma, RX_EDPKT_RING_BUFFER_READ);
+ rx_edpkt_cfg_wq(intf, intf->rx_ring_dma, RX_EDPKT_RING_BUFFER_WRITE);
+ rx_edpkt_cfg_wq(intf, intf->rx_ring_dma, RX_EDPKT_RING_BUFFER_BASE);
+ rx_edpkt_cfg_wq(intf, intf->rx_ring_dma_valid,
+ RX_EDPKT_RING_BUFFER_END);
+ rx_edpkt_cfg_wq(intf, intf->rx_ring_dma_valid,
+ RX_EDPKT_RING_BUFFER_VALID);
+
+ /* EDPKT */
+ rx_edpkt_cfg_wl(intf, (RX_EDPKT_CFG_CFG0_RBUF_4K <<
+ RX_EDPKT_CFG_CFG0_DBUF_SHIFT) |
+ (RX_EDPKT_CFG_CFG0_64_ALN <<
+ RX_EDPKT_CFG_CFG0_BALN_SHIFT) |
+ (RX_EDPKT_CFG_CFG0_EFRM_STUF),
+ RX_EDPKT_CFG_CFG0);
+ rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_WRITE);
+ rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_READ);
+ rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_BASE);
+ rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1),
+ RX_EDPKT_DMA_END);
+ rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1),
+ RX_EDPKT_DMA_VALID);
+
+ reg = UMAC2FB_CFG_DEFAULT_EN |
+ ((intf->channel + 11) << UMAC2FB_CFG_CHID_SHIFT);
+ reg |= (0xd << UMAC2FB_CFG_OK_SEND_SHIFT);
+ umac2fb_wl(intf, reg, UMAC2FB_CFG);
+
+ return 0;
+
+free_rx_ring:
+ dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order);
+
+ return ret;
+}
+
+static void bcmasp_reclaim_free_all_rx(struct bcmasp_intf *intf)
+{
+ struct device *kdev = &intf->parent->pdev->dev;
+
+ dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu,
+ intf->rx_edpkt_dma_addr);
+ dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order);
+}
+
+static int bcmasp_init_tx(struct bcmasp_intf *intf)
+{
+ struct device *kdev = &intf->parent->pdev->dev;
+ void *p;
+ int ret;
+
+ p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->tx_spb_dma_addr,
+ GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ intf->tx_spb_cpu = p;
+ intf->tx_spb_dma_valid = intf->tx_spb_dma_addr + DESC_RING_SIZE - 1;
+ intf->tx_spb_dma_read = intf->tx_spb_dma_addr;
+
+ intf->tx_cbs = kcalloc(DESC_RING_COUNT, sizeof(struct bcmasp_tx_cb),
+ GFP_KERNEL);
+ if (!intf->tx_cbs) {
+ ret = -ENOMEM;
+ goto free_tx_spb;
+ }
+
+ intf->tx_spb_index = 0;
+ intf->tx_spb_clean_index = 0;
+
+ netif_napi_add_tx(intf->ndev, &intf->tx_napi, bcmasp_tx_poll);
+
+ /* Make sure channels are disabled */
+ tx_spb_ctrl_wl(intf, 0x0, TX_SPB_CTRL_ENABLE);
+ tx_epkt_core_wl(intf, 0x0, TX_EPKT_C_CFG_MISC);
+
+ /* Tx SPB */
+ tx_spb_ctrl_wl(intf, ((intf->channel + 8) << TX_SPB_CTRL_XF_BID_SHIFT),
+ TX_SPB_CTRL_XF_CTRL2);
+ tx_pause_ctrl_wl(intf, (1 << (intf->channel + 8)), TX_PAUSE_MAP_VECTOR);
+ tx_spb_top_wl(intf, 0x1e, TX_SPB_TOP_BLKOUT);
+ tx_spb_top_wl(intf, 0x0, TX_SPB_TOP_SPRE_BW_CTRL);
+
+ tx_spb_dma_wq(intf, intf->tx_spb_dma_addr, TX_SPB_DMA_READ);
+ tx_spb_dma_wq(intf, intf->tx_spb_dma_addr, TX_SPB_DMA_BASE);
+ tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_END);
+ tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_VALID);
+
+ return 0;
+
+free_tx_spb:
+ dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu,
+ intf->tx_spb_dma_addr);
+
+ return ret;
+}
+
+static void bcmasp_reclaim_free_all_tx(struct bcmasp_intf *intf)
+{
+ struct device *kdev = &intf->parent->pdev->dev;
+
+ /* Free descriptors */
+ dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu,
+ intf->tx_spb_dma_addr);
+
+ /* Free cbs */
+ kfree(intf->tx_cbs);
+}
+
+static void bcmasp_ephy_enable_set(struct bcmasp_intf *intf, bool enable)
+{
+ u32 mask = RGMII_EPHY_CFG_IDDQ_BIAS | RGMII_EPHY_CFG_EXT_PWRDOWN |
+ RGMII_EPHY_CFG_IDDQ_GLOBAL;
+ u32 reg;
+
+ reg = rgmii_rl(intf, RGMII_EPHY_CNTRL);
+ if (enable) {
+ reg &= ~RGMII_EPHY_CK25_DIS;
+ rgmii_wl(intf, reg, RGMII_EPHY_CNTRL);
+ mdelay(1);
+
+ reg &= ~mask;
+ reg |= RGMII_EPHY_RESET;
+ rgmii_wl(intf, reg, RGMII_EPHY_CNTRL);
+ mdelay(1);
+
+ reg &= ~RGMII_EPHY_RESET;
+ } else {
+ reg |= mask | RGMII_EPHY_RESET;
+ rgmii_wl(intf, reg, RGMII_EPHY_CNTRL);
+ mdelay(1);
+ reg |= RGMII_EPHY_CK25_DIS;
+ }
+ rgmii_wl(intf, reg, RGMII_EPHY_CNTRL);
+ mdelay(1);
+
+ /* Set or clear the LED control override to avoid lighting up LEDs
+ * while the EPHY is powered off and drawing unnecessary current.
+ */
+ reg = rgmii_rl(intf, RGMII_SYS_LED_CNTRL);
+ if (enable)
+ reg &= ~RGMII_SYS_LED_CNTRL_LINK_OVRD;
+ else
+ reg |= RGMII_SYS_LED_CNTRL_LINK_OVRD;
+ rgmii_wl(intf, reg, RGMII_SYS_LED_CNTRL);
+}
+
+static void bcmasp_rgmii_mode_en_set(struct bcmasp_intf *intf, bool enable)
+{
+ u32 reg;
+
+ reg = rgmii_rl(intf, RGMII_OOB_CNTRL);
+ reg &= ~RGMII_OOB_DIS;
+ if (enable)
+ reg |= RGMII_MODE_EN;
+ else
+ reg &= ~RGMII_MODE_EN;
+ rgmii_wl(intf, reg, RGMII_OOB_CNTRL);
+}
+
+static void bcmasp_netif_deinit(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ u32 reg, timeout = 1000;
+
+ napi_disable(&intf->tx_napi);
+
+ bcmasp_enable_tx(intf, 0);
+
+ /* Flush any TX packets in the pipe */
+ tx_spb_dma_wl(intf, TX_SPB_DMA_FIFO_FLUSH, TX_SPB_DMA_FIFO_CTRL);
+ do {
+ reg = tx_spb_dma_rl(intf, TX_SPB_DMA_FIFO_STATUS);
+ if (!(reg & TX_SPB_DMA_FIFO_FLUSH))
+ break;
+ usleep_range(1000, 2000);
+ } while (timeout-- > 0);
+ tx_spb_dma_wl(intf, 0x0, TX_SPB_DMA_FIFO_CTRL);
+
+ umac_enable_set(intf, UMC_CMD_TX_EN, 0);
+
+ phy_stop(dev->phydev);
+
+ umac_enable_set(intf, UMC_CMD_RX_EN, 0);
+
+ bcmasp_flush_rx_port(intf);
+ usleep_range(1000, 2000);
+ bcmasp_enable_rx(intf, 0);
+
+ napi_disable(&intf->rx_napi);
+
+ /* Disable interrupts */
+ bcmasp_enable_tx_irq(intf, 0);
+ bcmasp_enable_rx_irq(intf, 0);
+
+ netif_napi_del(&intf->tx_napi);
+ bcmasp_reclaim_free_all_tx(intf);
+
+ netif_napi_del(&intf->rx_napi);
+ bcmasp_reclaim_free_all_rx(intf);
+}
+
+static int bcmasp_stop(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ netif_dbg(intf, ifdown, dev, "bcmasp stop\n");
+
+ /* Stop tx from updating HW */
+ netif_tx_disable(dev);
+
+ bcmasp_netif_deinit(dev);
+
+ phy_disconnect(dev->phydev);
+
+ /* Disable internal EPHY or external PHY */
+ if (intf->internal_phy)
+ bcmasp_ephy_enable_set(intf, false);
+ else
+ bcmasp_rgmii_mode_en_set(intf, false);
+
+ /* Disable the interface clocks */
+ bcmasp_core_clock_set_intf(intf, false);
+
+ clk_disable_unprepare(intf->parent->clk);
+
+ return 0;
+}
+
+static void bcmasp_configure_port(struct bcmasp_intf *intf)
+{
+ u32 reg, id_mode_dis = 0;
+
+ reg = rgmii_rl(intf, RGMII_PORT_CNTRL);
+ reg &= ~RGMII_PORT_MODE_MASK;
+
+ switch (intf->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ /* RGMII_NO_ID: TXC transitions at the same time as TXD
+ * (requires PCB or receiver-side delay)
+ * RGMII: Add 2ns delay on TXC (90 degree shift)
+ *
+ * ID is implicitly disabled for 100Mbps (RG)MII operation.
+ */
+ id_mode_dis = RGMII_ID_MODE_DIS;
+ fallthrough;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ reg |= RGMII_PORT_MODE_EXT_GPHY;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ reg |= RGMII_PORT_MODE_EXT_EPHY;
+ break;
+ default:
+ break;
+ }
+
+ if (intf->internal_phy)
+ reg |= RGMII_PORT_MODE_EPHY;
+
+ rgmii_wl(intf, reg, RGMII_PORT_CNTRL);
+
+ reg = rgmii_rl(intf, RGMII_OOB_CNTRL);
+ reg &= ~RGMII_ID_MODE_DIS;
+ reg |= id_mode_dis;
+ rgmii_wl(intf, reg, RGMII_OOB_CNTRL);
+}
+
+static int bcmasp_netif_init(struct net_device *dev, bool phy_connect)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ phy_interface_t phy_iface = intf->phy_interface;
+ u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE |
+ PHY_BRCM_DIS_TXCRXC_NOENRGY |
+ PHY_BRCM_IDDQ_SUSPEND;
+ struct phy_device *phydev = NULL;
+ int ret;
+
+ /* Always enable interface clocks */
+ bcmasp_core_clock_set_intf(intf, true);
+
+ /* Enable internal PHY or external PHY before any MAC activity */
+ if (intf->internal_phy)
+ bcmasp_ephy_enable_set(intf, true);
+ else
+ bcmasp_rgmii_mode_en_set(intf, true);
+ bcmasp_configure_port(intf);
+
+ /* This is an ugly quirk but we have not been correctly
+ * interpreting the phy_interface values and we have done that
+ * across different drivers, so at least we are consistent in
+ * our mistakes.
+ *
+ * When the Generic PHY driver is in use either the PHY has
+ * been strapped or programmed correctly by the boot loader so
+ * we should stick to our incorrect interpretation since we
+ * have validated it.
+ *
+ * Now when a dedicated PHY driver is in use, we need to
+ * reverse the meaning of the phy_interface_mode values to
+ * something that the PHY driver will interpret and act on such
+ * that we have two mistakes canceling themselves so to speak.
+ * We only do this for the two modes that GENET driver
+ * officially supports on Broadcom STB chips:
+ * PHY_INTERFACE_MODE_RGMII and PHY_INTERFACE_MODE_RGMII_TXID.
+ * Other modes are not *officially* supported with the boot
+ * loader and the scripted environment generating Device Tree
+ * blobs for those platforms.
+ *
+ * Note that internal PHY and fixed-link configurations are not
+ * affected because they use different phy_interface_t values
+ * or the Generic PHY driver.
+ */
+ switch (phy_iface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ phy_iface = PHY_INTERFACE_MODE_RGMII_ID;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ phy_iface = PHY_INTERFACE_MODE_RGMII_RXID;
+ break;
+ default:
+ break;
+ }
+
+ if (phy_connect) {
+ phydev = of_phy_connect(dev, intf->phy_dn,
+ bcmasp_adj_link, phy_flags,
+ phy_iface);
+ if (!phydev) {
+ ret = -ENODEV;
+ netdev_err(dev, "could not attach to PHY\n");
+ goto err_phy_disable;
+ }
+ } else if (!intf->wolopts) {
+ ret = phy_resume(dev->phydev);
+ if (ret)
+ goto err_phy_disable;
+ }
+
+ umac_reset(intf);
+
+ umac_init(intf);
+
+ /* Disable the UniMAC RX/TX */
+ umac_enable_set(intf, (UMC_CMD_RX_EN | UMC_CMD_TX_EN), 0);
+
+ umac_set_hw_addr(intf, dev->dev_addr);
+
+ intf->old_duplex = -1;
+ intf->old_link = -1;
+ intf->old_pause = -1;
+
+ ret = bcmasp_init_tx(intf);
+ if (ret)
+ goto err_phy_disconnect;
+
+ /* Turn on asp */
+ bcmasp_enable_tx(intf, 1);
+
+ ret = bcmasp_init_rx(intf);
+ if (ret)
+ goto err_reclaim_tx;
+
+ bcmasp_enable_rx(intf, 1);
+
+ /* Turn on UniMAC TX/RX */
+ umac_enable_set(intf, (UMC_CMD_RX_EN | UMC_CMD_TX_EN), 1);
+
+ intf->crc_fwd = !!(umac_rl(intf, UMC_CMD) & UMC_CMD_CRC_FWD);
+
+ bcmasp_netif_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+err_reclaim_tx:
+ bcmasp_reclaim_free_all_tx(intf);
+err_phy_disconnect:
+ if (phydev)
+ phy_disconnect(phydev);
+err_phy_disable:
+ if (intf->internal_phy)
+ bcmasp_ephy_enable_set(intf, false);
+ else
+ bcmasp_rgmii_mode_en_set(intf, false);
+ return ret;
+}
+
+static int bcmasp_open(struct net_device *dev)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ int ret;
+
+ netif_dbg(intf, ifup, dev, "bcmasp open\n");
+
+ ret = clk_prepare_enable(intf->parent->clk);
+ if (ret)
+ return ret;
+
+ ret = bcmasp_netif_init(dev, true);
+ if (ret)
+ clk_disable_unprepare(intf->parent->clk);
+
+ return ret;
+}
+
+static void bcmasp_tx_timeout(struct net_device *dev, unsigned int txqueue)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ netif_dbg(intf, tx_err, dev, "transmit timeout!\n");
+ intf->mib.tx_timeout_cnt++;
+}
+
+static int bcmasp_get_phys_port_name(struct net_device *dev,
+ char *name, size_t len)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+
+ if (snprintf(name, len, "p%d", intf->port) >= len)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void bcmasp_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct bcmasp_intf *intf = netdev_priv(dev);
+ struct bcmasp_intf_stats64 *lstats;
+ unsigned int start;
+
+ lstats = &intf->stats64;
+
+ do {
+ start = u64_stats_fetch_begin(&lstats->syncp);
+ stats->rx_packets = u64_stats_read(&lstats->rx_packets);
+ stats->rx_bytes = u64_stats_read(&lstats->rx_bytes);
+ stats->rx_dropped = u64_stats_read(&lstats->rx_dropped);
+ stats->rx_crc_errors = u64_stats_read(&lstats->rx_crc_errs);
+ stats->rx_frame_errors = u64_stats_read(&lstats->rx_sym_errs);
+ stats->rx_errors = stats->rx_crc_errors + stats->rx_frame_errors;
+
+ stats->tx_packets = u64_stats_read(&lstats->tx_packets);
+ stats->tx_bytes = u64_stats_read(&lstats->tx_bytes);
+ } while (u64_stats_fetch_retry(&lstats->syncp, start));
+}
+
+static const struct net_device_ops bcmasp_netdev_ops = {
+ .ndo_open = bcmasp_open,
+ .ndo_stop = bcmasp_stop,
+ .ndo_start_xmit = bcmasp_xmit,
+ .ndo_tx_timeout = bcmasp_tx_timeout,
+ .ndo_set_rx_mode = bcmasp_set_rx_mode,
+ .ndo_get_phys_port_name = bcmasp_get_phys_port_name,
+ .ndo_eth_ioctl = phy_do_ioctl_running,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_get_stats64 = bcmasp_get_stats64,
+};
+
+static void bcmasp_map_res(struct bcmasp_priv *priv, struct bcmasp_intf *intf)
+{
+ /* Per port */
+ intf->res.umac = priv->base + UMC_OFFSET(intf);
+ intf->res.umac2fb = priv->base + (priv->hw_info->umac2fb +
+ (intf->port * 0x4));
+ intf->res.rgmii = priv->base + RGMII_OFFSET(intf);
+
+ /* Per ch */
+ intf->tx_spb_dma = priv->base + TX_SPB_DMA_OFFSET(intf);
+ intf->res.tx_spb_ctrl = priv->base + TX_SPB_CTRL_OFFSET(intf);
+ intf->res.tx_spb_top = priv->base + TX_SPB_TOP_OFFSET(intf);
+ intf->res.tx_epkt_core = priv->base + TX_EPKT_C_OFFSET(intf);
+ intf->res.tx_pause_ctrl = priv->base + TX_PAUSE_CTRL_OFFSET(intf);
+
+ intf->rx_edpkt_dma = priv->base + RX_EDPKT_DMA_OFFSET(intf);
+ intf->rx_edpkt_cfg = priv->base + RX_EDPKT_CFG_OFFSET(intf);
+}
+
+#define MAX_IRQ_STR_LEN 64
+struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
+ struct device_node *ndev_dn, int i)
+{
+ struct device *dev = &priv->pdev->dev;
+ struct bcmasp_intf *intf;
+ struct net_device *ndev;
+ int ch, port, ret;
+
+ if (of_property_read_u32(ndev_dn, "reg", &port)) {
+ dev_warn(dev, "%s: invalid port number\n", ndev_dn->name);
+ goto err;
+ }
+
+ if (of_property_read_u32(ndev_dn, "brcm,channel", &ch)) {
+ dev_warn(dev, "%s: invalid ch number\n", ndev_dn->name);
+ goto err;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct bcmasp_intf));
+ if (!ndev) {
+ dev_warn(dev, "%s: unable to alloc ndev\n", ndev_dn->name);
+ goto err;
+ }
+ intf = netdev_priv(ndev);
+
+ intf->parent = priv;
+ intf->ndev = ndev;
+ intf->channel = ch;
+ intf->port = port;
+ intf->ndev_dn = ndev_dn;
+ intf->index = i;
+
+ ret = of_get_phy_mode(ndev_dn, &intf->phy_interface);
+ if (ret < 0) {
+ dev_err(dev, "invalid PHY mode property\n");
+ goto err_free_netdev;
+ }
+
+ if (intf->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+ intf->internal_phy = true;
+
+ intf->phy_dn = of_parse_phandle(ndev_dn, "phy-handle", 0);
+ if (!intf->phy_dn && of_phy_is_fixed_link(ndev_dn)) {
+ ret = of_phy_register_fixed_link(ndev_dn);
+ if (ret) {
+ dev_warn(dev, "%s: failed to register fixed PHY\n",
+ ndev_dn->name);
+ goto err_free_netdev;
+ }
+ intf->phy_dn = ndev_dn;
+ }
+
+ /* Map resource */
+ bcmasp_map_res(priv, intf);
+
+ if ((!phy_interface_mode_is_rgmii(intf->phy_interface) &&
+ intf->phy_interface != PHY_INTERFACE_MODE_MII &&
+ intf->phy_interface != PHY_INTERFACE_MODE_INTERNAL) ||
+ (intf->port != 1 && intf->internal_phy)) {
+ netdev_err(intf->ndev, "invalid PHY mode: %s for port %d\n",
+ phy_modes(intf->phy_interface), intf->port);
+ ret = -EINVAL;
+ goto err_free_netdev;
+ }
+
+ ret = of_get_ethdev_address(ndev_dn, ndev);
+ if (ret) {
+ netdev_warn(ndev, "using random Ethernet MAC\n");
+ eth_hw_addr_random(ndev);
+ }
+
+ SET_NETDEV_DEV(ndev, dev);
+ intf->ops = &bcmasp_intf_ops;
+ ndev->netdev_ops = &bcmasp_netdev_ops;
+ ndev->ethtool_ops = &bcmasp_ethtool_ops;
+ intf->msg_enable = netif_msg_init(-1, NETIF_MSG_DRV |
+ NETIF_MSG_PROBE |
+ NETIF_MSG_LINK);
+ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM;
+ ndev->hw_features |= ndev->features;
+ ndev->needed_headroom += sizeof(struct bcmasp_pkt_offload);
+
+ return intf;
+
+err_free_netdev:
+ free_netdev(ndev);
+err:
+ return NULL;
+}
+
+void bcmasp_interface_destroy(struct bcmasp_intf *intf)
+{
+ if (intf->ndev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(intf->ndev);
+ if (of_phy_is_fixed_link(intf->ndev_dn))
+ of_phy_deregister_fixed_link(intf->ndev_dn);
+ free_netdev(intf->ndev);
+}
+
+static void bcmasp_suspend_to_wol(struct bcmasp_intf *intf)
+{
+ struct net_device *ndev = intf->ndev;
+ u32 reg;
+
+ reg = umac_rl(intf, UMC_MPD_CTRL);
+ if (intf->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE))
+ reg |= UMC_MPD_CTRL_MPD_EN;
+ reg &= ~UMC_MPD_CTRL_PSW_EN;
+ if (intf->wolopts & WAKE_MAGICSECURE) {
+ /* Program the SecureOn password */
+ umac_wl(intf, get_unaligned_be16(&intf->sopass[0]),
+ UMC_PSW_MS);
+ umac_wl(intf, get_unaligned_be32(&intf->sopass[2]),
+ UMC_PSW_LS);
+ reg |= UMC_MPD_CTRL_PSW_EN;
+ }
+ umac_wl(intf, reg, UMC_MPD_CTRL);
+
+ if (intf->wolopts & WAKE_FILTER)
+ bcmasp_netfilt_suspend(intf);
+
+ /* UniMAC receive needs to be turned on */
+ umac_enable_set(intf, UMC_CMD_RX_EN, 1);
+
+ if (intf->parent->wol_irq > 0) {
+ wakeup_intr2_core_wl(intf->parent, 0xffffffff,
+ ASP_WAKEUP_INTR2_MASK_CLEAR);
+ }
+
+ netif_dbg(intf, wol, ndev, "entered WOL mode\n");
+}
+
+int bcmasp_interface_suspend(struct bcmasp_intf *intf)
+{
+ struct device *kdev = &intf->parent->pdev->dev;
+ struct net_device *dev = intf->ndev;
+ int ret = 0;
+
+ if (!netif_running(dev))
+ return 0;
+
+ netif_device_detach(dev);
+
+ bcmasp_netif_deinit(dev);
+
+ if (!intf->wolopts) {
+ ret = phy_suspend(dev->phydev);
+ if (ret)
+ goto out;
+
+ if (intf->internal_phy)
+ bcmasp_ephy_enable_set(intf, false);
+ else
+ bcmasp_rgmii_mode_en_set(intf, false);
+
+ /* If Wake-on-LAN is disabled, we can safely
+ * disable the network interface clocks.
+ */
+ bcmasp_core_clock_set_intf(intf, false);
+ }
+
+ if (device_may_wakeup(kdev) && intf->wolopts)
+ bcmasp_suspend_to_wol(intf);
+
+ clk_disable_unprepare(intf->parent->clk);
+
+ return ret;
+
+out:
+ bcmasp_netif_init(dev, false);
+ return ret;
+}
+
+static void bcmasp_resume_from_wol(struct bcmasp_intf *intf)
+{
+ u32 reg;
+
+ reg = umac_rl(intf, UMC_MPD_CTRL);
+ reg &= ~UMC_MPD_CTRL_MPD_EN;
+ umac_wl(intf, reg, UMC_MPD_CTRL);
+
+ if (intf->parent->wol_irq > 0) {
+ wakeup_intr2_core_wl(intf->parent, 0xffffffff,
+ ASP_WAKEUP_INTR2_MASK_SET);
+ }
+}
+
+int bcmasp_interface_resume(struct bcmasp_intf *intf)
+{
+ struct net_device *dev = intf->ndev;
+ int ret;
+
+ if (!netif_running(dev))
+ return 0;
+
+ ret = clk_prepare_enable(intf->parent->clk);
+ if (ret)
+ return ret;
+
+ ret = bcmasp_netif_init(dev, false);
+ if (ret)
+ goto out;
+
+ bcmasp_resume_from_wol(intf);
+
+ if (intf->eee.eee_enabled)
+ bcmasp_eee_enable_set(intf, true);
+
+ netif_device_attach(dev);
+
+ return 0;
+
+out:
+ clk_disable_unprepare(intf->parent->clk);
+ return ret;
+}
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h
new file mode 100644
index 000000000000..ad742612895f
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h
@@ -0,0 +1,257 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BCMASP_INTF_DEFS_H
+#define __BCMASP_INTF_DEFS_H
+
+#define UMC_OFFSET(intf) \
+ ((((intf)->port) * 0x800) + 0xc000)
+#define UMC_CMD 0x008
+#define UMC_CMD_TX_EN BIT(0)
+#define UMC_CMD_RX_EN BIT(1)
+#define UMC_CMD_SPEED_SHIFT 0x2
+#define UMC_CMD_SPEED_MASK 0x3
+#define UMC_CMD_SPEED_10 0x0
+#define UMC_CMD_SPEED_100 0x1
+#define UMC_CMD_SPEED_1000 0x2
+#define UMC_CMD_SPEED_2500 0x3
+#define UMC_CMD_PROMISC BIT(4)
+#define UMC_CMD_PAD_EN BIT(5)
+#define UMC_CMD_CRC_FWD BIT(6)
+#define UMC_CMD_PAUSE_FWD BIT(7)
+#define UMC_CMD_RX_PAUSE_IGNORE BIT(8)
+#define UMC_CMD_TX_ADDR_INS BIT(9)
+#define UMC_CMD_HD_EN BIT(10)
+#define UMC_CMD_SW_RESET BIT(13)
+#define UMC_CMD_LCL_LOOP_EN BIT(15)
+#define UMC_CMD_AUTO_CONFIG BIT(22)
+#define UMC_CMD_CNTL_FRM_EN BIT(23)
+#define UMC_CMD_NO_LEN_CHK BIT(24)
+#define UMC_CMD_RMT_LOOP_EN BIT(25)
+#define UMC_CMD_PRBL_EN BIT(27)
+#define UMC_CMD_TX_PAUSE_IGNORE BIT(28)
+#define UMC_CMD_TX_RX_EN BIT(29)
+#define UMC_CMD_RUNT_FILTER_DIS BIT(30)
+#define UMC_MAC0 0x0c
+#define UMC_MAC1 0x10
+#define UMC_FRM_LEN 0x14
+#define UMC_EEE_CTRL 0x64
+#define EN_LPI_RX_PAUSE BIT(0)
+#define EN_LPI_TX_PFC BIT(1)
+#define EN_LPI_TX_PAUSE BIT(2)
+#define EEE_EN BIT(3)
+#define RX_FIFO_CHECK BIT(4)
+#define EEE_TX_CLK_DIS BIT(5)
+#define DIS_EEE_10M BIT(6)
+#define LP_IDLE_PREDICTION_MODE BIT(7)
+#define UMC_EEE_LPI_TIMER 0x68
+#define UMC_PAUSE_CNTRL 0x330
+#define UMC_TX_FLUSH 0x334
+#define UMC_GR64 0x400
+#define UMC_GR127 0x404
+#define UMC_GR255 0x408
+#define UMC_GR511 0x40c
+#define UMC_GR1023 0x410
+#define UMC_GR1518 0x414
+#define UMC_GRMGV 0x418
+#define UMC_GR2047 0x41c
+#define UMC_GR4095 0x420
+#define UMC_GR9216 0x424
+#define UMC_GRPKT 0x428
+#define UMC_GRBYT 0x42c
+#define UMC_GRMCA 0x430
+#define UMC_GRBCA 0x434
+#define UMC_GRFCS 0x438
+#define UMC_GRXCF 0x43c
+#define UMC_GRXPF 0x440
+#define UMC_GRXUO 0x444
+#define UMC_GRALN 0x448
+#define UMC_GRFLR 0x44c
+#define UMC_GRCDE 0x450
+#define UMC_GRFCR 0x454
+#define UMC_GROVR 0x458
+#define UMC_GRJBR 0x45c
+#define UMC_GRMTUE 0x460
+#define UMC_GRPOK 0x464
+#define UMC_GRUC 0x468
+#define UMC_GRPPP 0x46c
+#define UMC_GRMCRC 0x470
+#define UMC_TR64 0x480
+#define UMC_TR127 0x484
+#define UMC_TR255 0x488
+#define UMC_TR511 0x48c
+#define UMC_TR1023 0x490
+#define UMC_TR1518 0x494
+#define UMC_TRMGV 0x498
+#define UMC_TR2047 0x49c
+#define UMC_TR4095 0x4a0
+#define UMC_TR9216 0x4a4
+#define UMC_GTPKT 0x4a8
+#define UMC_GTMCA 0x4ac
+#define UMC_GTBCA 0x4b0
+#define UMC_GTXPF 0x4b4
+#define UMC_GTXCF 0x4b8
+#define UMC_GTFCS 0x4bc
+#define UMC_GTOVR 0x4c0
+#define UMC_GTDRF 0x4c4
+#define UMC_GTEDF 0x4c8
+#define UMC_GTSCL 0x4cc
+#define UMC_GTMCL 0x4d0
+#define UMC_GTLCL 0x4d4
+#define UMC_GTXCL 0x4d8
+#define UMC_GTFRG 0x4dc
+#define UMC_GTNCL 0x4e0
+#define UMC_GTJBR 0x4e4
+#define UMC_GTBYT 0x4e8
+#define UMC_GTPOK 0x4ec
+#define UMC_GTUC 0x4f0
+#define UMC_RRPKT 0x500
+#define UMC_RRUND 0x504
+#define UMC_RRFRG 0x508
+#define UMC_RRBYT 0x50c
+#define UMC_MIB_CNTRL 0x580
+#define UMC_MIB_CNTRL_RX_CNT_RST BIT(0)
+#define UMC_MIB_CNTRL_RUNT_CNT_RST BIT(1)
+#define UMC_MIB_CNTRL_TX_CNT_RST BIT(2)
+#define UMC_RX_MAX_PKT_SZ 0x608
+#define UMC_MPD_CTRL 0x620
+#define UMC_MPD_CTRL_MPD_EN BIT(0)
+#define UMC_MPD_CTRL_PSW_EN BIT(27)
+#define UMC_PSW_MS 0x624
+#define UMC_PSW_LS 0x628
+
+#define UMAC2FB_OFFSET_2_1 0x9f044
+#define UMAC2FB_OFFSET 0x9f03c
+#define UMAC2FB_CFG 0x0
+#define UMAC2FB_CFG_OPUT_EN BIT(0)
+#define UMAC2FB_CFG_VLAN_EN BIT(1)
+#define UMAC2FB_CFG_SNAP_EN BIT(2)
+#define UMAC2FB_CFG_BCM_TG_EN BIT(3)
+#define UMAC2FB_CFG_IPUT_EN BIT(4)
+#define UMAC2FB_CFG_CHID_SHIFT 8
+#define UMAC2FB_CFG_OK_SEND_SHIFT 24
+#define UMAC2FB_CFG_DEFAULT_EN \
+ (UMAC2FB_CFG_OPUT_EN | UMAC2FB_CFG_VLAN_EN \
+ | UMAC2FB_CFG_SNAP_EN | UMAC2FB_CFG_IPUT_EN)
+
+#define RGMII_OFFSET(intf) \
+ ((((intf)->port) * 0x100) + 0xd000)
+#define RGMII_EPHY_CNTRL 0x00
+#define RGMII_EPHY_CFG_IDDQ_BIAS BIT(0)
+#define RGMII_EPHY_CFG_EXT_PWRDOWN BIT(1)
+#define RGMII_EPHY_CFG_FORCE_DLL_EN BIT(2)
+#define RGMII_EPHY_CFG_IDDQ_GLOBAL BIT(3)
+#define RGMII_EPHY_CK25_DIS BIT(4)
+#define RGMII_EPHY_RESET BIT(7)
+#define RGMII_OOB_CNTRL 0x0c
+#define RGMII_LINK BIT(4)
+#define RGMII_OOB_DIS BIT(5)
+#define RGMII_MODE_EN BIT(6)
+#define RGMII_ID_MODE_DIS BIT(16)
+
+#define RGMII_PORT_CNTRL 0x60
+#define RGMII_PORT_MODE_EPHY 0
+#define RGMII_PORT_MODE_GPHY 1
+#define RGMII_PORT_MODE_EXT_EPHY 2
+#define RGMII_PORT_MODE_EXT_GPHY 3
+#define RGMII_PORT_MODE_EXT_RVMII 4
+#define RGMII_PORT_MODE_MASK GENMASK(2, 0)
+
+#define RGMII_SYS_LED_CNTRL 0x74
+#define RGMII_SYS_LED_CNTRL_LINK_OVRD BIT(15)
+
+#define TX_SPB_DMA_OFFSET(intf) \
+ ((((intf)->channel) * 0x30) + 0x48180)
+#define TX_SPB_DMA_READ 0x00
+#define TX_SPB_DMA_BASE 0x08
+#define TX_SPB_DMA_END 0x10
+#define TX_SPB_DMA_VALID 0x18
+#define TX_SPB_DMA_FIFO_CTRL 0x20
+#define TX_SPB_DMA_FIFO_FLUSH BIT(0)
+#define TX_SPB_DMA_FIFO_STATUS 0x24
+
+#define TX_SPB_CTRL_OFFSET(intf) \
+ ((((intf)->channel) * 0x68) + 0x49340)
+#define TX_SPB_CTRL_ENABLE 0x0
+#define TX_SPB_CTRL_ENABLE_EN BIT(0)
+#define TX_SPB_CTRL_XF_CTRL2 0x20
+#define TX_SPB_CTRL_XF_BID_SHIFT 16
+
+#define TX_SPB_TOP_OFFSET(intf) \
+ ((((intf)->channel) * 0x1c) + 0x4a0e0)
+#define TX_SPB_TOP_BLKOUT 0x0
+#define TX_SPB_TOP_SPRE_BW_CTRL 0x4
+
+#define TX_EPKT_C_OFFSET(intf) \
+ ((((intf)->channel) * 0x120) + 0x40900)
+#define TX_EPKT_C_CFG_MISC 0x0
+#define TX_EPKT_C_CFG_MISC_EN BIT(0)
+#define TX_EPKT_C_CFG_MISC_PT BIT(1)
+#define TX_EPKT_C_CFG_MISC_PS_SHIFT 14
+#define TX_EPKT_C_CFG_MISC_FD_SHIFT 20
+
+#define TX_PAUSE_CTRL_OFFSET(intf) \
+ ((((intf)->channel * 0xc) + 0x49a20))
+#define TX_PAUSE_MAP_VECTOR 0x8
+
+#define RX_EDPKT_DMA_OFFSET(intf) \
+ ((((intf)->channel) * 0x38) + 0x9ca00)
+#define RX_EDPKT_DMA_WRITE 0x00
+#define RX_EDPKT_DMA_READ 0x08
+#define RX_EDPKT_DMA_BASE 0x10
+#define RX_EDPKT_DMA_END 0x18
+#define RX_EDPKT_DMA_VALID 0x20
+#define RX_EDPKT_DMA_FULLNESS 0x28
+#define RX_EDPKT_DMA_MIN_THRES 0x2c
+#define RX_EDPKT_DMA_CH_XONOFF 0x30
+
+#define RX_EDPKT_CFG_OFFSET(intf) \
+ ((((intf)->channel) * 0x70) + 0x9c600)
+#define RX_EDPKT_CFG_CFG0 0x0
+#define RX_EDPKT_CFG_CFG0_DBUF_SHIFT 9
+#define RX_EDPKT_CFG_CFG0_RBUF 0x0
+#define RX_EDPKT_CFG_CFG0_RBUF_4K 0x1
+#define RX_EDPKT_CFG_CFG0_BUF_4K 0x2
+/* EFRM STUFF, 0 = no byte stuff, 1 = two byte stuff */
+#define RX_EDPKT_CFG_CFG0_EFRM_STUF BIT(11)
+#define RX_EDPKT_CFG_CFG0_BALN_SHIFT 12
+#define RX_EDPKT_CFG_CFG0_NO_ALN 0
+#define RX_EDPKT_CFG_CFG0_4_ALN 2
+#define RX_EDPKT_CFG_CFG0_64_ALN 6
+#define RX_EDPKT_RING_BUFFER_WRITE 0x38
+#define RX_EDPKT_RING_BUFFER_READ 0x40
+#define RX_EDPKT_RING_BUFFER_BASE 0x48
+#define RX_EDPKT_RING_BUFFER_END 0x50
+#define RX_EDPKT_RING_BUFFER_VALID 0x58
+#define RX_EDPKT_CFG_ENABLE 0x6c
+#define RX_EDPKT_CFG_ENABLE_EN BIT(0)
+
+#define RX_SPB_DMA_OFFSET(intf) \
+ ((((intf)->channel) * 0x30) + 0xa0000)
+#define RX_SPB_DMA_READ 0x00
+#define RX_SPB_DMA_BASE 0x08
+#define RX_SPB_DMA_END 0x10
+#define RX_SPB_DMA_VALID 0x18
+#define RX_SPB_DMA_FIFO_CTRL 0x20
+#define RX_SPB_DMA_FIFO_FLUSH BIT(0)
+#define RX_SPB_DMA_FIFO_STATUS 0x24
+
+#define RX_SPB_CTRL_OFFSET(intf) \
+ ((((intf)->channel - 6) * 0x68) + 0xa1000)
+#define RX_SPB_CTRL_ENABLE 0x00
+#define RX_SPB_CTRL_ENABLE_EN BIT(0)
+
+#define RX_PAUSE_CTRL_OFFSET(intf) \
+ ((((intf)->channel - 6) * 0x4) + 0xa1138)
+#define RX_PAUSE_MAP_VECTOR 0x00
+
+#define RX_SPB_TOP_CTRL_OFFSET(intf) \
+ ((((intf)->channel - 6) * 0x14) + 0xa2000)
+#define RX_SPB_TOP_BLKOUT 0x00
+
+#define NUM_4K_BUFFERS 32
+#define RING_BUFFER_SIZE (PAGE_SIZE * NUM_4K_BUFFERS)
+
+#define DESC_RING_COUNT (64 * NUM_4K_BUFFERS)
+#define DESC_SIZE 16
+#define DESC_RING_SIZE (DESC_RING_COUNT * DESC_SIZE)
+
+#endif
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 2cf96892e565..a741070f1f9a 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -1940,7 +1940,6 @@ static struct platform_driver bcm63xx_enet_driver = {
.remove = bcm_enet_remove,
.driver = {
.name = "bcm63xx_enet",
- .owner = THIS_MODULE,
},
};
@@ -2761,7 +2760,6 @@ static struct platform_driver bcm63xx_enetsw_driver = {
.remove = bcm_enetsw_remove,
.driver = {
.name = "bcm63xx_enetsw",
- .owner = THIS_MODULE,
},
};
@@ -2791,7 +2789,6 @@ struct platform_driver bcm63xx_enet_shared_driver = {
.probe = bcm_enet_shared_probe,
.driver = {
.name = "bcm63xx_enet_shared",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 10c7c232cc4e..448a1b90de5e 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1448,9 +1448,9 @@ int bgmac_phy_connect_direct(struct bgmac *bgmac)
int err;
phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
- if (!phy_dev || IS_ERR(phy_dev)) {
+ if (IS_ERR(phy_dev)) {
dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
- return -ENODEV;
+ return PTR_ERR(phy_dev);
}
err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 8bcde0a6e011..e2a4e1088b7f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1508,6 +1508,8 @@ struct bnx2x {
bool cnic_loaded;
struct cnic_eth_dev *(*cnic_probe)(struct net_device *);
+ bool nic_stopped;
+
/* Flag that indicates that we can start looking for FCoE L2 queue
* completions in the default status block.
*/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 6ea5521074d3..e9c1e1bb5580 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -2715,6 +2715,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bnx2x_add_all_napi(bp);
DP(NETIF_MSG_IFUP, "napi added\n");
bnx2x_napi_enable(bp);
+ bp->nic_stopped = false;
if (IS_PF(bp)) {
/* set pf load just before approaching the MCP */
@@ -2960,6 +2961,7 @@ load_error2:
load_error1:
bnx2x_napi_disable(bp);
bnx2x_del_all_napi(bp);
+ bp->nic_stopped = true;
/* clear pf_load status, as it was already set */
if (IS_PF(bp))
@@ -3095,14 +3097,17 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
if (!CHIP_IS_E1x(bp))
bnx2x_pf_disable(bp);
- /* Disable HW interrupts, NAPI */
- bnx2x_netif_stop(bp, 1);
- /* Delete all NAPI objects */
- bnx2x_del_all_napi(bp);
- if (CNIC_LOADED(bp))
- bnx2x_del_all_napi_cnic(bp);
- /* Release IRQs */
- bnx2x_free_irq(bp);
+ if (!bp->nic_stopped) {
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 1);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+ if (CNIC_LOADED(bp))
+ bnx2x_del_all_napi_cnic(bp);
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+ bp->nic_stopped = true;
+ }
/* Report UNLOAD_DONE to MCP */
bnx2x_send_unload_done(bp, false);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 1e7a6f1d4223..0d8e61c63c7c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9474,15 +9474,18 @@ unload_error:
}
}
- /* Disable HW interrupts, NAPI */
- bnx2x_netif_stop(bp, 1);
- /* Delete all NAPI objects */
- bnx2x_del_all_napi(bp);
- if (CNIC_LOADED(bp))
- bnx2x_del_all_napi_cnic(bp);
+ if (!bp->nic_stopped) {
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 1);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+ if (CNIC_LOADED(bp))
+ bnx2x_del_all_napi_cnic(bp);
- /* Release IRQs */
- bnx2x_free_irq(bp);
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+ bp->nic_stopped = true;
+ }
/* Reset the chip, unless PCI function is offline. If we reach this
* point following a PCI error handling, it means device is really
@@ -14238,13 +14241,16 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
}
bnx2x_drain_tx_queues(bp);
bnx2x_send_unload_req(bp, UNLOAD_RECOVERY);
- bnx2x_netif_stop(bp, 1);
- bnx2x_del_all_napi(bp);
+ if (!bp->nic_stopped) {
+ bnx2x_netif_stop(bp, 1);
+ bnx2x_del_all_napi(bp);
- if (CNIC_LOADED(bp))
- bnx2x_del_all_napi_cnic(bp);
+ if (CNIC_LOADED(bp))
+ bnx2x_del_all_napi_cnic(bp);
- bnx2x_free_irq(bp);
+ bnx2x_free_irq(bp);
+ bp->nic_stopped = true;
+ }
/* Report UNLOAD_DONE to MCP */
bnx2x_send_unload_done(bp, true);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 542c69822649..8e04552d2216 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -890,7 +890,7 @@ static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
(struct eth_classify_rules_ramrod_data *)(raw->rdata);
int rule_cnt = rule_idx + 1, cmd = elem->cmd_data.vlan_mac.cmd;
union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
- bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
+ bool add = cmd == BNX2X_VLAN_MAC_ADD;
unsigned long *vlan_mac_flags = &elem->cmd_data.vlan_mac.vlan_mac_flags;
u8 *mac = elem->cmd_data.vlan_mac.u.mac.mac;
@@ -1075,7 +1075,7 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
int rule_cnt = rule_idx + 1;
union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
- bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
+ bool add = cmd == BNX2X_VLAN_MAC_ADD;
u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan;
/* Reset the ramrod data buffer for the first rule */
@@ -1125,7 +1125,7 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
int rule_cnt = rule_idx + 1;
union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
- bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
+ bool add = cmd == BNX2X_VLAN_MAC_ADD;
u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
u16 inner_mac;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 0657a0f5170f..8946a931e87e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -529,13 +529,16 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp)
bnx2x_vfpf_finalize(bp, &req->first_tlv);
free_irq:
- /* Disable HW interrupts, NAPI */
- bnx2x_netif_stop(bp, 0);
- /* Delete all NAPI objects */
- bnx2x_del_all_napi(bp);
-
- /* Release IRQs */
- bnx2x_free_irq(bp);
+ if (!bp->nic_stopped) {
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 0);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+ bp->nic_stopped = true;
+ }
}
static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 1eb490c48c52..5cc0dbe12132 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -54,7 +54,7 @@
#include <net/pkt_cls.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <linux/align.h>
#include <net/netdev_queues.h>
@@ -293,6 +293,60 @@ static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
BNXT_DB_CQ(db, idx);
}
+static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
+{
+ if (!(test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)))
+ return;
+
+ if (BNXT_PF(bp))
+ queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
+ else
+ schedule_delayed_work(&bp->fw_reset_task, delay);
+}
+
+static void __bnxt_queue_sp_work(struct bnxt *bp)
+{
+ if (BNXT_PF(bp))
+ queue_work(bnxt_pf_wq, &bp->sp_task);
+ else
+ schedule_work(&bp->sp_task);
+}
+
+static void bnxt_queue_sp_work(struct bnxt *bp, unsigned int event)
+{
+ set_bit(event, &bp->sp_event);
+ __bnxt_queue_sp_work(bp);
+}
+
+static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
+{
+ if (!rxr->bnapi->in_reset) {
+ rxr->bnapi->in_reset = true;
+ if (bp->flags & BNXT_FLAG_CHIP_P5)
+ set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event);
+ else
+ set_bit(BNXT_RST_RING_SP_EVENT, &bp->sp_event);
+ __bnxt_queue_sp_work(bp);
+ }
+ rxr->rx_next_cons = 0xffff;
+}
+
+void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
+ int idx)
+{
+ struct bnxt_napi *bnapi = txr->bnapi;
+
+ if (bnapi->tx_fault)
+ return;
+
+ netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_pkts:%d cons:%u prod:%u i:%d)",
+ txr->txq_index, bnapi->tx_pkts,
+ txr->tx_cons, txr->tx_prod, idx);
+ WARN_ON_ONCE(1);
+ bnapi->tx_fault = 1;
+ bnxt_queue_sp_work(bp, BNXT_RESET_TASK_SP_EVENT);
+}
+
const u16 bnxt_lhint_arr[] = {
TX_BD_FLAGS_LHINT_512_AND_SMALLER,
TX_BD_FLAGS_LHINT_512_TO_1023,
@@ -653,6 +707,11 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
skb = tx_buf->skb;
tx_buf->skb = NULL;
+ if (unlikely(!skb)) {
+ bnxt_sched_reset_txr(bp, txr, i);
+ return;
+ }
+
tx_bytes += skb->len;
if (tx_buf->is_push) {
@@ -686,7 +745,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
next_tx_int:
cons = NEXT_TX(cons);
- dev_kfree_skb_any(skb);
+ dev_consume_skb_any(skb);
}
bnapi->tx_pkts = 0;
@@ -702,7 +761,6 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
unsigned int *offset,
gfp_t gfp)
{
- struct device *dev = &bp->pdev->dev;
struct page *page;
if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
@@ -715,12 +773,7 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
if (!page)
return NULL;
- *mapping = dma_map_page_attrs(dev, page, *offset, BNXT_RX_PAGE_SIZE,
- bp->rx_dir, DMA_ATTR_WEAK_ORDERING);
- if (dma_mapping_error(dev, *mapping)) {
- page_pool_recycle_direct(rxr->page_pool, page);
- return NULL;
- }
+ *mapping = page_pool_get_dma_addr(page) + *offset;
return page;
}
@@ -818,48 +871,15 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp,
struct rx_bd *rxbd =
&rxr->rx_agg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
struct bnxt_sw_rx_agg_bd *rx_agg_buf;
- struct pci_dev *pdev = bp->pdev;
struct page *page;
dma_addr_t mapping;
u16 sw_prod = rxr->rx_sw_agg_prod;
unsigned int offset = 0;
- if (BNXT_RX_PAGE_MODE(bp)) {
- page = __bnxt_alloc_rx_page(bp, &mapping, rxr, &offset, gfp);
-
- if (!page)
- return -ENOMEM;
-
- } else {
- if (PAGE_SIZE > BNXT_RX_PAGE_SIZE) {
- page = rxr->rx_page;
- if (!page) {
- page = alloc_page(gfp);
- if (!page)
- return -ENOMEM;
- rxr->rx_page = page;
- rxr->rx_page_offset = 0;
- }
- offset = rxr->rx_page_offset;
- rxr->rx_page_offset += BNXT_RX_PAGE_SIZE;
- if (rxr->rx_page_offset == PAGE_SIZE)
- rxr->rx_page = NULL;
- else
- get_page(page);
- } else {
- page = alloc_page(gfp);
- if (!page)
- return -ENOMEM;
- }
+ page = __bnxt_alloc_rx_page(bp, &mapping, rxr, &offset, gfp);
- mapping = dma_map_page_attrs(&pdev->dev, page, offset,
- BNXT_RX_PAGE_SIZE, DMA_FROM_DEVICE,
- DMA_ATTR_WEAK_ORDERING);
- if (dma_mapping_error(&pdev->dev, mapping)) {
- __free_page(page);
- return -EIO;
- }
- }
+ if (!page)
+ return -ENOMEM;
if (unlikely(test_bit(sw_prod, rxr->rx_agg_bmap)))
sw_prod = bnxt_find_next_agg_idx(rxr, sw_prod);
@@ -972,9 +992,9 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
return NULL;
}
dma_addr -= bp->rx_dma_offset;
- dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
- bp->rx_dir, DMA_ATTR_WEAK_ORDERING);
- skb = build_skb(data_ptr - bp->rx_offset, BNXT_RX_PAGE_SIZE);
+ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
+ bp->rx_dir);
+ skb = napi_build_skb(data_ptr - bp->rx_offset, BNXT_RX_PAGE_SIZE);
if (!skb) {
page_pool_recycle_direct(rxr->page_pool, page);
return NULL;
@@ -1006,8 +1026,8 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
return NULL;
}
dma_addr -= bp->rx_dma_offset;
- dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
- bp->rx_dir, DMA_ATTR_WEAK_ORDERING);
+ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, BNXT_RX_PAGE_SIZE,
+ bp->rx_dir);
if (unlikely(!payload))
payload = eth_get_headlen(bp->dev, data_ptr, len);
@@ -1049,7 +1069,7 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp,
return NULL;
}
- skb = build_skb(data, bp->rx_buf_size);
+ 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);
if (!skb) {
@@ -1123,9 +1143,8 @@ static u32 __bnxt_rx_agg_pages(struct bnxt *bp,
return 0;
}
- dma_unmap_page_attrs(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE,
- bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
+ dma_sync_single_for_cpu(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE,
+ bp->rx_dir);
total_frag_len += frag_len;
prod = NEXT_RX_AGG(prod);
@@ -1145,6 +1164,7 @@ static struct sk_buff *bnxt_rx_agg_pages_skb(struct bnxt *bp,
total_frag_len = __bnxt_rx_agg_pages(bp, cpr, shinfo, idx,
agg_bufs, tpa, NULL);
if (!total_frag_len) {
+ skb_mark_for_recycle(skb);
dev_kfree_skb(skb);
return NULL;
}
@@ -1244,38 +1264,6 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
return 0;
}
-static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
-{
- if (!(test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)))
- return;
-
- if (BNXT_PF(bp))
- queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
- else
- schedule_delayed_work(&bp->fw_reset_task, delay);
-}
-
-static void bnxt_queue_sp_work(struct bnxt *bp)
-{
- if (BNXT_PF(bp))
- queue_work(bnxt_pf_wq, &bp->sp_task);
- else
- schedule_work(&bp->sp_task);
-}
-
-static void bnxt_sched_reset(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
-{
- if (!rxr->bnapi->in_reset) {
- rxr->bnapi->in_reset = true;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
- set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event);
- else
- set_bit(BNXT_RST_RING_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
- rxr->rx_next_cons = 0xffff;
-}
-
static u16 bnxt_alloc_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id)
{
struct bnxt_tpa_idx_map *map = rxr->rx_tpa_idx_map;
@@ -1330,7 +1318,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
netdev_warn(bp->dev, "TPA cons %x, expected cons %x, error code %x\n",
cons, rxr->rx_next_cons,
TPA_START_ERROR_CODE(tpa_start1));
- bnxt_sched_reset(bp, rxr);
+ bnxt_sched_reset_rxr(bp, rxr);
return;
}
/* Store cfa_code in tpa_info to use in tpa_end
@@ -1689,7 +1677,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
tpa_info->data_ptr = new_data + bp->rx_offset;
tpa_info->mapping = new_mapping;
- skb = build_skb(data, bp->rx_buf_size);
+ 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);
@@ -1767,6 +1755,7 @@ static void bnxt_deliver_skb(struct bnxt *bp, struct bnxt_napi *bnapi,
return;
}
skb_record_rx_queue(skb, bnapi->index);
+ skb_mark_for_recycle(skb);
napi_gro_receive(&bnapi->napi, skb);
}
@@ -1854,7 +1843,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
if (rxr->rx_next_cons != 0xffff)
netdev_warn(bp->dev, "RX cons %x != expected cons %x\n",
cons, rxr->rx_next_cons);
- bnxt_sched_reset(bp, rxr);
+ bnxt_sched_reset_rxr(bp, rxr);
if (rc1)
return rc1;
goto next_rx_no_prod_no_len;
@@ -1892,7 +1881,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
!(bp->fw_cap & BNXT_FW_CAP_RING_MONITOR)) {
netdev_warn_once(bp->dev, "RX buffer error %x\n",
rx_err);
- bnxt_sched_reset(bp, rxr);
+ bnxt_sched_reset_rxr(bp, rxr);
}
}
goto next_rx_no_len;
@@ -2339,7 +2328,7 @@ static int bnxt_async_event_process(struct bnxt *bp,
goto async_event_process_exit;
}
rxr = bp->bnapi[grp_idx]->rx_ring;
- bnxt_sched_reset(bp, rxr);
+ bnxt_sched_reset_rxr(bp, rxr);
goto async_event_process_exit;
}
case ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST: {
@@ -2394,7 +2383,7 @@ static int bnxt_async_event_process(struct bnxt *bp,
default:
goto async_event_process_exit;
}
- bnxt_queue_sp_work(bp);
+ __bnxt_queue_sp_work(bp);
async_event_process_exit:
return 0;
}
@@ -2423,8 +2412,7 @@ static int bnxt_hwrm_handler(struct bnxt *bp, struct tx_cmp *txcmp)
}
set_bit(vf_id - bp->pf.first_vf_id, bp->pf.vf_event_bmap);
- set_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT);
break;
case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT:
@@ -2582,7 +2570,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi,
int budget)
{
- if (bnapi->tx_pkts)
+ if (bnapi->tx_pkts && !bnapi->tx_fault)
bnapi->tx_int(bp, bnapi, budget);
if ((bnapi->events & BNXT_RX_EVENT) && !(bnapi->in_reset)) {
@@ -2952,10 +2940,6 @@ skip_rx_tpa_free:
rx_buf->data = NULL;
if (BNXT_RX_PAGE_MODE(bp)) {
- mapping -= bp->rx_dma_offset;
- dma_unmap_page_attrs(&pdev->dev, mapping,
- BNXT_RX_PAGE_SIZE, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
page_pool_recycle_direct(rxr->page_pool, data);
} else {
dma_unmap_single_attrs(&pdev->dev, mapping,
@@ -2976,30 +2960,13 @@ skip_rx_buf_free:
if (!page)
continue;
- if (BNXT_RX_PAGE_MODE(bp)) {
- dma_unmap_page_attrs(&pdev->dev, rx_agg_buf->mapping,
- BNXT_RX_PAGE_SIZE, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
- rx_agg_buf->page = NULL;
- __clear_bit(i, rxr->rx_agg_bmap);
-
- page_pool_recycle_direct(rxr->page_pool, page);
- } else {
- dma_unmap_page_attrs(&pdev->dev, rx_agg_buf->mapping,
- BNXT_RX_PAGE_SIZE, DMA_FROM_DEVICE,
- DMA_ATTR_WEAK_ORDERING);
- rx_agg_buf->page = NULL;
- __clear_bit(i, rxr->rx_agg_bmap);
+ rx_agg_buf->page = NULL;
+ __clear_bit(i, rxr->rx_agg_bmap);
- __free_page(page);
- }
+ page_pool_recycle_direct(rxr->page_pool, page);
}
skip_rx_agg_free:
- if (rxr->rx_page) {
- __free_page(rxr->rx_page);
- rxr->rx_page = NULL;
- }
map = rxr->rx_tpa_idx_map;
if (map)
memset(map->agg_idx_bmap, 0, sizeof(map->agg_idx_bmap));
@@ -3218,11 +3185,15 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
{
struct page_pool_params pp = { 0 };
- pp.pool_size = bp->rx_ring_size;
+ pp.pool_size = bp->rx_agg_ring_size;
+ if (BNXT_RX_PAGE_MODE(bp))
+ pp.pool_size += bp->rx_ring_size;
pp.nid = dev_to_node(&bp->pdev->dev);
pp.napi = &rxr->bnapi->napi;
pp.dev = &bp->pdev->dev;
- pp.dma_dir = DMA_BIDIRECTIONAL;
+ pp.dma_dir = bp->rx_dir;
+ pp.max_len = PAGE_SIZE;
+ pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
if (PAGE_SIZE > BNXT_RX_PAGE_SIZE)
pp.flags |= PP_FLAG_PAGE_FRAG;
@@ -9422,10 +9393,16 @@ static void bnxt_disable_napi(struct bnxt *bp)
return;
for (i = 0; i < bp->cp_nr_rings; i++) {
- struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
+ struct bnxt_napi *bnapi = bp->bnapi[i];
+ struct bnxt_cp_ring_info *cpr;
- napi_disable(&bp->bnapi[i]->napi);
- if (bp->bnapi[i]->rx_ring)
+ cpr = &bnapi->cp_ring;
+ if (bnapi->tx_fault)
+ cpr->sw_stats.tx.tx_resets++;
+ if (bnapi->in_reset)
+ cpr->sw_stats.rx.rx_resets++;
+ napi_disable(&bnapi->napi);
+ if (bnapi->rx_ring)
cancel_work_sync(&cpr->dim.work);
}
}
@@ -9439,9 +9416,9 @@ static void bnxt_enable_napi(struct bnxt *bp)
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr;
+ bnapi->tx_fault = 0;
+
cpr = &bnapi->cp_ring;
- if (bnapi->in_reset)
- cpr->sw_stats.rx.rx_resets++;
bnapi->in_reset = false;
bnapi->tx_pkts = 0;
@@ -10710,8 +10687,10 @@ static void __bnxt_close_nic(struct bnxt *bp, bool irq_re_init,
bnxt_free_skbs(bp);
/* Save ring stats before shutdown */
- if (bp->bnapi && irq_re_init)
+ if (bp->bnapi && irq_re_init) {
bnxt_get_ring_stats(bp, &bp->net_stats_prev);
+ bnxt_get_ring_err_stats(bp, &bp->ring_err_stats_prev);
+ }
if (irq_re_init) {
bnxt_free_irq(bp);
bnxt_del_napi(bp);
@@ -10960,6 +10939,35 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
clear_bit(BNXT_STATE_READ_STATS, &bp->state);
}
+static void bnxt_get_one_ring_err_stats(struct bnxt *bp,
+ struct bnxt_total_ring_err_stats *stats,
+ struct bnxt_cp_ring_info *cpr)
+{
+ struct bnxt_sw_stats *sw_stats = &cpr->sw_stats;
+ u64 *hw_stats = cpr->stats.sw_stats;
+
+ stats->rx_total_l4_csum_errors += sw_stats->rx.rx_l4_csum_errors;
+ stats->rx_total_resets += sw_stats->rx.rx_resets;
+ stats->rx_total_buf_errors += sw_stats->rx.rx_buf_errors;
+ stats->rx_total_oom_discards += sw_stats->rx.rx_oom_discards;
+ stats->rx_total_netpoll_discards += sw_stats->rx.rx_netpoll_discards;
+ stats->rx_total_ring_discards +=
+ BNXT_GET_RING_STATS64(hw_stats, rx_discard_pkts);
+ stats->tx_total_resets += sw_stats->tx.tx_resets;
+ stats->tx_total_ring_discards +=
+ BNXT_GET_RING_STATS64(hw_stats, tx_discard_pkts);
+ stats->total_missed_irqs += sw_stats->cmn.missed_irqs;
+}
+
+void bnxt_get_ring_err_stats(struct bnxt *bp,
+ struct bnxt_total_ring_err_stats *stats)
+{
+ int i;
+
+ for (i = 0; i < bp->cp_nr_rings; i++)
+ bnxt_get_one_ring_err_stats(bp, stats, &bp->bnapi[i]->cp_ring);
+}
+
static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask)
{
struct net_device *dev = bp->dev;
@@ -11048,8 +11056,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)
if (mask != vnic->rx_mask || uc_update || mc_update) {
vnic->rx_mask = mask;
- set_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_RX_MASK_SP_EVENT);
}
}
@@ -11614,8 +11621,7 @@ static void bnxt_tx_timeout(struct net_device *dev, unsigned int txqueue)
struct bnxt *bp = netdev_priv(dev);
netdev_err(bp->dev, "TX timeout detected, starting reset task!\n");
- set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_RESET_TASK_SP_EVENT);
}
static void bnxt_fw_health_check(struct bnxt *bp)
@@ -11652,8 +11658,7 @@ static void bnxt_fw_health_check(struct bnxt *bp)
return;
fw_reset:
- set_bit(BNXT_FW_EXCEPTION_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_FW_EXCEPTION_SP_EVENT);
}
static void bnxt_timer(struct timer_list *t)
@@ -11670,21 +11675,15 @@ static void bnxt_timer(struct timer_list *t)
if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
bnxt_fw_health_check(bp);
- if (BNXT_LINK_IS_UP(bp) && bp->stats_coal_ticks) {
- set_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
+ if (BNXT_LINK_IS_UP(bp) && bp->stats_coal_ticks)
+ bnxt_queue_sp_work(bp, BNXT_PERIODIC_STATS_SP_EVENT);
- if (bnxt_tc_flower_enabled(bp)) {
- set_bit(BNXT_FLOW_STATS_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
+ if (bnxt_tc_flower_enabled(bp))
+ bnxt_queue_sp_work(bp, BNXT_FLOW_STATS_SP_EVENT);
#ifdef CONFIG_RFS_ACCEL
- if ((bp->flags & BNXT_FLAG_RFS) && bp->ntp_fltr_count) {
- set_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
+ if ((bp->flags & BNXT_FLAG_RFS) && bp->ntp_fltr_count)
+ bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT);
#endif /*CONFIG_RFS_ACCEL*/
if (bp->link_info.phy_retry) {
@@ -11692,21 +11691,17 @@ static void bnxt_timer(struct timer_list *t)
bp->link_info.phy_retry = false;
netdev_warn(bp->dev, "failed to update phy settings after maximum retries.\n");
} else {
- set_bit(BNXT_UPDATE_PHY_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_UPDATE_PHY_SP_EVENT);
}
}
- if (test_bit(BNXT_STATE_L2_FILTER_RETRY, &bp->state)) {
- set_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
+ if (test_bit(BNXT_STATE_L2_FILTER_RETRY, &bp->state))
+ bnxt_queue_sp_work(bp, BNXT_RX_MASK_SP_EVENT);
if ((bp->flags & BNXT_FLAG_CHIP_P5) && !bp->chip_rev &&
- netif_carrier_ok(dev)) {
- set_bit(BNXT_RING_COAL_NOW_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
- }
+ netif_carrier_ok(dev))
+ bnxt_queue_sp_work(bp, BNXT_RING_COAL_NOW_SP_EVENT);
+
bnxt_restart_timer:
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
@@ -12985,8 +12980,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
bp->ntp_fltr_count++;
spin_unlock_bh(&bp->ntp_fltr_lock);
- set_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event);
- bnxt_queue_sp_work(bp);
+ bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT);
return new_fltr->sw_id;
@@ -13118,9 +13112,6 @@ static int bnxt_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
- if (nla_len(attr) < sizeof(mode))
- return -EINVAL;
-
mode = nla_get_u16(attr);
if (mode == bp->br_mode)
break;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index bb95c3dc5270..84cbcfa61bc1 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -919,9 +919,6 @@ struct bnxt_rx_ring_info {
unsigned long *rx_agg_bmap;
u16 rx_agg_bmap_size;
- struct page *rx_page;
- unsigned int rx_page_offset;
-
dma_addr_t rx_desc_mapping[MAX_RX_PAGES];
dma_addr_t rx_agg_desc_mapping[MAX_RX_AGG_PAGES];
@@ -942,15 +939,32 @@ struct bnxt_rx_sw_stats {
u64 rx_netpoll_discards;
};
+struct bnxt_tx_sw_stats {
+ u64 tx_resets;
+};
+
struct bnxt_cmn_sw_stats {
u64 missed_irqs;
};
struct bnxt_sw_stats {
struct bnxt_rx_sw_stats rx;
+ struct bnxt_tx_sw_stats tx;
struct bnxt_cmn_sw_stats cmn;
};
+struct bnxt_total_ring_err_stats {
+ u64 rx_total_l4_csum_errors;
+ u64 rx_total_resets;
+ u64 rx_total_buf_errors;
+ u64 rx_total_oom_discards;
+ u64 rx_total_netpoll_discards;
+ u64 rx_total_ring_discards;
+ u64 tx_total_resets;
+ u64 tx_total_ring_discards;
+ u64 total_missed_irqs;
+};
+
struct bnxt_stats_mem {
u64 *sw_stats;
u64 *hw_masks;
@@ -1008,6 +1022,7 @@ struct bnxt_napi {
int budget);
int tx_pkts;
u8 events;
+ u8 tx_fault:1;
u32 flags;
#define BNXT_NAPI_FLAG_XDP 0x1
@@ -2020,6 +2035,8 @@ struct bnxt {
u8 pri2cos_idx[8];
u8 pri2cos_valid;
+ struct bnxt_total_ring_err_stats ring_err_stats_prev;
+
u16 hwrm_max_req_len;
u16 hwrm_max_ext_req_len;
unsigned int hwrm_cmd_timeout;
@@ -2329,6 +2346,8 @@ int bnxt_get_avail_msix(struct bnxt *bp, int num);
int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init);
void bnxt_tx_disable(struct bnxt *bp);
void bnxt_tx_enable(struct bnxt *bp);
+void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
+ int idx);
void bnxt_report_link(struct bnxt *bp);
int bnxt_update_link(struct bnxt *bp, bool chng_link_state);
int bnxt_hwrm_set_pause(struct bnxt *);
@@ -2344,6 +2363,8 @@ int bnxt_half_open_nic(struct bnxt *bp);
void bnxt_half_close_nic(struct bnxt *bp);
void bnxt_reenable_sriov(struct bnxt *bp);
int bnxt_close_nic(struct bnxt *, bool, bool);
+void bnxt_get_ring_err_stats(struct bnxt *bp,
+ struct bnxt_total_ring_err_stats *stats);
int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words,
u32 *reg_buf);
void bnxt_fw_exception(struct bnxt *bp);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
index caab3d626a2a..63e067038385 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -98,7 +98,6 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
{
struct hwrm_queue_cos2bw_cfg_input *req;
struct bnxt_cos2bw_cfg cos2bw;
- void *data;
int rc, i;
rc = hwrm_req_init(bp, req, HWRM_QUEUE_COS2BW_CFG);
@@ -129,11 +128,15 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
cpu_to_le32((ets->tc_tx_bw[i] * 100) |
BW_VALUE_UNIT_PERCENT1_100);
}
- data = &req->unused_0 + qidx * (sizeof(cos2bw) - 4);
- memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
if (qidx == 0) {
req->queue_id0 = cos2bw.queue_id;
- req->unused_0 = 0;
+ req->queue_id0_min_bw = cos2bw.min_bw;
+ req->queue_id0_max_bw = cos2bw.max_bw;
+ req->queue_id0_tsa_assign = cos2bw.tsa;
+ req->queue_id0_pri_lvl = cos2bw.pri_lvl;
+ req->queue_id0_bw_weight = cos2bw.bw_weight;
+ } else {
+ memcpy(&req->cfg[i - 1], &cos2bw.cfg, sizeof(cos2bw.cfg));
}
}
return hwrm_req_send(bp, req);
@@ -144,7 +147,6 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
struct hwrm_queue_cos2bw_qcfg_output *resp;
struct hwrm_queue_cos2bw_qcfg_input *req;
struct bnxt_cos2bw_cfg cos2bw;
- void *data;
int rc, i;
rc = hwrm_req_init(bp, req, HWRM_QUEUE_COS2BW_QCFG);
@@ -158,13 +160,19 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
return rc;
}
- data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
- for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw.cfg)) {
+ for (i = 0; i < bp->max_tc; i++) {
int tc;
- memcpy(&cos2bw.cfg, data, sizeof(cos2bw.cfg));
- if (i == 0)
+ if (i == 0) {
cos2bw.queue_id = resp->queue_id0;
+ cos2bw.min_bw = resp->queue_id0_min_bw;
+ cos2bw.max_bw = resp->queue_id0_max_bw;
+ cos2bw.tsa = resp->queue_id0_tsa_assign;
+ cos2bw.pri_lvl = resp->queue_id0_pri_lvl;
+ cos2bw.bw_weight = resp->queue_id0_bw_weight;
+ } else {
+ memcpy(&cos2bw.cfg, &resp->cfg[i - 1], sizeof(cos2bw.cfg));
+ }
tc = bnxt_queue_to_tc(bp, cos2bw.queue_id);
if (tc < 0)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h
index 716742522161..5b2a6f678244 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.h
@@ -27,11 +27,12 @@ struct bnxt_cos2bw_cfg {
u8 queue_id;
__le32 min_bw;
__le32 max_bw;
-#define BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
u8 tsa;
u8 pri_lvl;
u8 bw_weight;
);
+/* for min_bw / max_bw */
+#define BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
u8 unused;
};
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 8fd5071d8b09..547247d98eba 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -339,13 +339,16 @@ enum {
RX_NETPOLL_DISCARDS,
};
-static struct {
- u64 counter;
- char string[ETH_GSTRING_LEN];
-} bnxt_sw_func_stats[] = {
- {0, "rx_total_discard_pkts"},
- {0, "tx_total_discard_pkts"},
- {0, "rx_total_netpoll_discards"},
+static const char *const bnxt_ring_err_stats_arr[] = {
+ "rx_total_l4_csum_errors",
+ "rx_total_resets",
+ "rx_total_buf_errors",
+ "rx_total_oom_discards",
+ "rx_total_netpoll_discards",
+ "rx_total_ring_discards",
+ "tx_total_resets",
+ "tx_total_ring_discards",
+ "total_missed_irqs",
};
#define NUM_RING_RX_SW_STATS ARRAY_SIZE(bnxt_rx_sw_stats_str)
@@ -495,7 +498,7 @@ static const struct {
BNXT_TX_STATS_PRI_ENTRIES(tx_packets),
};
-#define BNXT_NUM_SW_FUNC_STATS ARRAY_SIZE(bnxt_sw_func_stats)
+#define BNXT_NUM_RING_ERR_STATS ARRAY_SIZE(bnxt_ring_err_stats_arr)
#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
#define BNXT_NUM_STATS_PRI \
(ARRAY_SIZE(bnxt_rx_bytes_pri_arr) + \
@@ -532,7 +535,7 @@ static int bnxt_get_num_stats(struct bnxt *bp)
{
int num_stats = bnxt_get_num_ring_stats(bp);
- num_stats += BNXT_NUM_SW_FUNC_STATS;
+ num_stats += BNXT_NUM_RING_ERR_STATS;
if (bp->flags & BNXT_FLAG_PORT_STATS)
num_stats += BNXT_NUM_PORT_STATS;
@@ -583,18 +586,17 @@ static bool is_tx_ring(struct bnxt *bp, int ring_num)
static void bnxt_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
{
- u32 i, j = 0;
+ struct bnxt_total_ring_err_stats ring_err_stats = {0};
struct bnxt *bp = netdev_priv(dev);
+ u64 *curr, *prev;
u32 tpa_stats;
+ u32 i, j = 0;
if (!bp->bnapi) {
- j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS;
+ j += bnxt_get_num_ring_stats(bp);
goto skip_ring_stats;
}
- for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++)
- bnxt_sw_func_stats[i].counter = 0;
-
tpa_stats = bnxt_get_num_tpa_ring_stats(bp);
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
@@ -631,19 +633,16 @@ skip_tpa_ring_stats:
sw = (u64 *)&cpr->sw_stats.cmn;
for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++)
buf[j] = sw[k];
-
- bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter +=
- BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts);
- bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter +=
- BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts);
- bnxt_sw_func_stats[RX_NETPOLL_DISCARDS].counter +=
- cpr->sw_stats.rx.rx_netpoll_discards;
}
- for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++)
- buf[j] = bnxt_sw_func_stats[i].counter;
+ bnxt_get_ring_err_stats(bp, &ring_err_stats);
skip_ring_stats:
+ curr = &ring_err_stats.rx_total_l4_csum_errors;
+ prev = &bp->ring_err_stats_prev.rx_total_l4_csum_errors;
+ for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++, j++, curr++, prev++)
+ buf[j] = *curr + *prev;
+
if (bp->flags & BNXT_FLAG_PORT_STATS) {
u64 *port_stats = bp->port_stats.sw_stats;
@@ -745,8 +744,8 @@ skip_tpa_stats:
buf += ETH_GSTRING_LEN;
}
}
- for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) {
- strcpy(buf, bnxt_sw_func_stats[i].string);
+ 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;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index b31de4cf6534..f178ed9899a9 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -5739,286 +5739,48 @@ struct hwrm_queue_cos2bw_qcfg_output {
#define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_RESERVED_LAST 0xffUL
u8 queue_id0_pri_lvl;
u8 queue_id0_bw_weight;
- u8 queue_id1;
- __le32 queue_id1_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id1_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id1_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID1_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id1_pri_lvl;
- u8 queue_id1_bw_weight;
- u8 queue_id2;
- __le32 queue_id2_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id2_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id2_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID2_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id2_pri_lvl;
- u8 queue_id2_bw_weight;
- u8 queue_id3;
- __le32 queue_id3_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id3_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id3_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID3_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id3_pri_lvl;
- u8 queue_id3_bw_weight;
- u8 queue_id4;
- __le32 queue_id4_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id4_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id4_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID4_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id4_pri_lvl;
- u8 queue_id4_bw_weight;
- u8 queue_id5;
- __le32 queue_id5_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id5_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id5_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID5_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id5_pri_lvl;
- u8 queue_id5_bw_weight;
- u8 queue_id6;
- __le32 queue_id6_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id6_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id6_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID6_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id6_pri_lvl;
- u8 queue_id6_bw_weight;
- u8 queue_id7;
- __le32 queue_id7_min_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id7_max_bw;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id7_tsa_assign;
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID7_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id7_pri_lvl;
- u8 queue_id7_bw_weight;
+ struct {
+ u8 queue_id;
+ __le32 queue_id_min_bw;
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_MASK 0xfffffffUL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_SFT 0
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_SCALE 0x10000000UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_SCALE_BITS (0x0UL << 28)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_SCALE_BYTES (0x1UL << 28)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_SCALE_BYTES
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_SFT 29
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_INVALID
+ __le32 queue_id_max_bw;
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_MASK 0xfffffffUL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_SFT 0
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_SCALE 0x10000000UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_SCALE_BITS (0x0UL << 28)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_SCALE_BYTES (0x1UL << 28)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_SCALE_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_SCALE_BYTES
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_SFT 29
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_INVALID
+ u8 queue_id_tsa_assign;
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_TSA_ASSIGN_SP 0x0UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_TSA_ASSIGN_ETS 0x1UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_TSA_ASSIGN_RESERVED_FIRST 0x2UL
+ #define QUEUE_COS2BW_QCFG_RESP_QUEUE_ID_TSA_ASSIGN_RESERVED_LAST 0xffUL
+ u8 queue_id_pri_lvl;
+ u8 queue_id_bw_weight;
+ } __packed cfg[7];
u8 unused_2[4];
u8 valid;
};
@@ -6082,286 +5844,48 @@ struct hwrm_queue_cos2bw_cfg_input {
#define QUEUE_COS2BW_CFG_REQ_QUEUE_ID0_TSA_ASSIGN_RESERVED_LAST 0xffUL
u8 queue_id0_pri_lvl;
u8 queue_id0_bw_weight;
- u8 queue_id1;
- __le32 queue_id1_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id1_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id1_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID1_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id1_pri_lvl;
- u8 queue_id1_bw_weight;
- u8 queue_id2;
- __le32 queue_id2_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id2_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id2_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID2_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id2_pri_lvl;
- u8 queue_id2_bw_weight;
- u8 queue_id3;
- __le32 queue_id3_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id3_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id3_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID3_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id3_pri_lvl;
- u8 queue_id3_bw_weight;
- u8 queue_id4;
- __le32 queue_id4_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id4_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id4_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID4_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id4_pri_lvl;
- u8 queue_id4_bw_weight;
- u8 queue_id5;
- __le32 queue_id5_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id5_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id5_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID5_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id5_pri_lvl;
- u8 queue_id5_bw_weight;
- u8 queue_id6;
- __le32 queue_id6_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id6_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id6_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID6_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id6_pri_lvl;
- u8 queue_id6_bw_weight;
- u8 queue_id7;
- __le32 queue_id7_min_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MIN_BW_BW_VALUE_UNIT_INVALID
- __le32 queue_id7_max_bw;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_MASK 0xfffffffUL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_SFT 0
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_SCALE 0x10000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_SCALE_BITS (0x0UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_SCALE_BYTES (0x1UL << 28)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_SCALE_BYTES
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_SFT 29
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_MAX_BW_BW_VALUE_UNIT_INVALID
- u8 queue_id7_tsa_assign;
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_TSA_ASSIGN_SP 0x0UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_TSA_ASSIGN_ETS 0x1UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_TSA_ASSIGN_RESERVED_FIRST 0x2UL
- #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID7_TSA_ASSIGN_RESERVED_LAST 0xffUL
- u8 queue_id7_pri_lvl;
- u8 queue_id7_bw_weight;
+ struct {
+ u8 queue_id;
+ __le32 queue_id_min_bw;
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_MASK 0xfffffffUL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_SFT 0
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_SCALE 0x10000000UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_SCALE_BITS (0x0UL << 28)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_SCALE_BYTES (0x1UL << 28)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_SCALE_BYTES
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_SFT 29
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MIN_BW_BW_VALUE_UNIT_INVALID
+ __le32 queue_id_max_bw;
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_MASK 0xfffffffUL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_SFT 0
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_SCALE 0x10000000UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_SCALE_BITS (0x0UL << 28)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_SCALE_BYTES (0x1UL << 28)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_SCALE_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_SCALE_BYTES
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_MASK 0xe0000000UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_SFT 29
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_MEGA (0x0UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_KILO (0x2UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_BASE (0x4UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_GIGA (0x6UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_PERCENT1_100 (0x1UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_INVALID (0x7UL << 29)
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_LAST QUEUE_COS2BW_CFG_REQ_QUEUE_ID_MAX_BW_BW_VALUE_UNIT_INVALID
+ u8 queue_id_tsa_assign;
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_TSA_ASSIGN_SP 0x0UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_TSA_ASSIGN_ETS 0x1UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_TSA_ASSIGN_RESERVED_FIRST 0x2UL
+ #define QUEUE_COS2BW_CFG_REQ_QUEUE_ID_TSA_ASSIGN_RESERVED_LAST 0xffUL
+ u8 queue_id_pri_lvl;
+ u8 queue_id_bw_weight;
+ } __packed cfg[7];
u8 unused_1[5];
};
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index d8afcf8d6b30..38d89d80b4a9 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -373,9 +373,9 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
struct flow_dissector *dissector = rule->match.dissector;
/* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
- if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
- (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
- netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%x\n",
+ if ((dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
+ (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
+ netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index fb43232310b2..96f5ca778c67 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -15,7 +15,7 @@
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/filter.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
@@ -153,6 +153,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
tx_buf->action = 0;
tx_buf->xdpf = NULL;
} else if (tx_buf->action == XDP_TX) {
+ tx_buf->action = 0;
rx_doorbell_needed = true;
last_tx_cons = tx_cons;
@@ -162,6 +163,9 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
tx_buf = &txr->tx_buf_ring[tx_cons];
page_pool_recycle_direct(rxr->page_pool, tx_buf->page);
}
+ } else {
+ bnxt_sched_reset_txr(bp, txr, i);
+ return;
}
tx_cons = NEXT_TX(tx_cons);
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 2b5761ad2f92..24bade875ca6 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2077,12 +2077,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock(&ring->lock);
if (ring->free_bds <= (nr_frags + 1)) {
- if (!netif_tx_queue_stopped(txq)) {
+ if (!netif_tx_queue_stopped(txq))
netif_tx_stop_queue(txq);
- netdev_err(dev,
- "%s: tx ring %d full when queue %d awake\n",
- __func__, index, ring->queue);
- }
ret = NETDEV_TX_BUSY;
goto out;
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 0092e46c46f8..97ea76d443ab 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -617,9 +617,9 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
};
phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
- if (!phydev || IS_ERR(phydev)) {
+ if (IS_ERR(phydev)) {
dev_err(kdev, "failed to register fixed PHY device\n");
- return -ENODEV;
+ return PTR_ERR(phydev);
}
/* Make sure we initialize MoCA PHYs with a link down */
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 5ef073a79ce9..14b311196b8f 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -1539,8 +1539,7 @@ static int tg3_mdio_init(struct tg3 *tp)
return -ENOMEM;
tp->mdio_bus->name = "tg3 mdio bus";
- snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x",
- (tp->pdev->bus->number << 8) | tp->pdev->devfn);
+ snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(tp->pdev));
tp->mdio_bus->priv = tp;
tp->mdio_bus->parent = &tp->pdev->dev;
tp->mdio_bus->read = &tg3_mdio_read;
@@ -6881,7 +6880,10 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
ri->data = NULL;
- skb = build_skb(data, frag_size);
+ if (frag_size)
+ skb = build_skb(data, frag_size);
+ else
+ skb = slab_build_skb(data);
if (!skb) {
tg3_frag_free(frag_size != 0, data);
goto drop_it_no_recycle;
@@ -17792,10 +17794,7 @@ static int tg3_init_one(struct pci_dev *pdev,
tnapi->tx_pending = TG3_DEF_TX_RING_PENDING;
tnapi->int_mbox = intmbx;
- if (i <= 4)
- intmbx += 0x8;
- else
- intmbx += 0x4;
+ intmbx += 0x8;
tnapi->consmbox = rcvmbx;
tnapi->prodmbox = sndmbx;
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index d6d90f9722a7..31191b520b58 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -1037,8 +1037,7 @@ bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb)
static void
bnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx)
{
- struct bnad_tx_info *tx_info =
- (struct bnad_tx_info *)tx->priv;
+ struct bnad_tx_info *tx_info = tx->priv;
struct bna_tcb *tcb;
u32 txq_id;
int i;
@@ -1056,7 +1055,7 @@ bnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx)
static void
bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
{
- struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv;
+ struct bnad_tx_info *tx_info = tx->priv;
struct bna_tcb *tcb;
u32 txq_id;
int i;
@@ -1133,7 +1132,7 @@ bnad_tx_cleanup(struct delayed_work *work)
static void
bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx)
{
- struct bnad_tx_info *tx_info = (struct bnad_tx_info *)tx->priv;
+ struct bnad_tx_info *tx_info = tx->priv;
struct bna_tcb *tcb;
int i;
@@ -1149,7 +1148,7 @@ bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx)
static void
bnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx)
{
- struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bnad_rx_info *rx_info = rx->priv;
struct bna_ccb *ccb;
struct bnad_rx_ctrl *rx_ctrl;
int i;
@@ -1208,7 +1207,7 @@ bnad_rx_cleanup(void *work)
static void
bnad_cb_rx_cleanup(struct bnad *bnad, struct bna_rx *rx)
{
- struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bnad_rx_info *rx_info = rx->priv;
struct bna_ccb *ccb;
struct bnad_rx_ctrl *rx_ctrl;
int i;
@@ -1231,7 +1230,7 @@ bnad_cb_rx_cleanup(struct bnad *bnad, struct bna_rx *rx)
static void
bnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx)
{
- struct bnad_rx_info *rx_info = (struct bnad_rx_info *)rx->priv;
+ struct bnad_rx_info *rx_info = rx->priv;
struct bna_ccb *ccb;
struct bna_rcb *rcb;
struct bnad_rx_ctrl *rx_ctrl;
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 82929ee76739..31f664ee4d77 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -26,7 +26,6 @@
#include <linux/platform_device.h>
#include <linux/phylink.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 9b84c8d8d309..d117022d15d7 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -2126,7 +2126,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.set_link_ksettings = set_link_ksettings,
};
-static int in_range(int val, int lo, int hi)
+static int cxgb_in_range(int val, int lo, int hi)
{
return val < 0 || (val <= hi && val >= lo);
}
@@ -2162,19 +2162,19 @@ static int cxgb_siocdevprivate(struct net_device *dev,
return -EINVAL;
if (t.qset_idx >= SGE_QSETS)
return -EINVAL;
- if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
- !in_range(t.cong_thres, 0, 255) ||
- !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+ if (!cxgb_in_range(t.intr_lat, 0, M_NEWTIMER) ||
+ !cxgb_in_range(t.cong_thres, 0, 255) ||
+ !cxgb_in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
MAX_TXQ_ENTRIES) ||
- !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+ !cxgb_in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
MAX_TXQ_ENTRIES) ||
- !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+ !cxgb_in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
MAX_CTRL_TXQ_ENTRIES) ||
- !in_range(t.fl_size[0], MIN_FL_ENTRIES,
+ !cxgb_in_range(t.fl_size[0], MIN_FL_ENTRIES,
MAX_RX_BUFFERS) ||
- !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+ !cxgb_in_range(t.fl_size[1], MIN_FL_ENTRIES,
MAX_RX_JUMBO_BUFFERS) ||
- !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+ !cxgb_in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
MAX_RSPQ_ENTRIES))
return -EINVAL;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
index d3541159487d..72ac4a34424b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
@@ -313,15 +313,15 @@ static int cxgb4_validate_flow_match(struct net_device *dev,
u16 ethtype_key = 0;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IP))) {
- netdev_warn(dev, "Unsupported key used: 0x%x\n",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP))) {
+ netdev_warn(dev, "Unsupported key used: 0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h
index 68562a82d036..62f62bff74a5 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h
@@ -22,6 +22,7 @@
#include <crypto/internal/hash.h>
#include <linux/tls.h>
#include <net/tls.h>
+#include <net/tls_prot.h>
#include <net/tls_toe.h>
#include "t4fw_api.h"
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
index c2e7037c7ba1..7750702900fa 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
@@ -1466,7 +1466,7 @@ static void make_established(struct sock *sk, u32 snd_isn, unsigned int opt)
tp->write_seq = snd_isn;
tp->snd_nxt = snd_isn;
tp->snd_una = snd_isn;
- inet_sk(sk)->inet_id = get_random_u16();
+ atomic_set(&inet_sk(sk)->inet_id, get_random_u16());
assign_rxopt(sk, opt);
if (tp->rcv_wnd > (RCV_BUFSIZ_M << 10))
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 276c32c3926a..d323c5c23521 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -54,7 +54,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -1855,9 +1854,8 @@ static int __init cs89x0_platform_probe(struct platform_device *pdev)
return -ENOMEM;
dev->irq = platform_get_irq(pdev, 0);
- if (dev->irq <= 0) {
- dev_warn(&dev->dev, "interrupt resource missing\n");
- err = -ENXIO;
+ if (dev->irq < 0) {
+ err = dev->irq;
goto free;
}
diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 5715b9ab2712..a8b9d1a3e4d5 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -2415,8 +2415,8 @@ static int gemini_ethernet_port_probe(struct platform_device *pdev)
/* Interrupt */
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return irq ? irq : -ENODEV;
+ if (irq < 0)
+ return irq;
port->irq = irq;
/* Clock the port */
@@ -2538,7 +2538,7 @@ MODULE_DEVICE_TABLE(of, gemini_ethernet_port_of_match);
static struct platform_driver gemini_ethernet_port_driver = {
.driver = {
.name = "gemini-ethernet-port",
- .of_match_table = of_match_ptr(gemini_ethernet_port_of_match),
+ .of_match_table = gemini_ethernet_port_of_match,
},
.probe = gemini_ethernet_port_probe,
.remove = gemini_ethernet_port_remove,
@@ -2604,7 +2604,7 @@ MODULE_DEVICE_TABLE(of, gemini_ethernet_of_match);
static struct platform_driver gemini_ethernet_driver = {
.driver = {
.name = DRV_NAME,
- .of_match_table = of_match_ptr(gemini_ethernet_of_match),
+ .of_match_table = gemini_ethernet_of_match,
},
.probe = gemini_ethernet_probe,
.remove = gemini_ethernet_remove,
diff --git a/drivers/net/ethernet/davicom/dm9051.c b/drivers/net/ethernet/davicom/dm9051.c
index 70728b2e5f18..bcfe52c11804 100644
--- a/drivers/net/ethernet/davicom/dm9051.c
+++ b/drivers/net/ethernet/davicom/dm9051.c
@@ -510,10 +510,7 @@ static int dm9051_map_init(struct spi_device *spi, struct board_info *db)
regconfigdmbulk.lock_arg = db;
db->regmap_dmbulk = devm_regmap_init_spi(db->spidev, &regconfigdmbulk);
- if (IS_ERR(db->regmap_dmbulk))
- return PTR_ERR(db->regmap_dmbulk);
-
- return 0;
+ return PTR_ERR_OR_ZERO(db->regmap_dmbulk);
}
static int dm9051_map_chipid(struct board_info *db)
@@ -1161,9 +1158,7 @@ static int dm9051_phy_connect(struct board_info *db)
db->phydev = phy_connect(db->ndev, phy_id, dm9051_handle_link_change,
PHY_INTERFACE_MODE_MII);
- if (IS_ERR(db->phydev))
- return PTR_ERR_OR_ZERO(db->phydev);
- return 0;
+ return PTR_ERR_OR_ZERO(db->phydev);
}
static int dm9051_probe(struct spi_device *spi)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 0616b5fe241c..ad862ed7888a 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4986,9 +4986,6 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
- if (nla_len(attr) < sizeof(mode))
- return -EINVAL;
-
mode = nla_get_u16(attr);
if (BE3_chip(adapter) && mode == BRIDGE_MODE_VEPA)
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/engleder/tsnep.h b/drivers/net/ethernet/engleder/tsnep.h
index 11b29f56aaf9..6e14c918e3fb 100644
--- a/drivers/net/ethernet/engleder/tsnep.h
+++ b/drivers/net/ethernet/engleder/tsnep.h
@@ -14,6 +14,7 @@
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/miscdevice.h>
+#include <net/xdp.h>
#define TSNEP "tsnep"
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index 84751bb303a6..f61bd89734c5 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -28,6 +28,7 @@
#include <linux/iopoll.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
+#include <net/page_pool/helpers.h>
#include <net/xdp_sock_drv.h>
#define TSNEP_RX_OFFSET (max(NET_SKB_PAD, XDP_PACKET_HEADROOM) + NET_IP_ALIGN)
@@ -1333,7 +1334,7 @@ static void tsnep_rx_page(struct tsnep_rx *rx, struct napi_struct *napi,
skb = tsnep_build_skb(rx, page, length);
if (skb) {
- page_pool_release_page(rx->page_pool, page);
+ skb_mark_for_recycle(skb);
rx->packets++;
rx->bytes += length;
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
index f1eb660aaee2..edf000e7bab4 100644
--- a/drivers/net/ethernet/ezchip/nps_enet.c
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -6,10 +6,9 @@
#include <linux/module.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include "nps_enet.h"
#define DRV_NAME "nps_mgt_enet"
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index a03879a27b04..9135b918dd49 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -177,16 +177,20 @@ static void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const u8 *mac)
iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
}
-static void ftgmac100_initial_mac(struct ftgmac100 *priv)
+static int ftgmac100_initial_mac(struct ftgmac100 *priv)
{
u8 mac[ETH_ALEN];
unsigned int m;
unsigned int l;
+ int err;
- if (!device_get_ethdev_address(priv->dev, priv->netdev)) {
+ err = of_get_ethdev_address(priv->dev->of_node, priv->netdev);
+ if (err == -EPROBE_DEFER)
+ return err;
+ if (!err) {
dev_info(priv->dev, "Read MAC address %pM from device tree\n",
priv->netdev->dev_addr);
- return;
+ return 0;
}
m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
@@ -207,6 +211,8 @@ static void ftgmac100_initial_mac(struct ftgmac100 *priv)
dev_info(priv->dev, "Generated random MAC address %pM\n",
priv->netdev->dev_addr);
}
+
+ return 0;
}
static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
@@ -1843,7 +1849,9 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv->aneg_pause = true;
/* MAC address from chip or random one */
- ftgmac100_initial_mac(priv);
+ err = ftgmac100_initial_mac(priv);
+ if (err)
+ goto err_phy_connect;
np = pdev->dev.of_node;
if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index 139fe66f8bcd..183069581bc0 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -149,6 +149,40 @@ static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
}
+static void ftmac100_setup_mc_ht(struct ftmac100 *priv)
+{
+ struct netdev_hw_addr *ha;
+ u64 maht = 0; /* Multicast Address Hash Table */
+
+ netdev_for_each_mc_addr(ha, priv->netdev) {
+ u32 hash = ether_crc(ETH_ALEN, ha->addr) >> 26;
+
+ maht |= BIT_ULL(hash);
+ }
+
+ iowrite32(lower_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT0);
+ iowrite32(upper_32_bits(maht), priv->base + FTMAC100_OFFSET_MAHT1);
+}
+
+static void ftmac100_set_rx_bits(struct ftmac100 *priv, unsigned int *maccr)
+{
+ struct net_device *netdev = priv->netdev;
+
+ /* Clear all */
+ *maccr &= ~(FTMAC100_MACCR_RCV_ALL | FTMAC100_MACCR_RX_MULTIPKT |
+ FTMAC100_MACCR_HT_MULTI_EN);
+
+ /* Set the requested bits */
+ if (netdev->flags & IFF_PROMISC)
+ *maccr |= FTMAC100_MACCR_RCV_ALL;
+ if (netdev->flags & IFF_ALLMULTI)
+ *maccr |= FTMAC100_MACCR_RX_MULTIPKT;
+ else if (netdev_mc_count(netdev)) {
+ *maccr |= FTMAC100_MACCR_HT_MULTI_EN;
+ ftmac100_setup_mc_ht(priv);
+ }
+}
+
#define MACCR_ENABLE_ALL (FTMAC100_MACCR_XMT_EN | \
FTMAC100_MACCR_RCV_EN | \
FTMAC100_MACCR_XDMA_EN | \
@@ -182,11 +216,7 @@ static int ftmac100_start_hw(struct ftmac100 *priv)
if (netdev->mtu > ETH_DATA_LEN)
maccr |= FTMAC100_MACCR_RX_FTL;
- /* Add other bits as needed */
- if (netdev->flags & IFF_PROMISC)
- maccr |= FTMAC100_MACCR_RCV_ALL;
- if (netdev->flags & IFF_ALLMULTI)
- maccr |= FTMAC100_MACCR_RX_MULTIPKT;
+ ftmac100_set_rx_bits(priv, &maccr);
iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
return 0;
@@ -1067,6 +1097,15 @@ static int ftmac100_change_mtu(struct net_device *netdev, int mtu)
return 0;
}
+static void ftmac100_set_rx_mode(struct net_device *netdev)
+{
+ struct ftmac100 *priv = netdev_priv(netdev);
+ unsigned int maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
+
+ ftmac100_set_rx_bits(priv, &maccr);
+ iowrite32(maccr, priv->base + FTMAC100_OFFSET_MACCR);
+}
+
static const struct net_device_ops ftmac100_netdev_ops = {
.ndo_open = ftmac100_open,
.ndo_stop = ftmac100_stop,
@@ -1075,6 +1114,7 @@ static const struct net_device_ops ftmac100_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_eth_ioctl = ftmac100_do_ioctl,
.ndo_change_mtu = ftmac100_change_mtu,
+ .ndo_set_rx_mode = ftmac100_set_rx_mode,
};
/******************************************************************************
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 431f8917dc39..dcbc598b11c6 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -7,8 +7,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/io.h>
@@ -17,6 +17,7 @@
#include <linux/icmp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <linux/platform_device.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/net.h>
@@ -3497,7 +3498,7 @@ free_netdev:
return err;
}
-static int dpaa_remove(struct platform_device *pdev)
+static void dpaa_remove(struct platform_device *pdev)
{
struct net_device *net_dev;
struct dpaa_priv *priv;
@@ -3516,6 +3517,9 @@ static int dpaa_remove(struct platform_device *pdev)
phylink_destroy(priv->mac_dev->phylink);
err = dpaa_fq_free(dev, &priv->dpaa_fq_list);
+ if (err)
+ dev_err(dev, "Failed to free FQs on remove (%pE)\n",
+ ERR_PTR(err));
qman_delete_cgr_safe(&priv->ingress_cgr);
qman_release_cgrid(priv->ingress_cgr.cgrid);
@@ -3527,8 +3531,6 @@ static int dpaa_remove(struct platform_device *pdev)
dpaa_bps_free(priv);
free_netdev(net_dev);
-
- return err;
}
static const struct platform_device_id dpaa_devtype[] = {
@@ -3546,7 +3548,7 @@ static struct platform_driver dpaa_driver = {
},
.id_table = dpaa_devtype,
.probe = dpaa_eth_probe,
- .remove = dpaa_remove
+ .remove_new = dpaa_remove
};
static int __init dpaa_load(void)
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
index 35b8cea7f886..ac3c8ed57bbe 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
@@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/refcount.h>
+#include <net/xdp.h>
#include <soc/fsl/qman.h>
#include <soc/fsl/bman.h>
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index 9c71cbbb13d8..5bd0b36d1feb 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -6,7 +6,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/string.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/net_tstamp.h>
#include <linux/fsl/ptp_qoriq.h>
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
index a9676d0dece8..15bab41cee48 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
@@ -5087,7 +5087,6 @@ MODULE_DEVICE_TABLE(fslmc, dpaa2_eth_match_id_table);
static struct fsl_mc_driver dpaa2_eth_driver = {
.driver = {
.name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
},
.probe = dpaa2_eth_probe,
.remove = dpaa2_eth_remove,
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
index d56d7a13262e..bfb6c96c3b2f 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
@@ -12,6 +12,7 @@
#include <linux/fsl/mc.h>
#include <linux/net_tstamp.h>
#include <net/devlink.h>
+#include <net/xdp.h>
#include <soc/fsl/dpaa2-io.h>
#include <soc/fsl/dpaa2-fd.h>
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
index c39b866e2582..4798fb7fe35d 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
@@ -17,14 +17,14 @@ static int dpaa2_switch_flower_parse_key(struct flow_cls_offload *cls,
struct dpsw_acl_fields *acl_h, *acl_m;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS))) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported keys used");
return -EOPNOTSUPP;
@@ -539,9 +539,9 @@ static int dpaa2_switch_flower_parse_mirror_key(struct flow_cls_offload *cls,
int ret = -EOPNOTSUPP;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_VLAN))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {
NL_SET_ERR_MSG_MOD(extack,
"Mirroring is supported only per VLAN");
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 21cc4e52425a..97d3151076d5 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -3457,7 +3457,6 @@ MODULE_DEVICE_TABLE(fslmc, dpaa2_switch_match_id_table);
static struct fsl_mc_driver dpaa2_switch_drv = {
.driver = {
.name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
},
.probe = dpaa2_switch_probe,
.remove = dpaa2_switch_remove,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8577cf7699a0..7439739cd81a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -11,6 +11,7 @@
#include <linux/if_vlan.h>
#include <linux/phylink.h>
#include <linux/dim.h>
+#include <net/xdp.h>
#include "enetc_hw.h"
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
index b307bef4dc29..d39617ab9306 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c
@@ -18,8 +18,8 @@
*/
#include <linux/io.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include "enetc.h"
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
index 17c097cef7d4..5243fc031058 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
@@ -8,7 +8,7 @@
#include "enetc.h"
int enetc_phc_index = -1;
-EXPORT_SYMBOL(enetc_phc_index);
+EXPORT_SYMBOL_GPL(enetc_phc_index);
static struct ptp_clock_info enetc_ptp_caps = {
.owner = THIS_MODULE,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index 270cbd5e8684..2513b44056c1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -483,13 +483,13 @@ struct enetc_psfp {
static struct actions_fwd enetc_act_fwd[] = {
{
BIT(FLOW_ACTION_GATE),
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS),
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS),
FILTER_ACTION_TYPE_PSFP
},
{
BIT(FLOW_ACTION_POLICE) |
BIT(FLOW_ACTION_GATE),
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS),
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS),
FILTER_ACTION_TYPE_PSFP
},
/* example for ACL actions */
@@ -1069,8 +1069,8 @@ revert_sid:
return err;
}
-static struct actions_fwd *enetc_check_flow_actions(u64 acts,
- unsigned int inputkeys)
+static struct actions_fwd *
+enetc_check_flow_actions(u64 acts, unsigned long long inputkeys)
{
int i;
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 63a053dea819..a8fbcada6b01 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -22,6 +22,7 @@
#include <linux/timecounter.h>
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/firmware/imx/sci.h>
+#include <net/xdp.h>
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
@@ -547,13 +548,11 @@ enum {
enum fec_txbuf_type {
FEC_TXBUF_T_SKB,
FEC_TXBUF_T_XDP_NDO,
+ FEC_TXBUF_T_XDP_TX,
};
struct fec_tx_buffer {
- union {
- struct sk_buff *skb;
- struct xdp_frame *xdp;
- };
+ void *buf_p;
enum fec_txbuf_type type;
};
@@ -651,12 +650,9 @@ struct fec_enet_private {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
- unsigned long last_overflow_check;
spinlock_t tmreg_lock;
struct cyclecounter cc;
struct timecounter tc;
- int rx_hwtstamp_filter;
- u32 base_incval;
u32 cycle_speed;
int hwts_rx_en;
int hwts_tx_en;
@@ -679,8 +675,6 @@ struct fec_enet_private {
struct ethtool_eee eee;
unsigned int clk_ref_rate;
- u32 rx_copybreak;
-
/* ptp clock period in ns*/
unsigned int ptp_inc;
@@ -703,9 +697,9 @@ struct fec_enet_private {
void fec_ptp_init(struct platform_device *pdev, int irq_idx);
void fec_ptp_stop(struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
-void fec_ptp_disable_hwts(struct net_device *ndev);
-int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
-int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
+int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack);
+void fec_ptp_get(struct net_device *ndev, struct kernel_hwtstamp_config *config);
/****************************************************************************/
#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 66b5cbdb43b9..77c8e9cfb445 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -38,6 +38,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <net/ip.h>
+#include <net/page_pool/helpers.h>
#include <net/selftests.h>
#include <net/tso.h>
#include <linux/tcp.h>
@@ -68,6 +69,7 @@
#include <soc/imx/cpuidle.h>
#include <linux/filter.h>
#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
#include <asm/cacheflush.h>
@@ -75,6 +77,9 @@
static void set_multicast_list(struct net_device *ndev);
static void fec_enet_itr_coal_set(struct net_device *ndev);
+static int fec_enet_xdp_tx_xmit(struct fec_enet_private *fep,
+ int cpu, struct xdp_buff *xdp,
+ u32 dma_sync_len);
#define DRIVER_NAME "fec"
@@ -325,8 +330,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
-#define COPYBREAK_DEFAULT 256
-
/* Max number of allowed TCP segments for software TSO */
#define FEC_MAX_TSO_SEGS 100
#define FEC_MAX_SKB_DESCS (FEC_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
@@ -397,7 +400,7 @@ static void fec_dump(struct net_device *ndev)
fec16_to_cpu(bdp->cbd_sc),
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
- txq->tx_buf[index].skb);
+ txq->tx_buf[index].buf_p);
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
index++;
} while (bdp != txq->bd.base);
@@ -654,7 +657,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
index = fec_enet_get_bd_index(last_bdp, &txq->bd);
/* Save skb pointer */
- txq->tx_buf[index].skb = skb;
+ txq->tx_buf[index].buf_p = skb;
/* Make sure the updates to rest of the descriptor are performed before
* transferring ownership.
@@ -860,7 +863,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
}
/* Save skb pointer */
- txq->tx_buf[index].skb = skb;
+ txq->tx_buf[index].buf_p = skb;
skb_tx_timestamp(skb);
txq->bd.cur = bdp;
@@ -957,26 +960,27 @@ static void fec_enet_bd_init(struct net_device *dev)
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
DMA_TO_DEVICE);
- if (txq->tx_buf[i].skb) {
- dev_kfree_skb_any(txq->tx_buf[i].skb);
- txq->tx_buf[i].skb = NULL;
- }
- } else {
+ if (txq->tx_buf[i].buf_p)
+ dev_kfree_skb_any(txq->tx_buf[i].buf_p);
+ } else if (txq->tx_buf[i].type == FEC_TXBUF_T_XDP_NDO) {
if (bdp->cbd_bufaddr)
dma_unmap_single(&fep->pdev->dev,
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
DMA_TO_DEVICE);
- if (txq->tx_buf[i].xdp) {
- xdp_return_frame(txq->tx_buf[i].xdp);
- txq->tx_buf[i].xdp = NULL;
- }
+ if (txq->tx_buf[i].buf_p)
+ xdp_return_frame(txq->tx_buf[i].buf_p);
+ } else {
+ struct page *page = txq->tx_buf[i].buf_p;
- /* restore default tx buffer type: FEC_TXBUF_T_SKB */
- txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
+ if (page)
+ page_pool_put_page(page->pp, page, 0, false);
}
+ txq->tx_buf[i].buf_p = NULL;
+ /* restore default tx buffer type: FEC_TXBUF_T_SKB */
+ txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
bdp->cbd_bufaddr = cpu_to_fec32(0);
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
}
@@ -1383,6 +1387,8 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
struct netdev_queue *nq;
int index = 0;
int entries_free;
+ struct page *page;
+ int frame_len;
fep = netdev_priv(ndev);
@@ -1404,8 +1410,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
index = fec_enet_get_bd_index(bdp, &txq->bd);
if (txq->tx_buf[index].type == FEC_TXBUF_T_SKB) {
- skb = txq->tx_buf[index].skb;
- txq->tx_buf[index].skb = NULL;
+ skb = txq->tx_buf[index].buf_p;
if (bdp->cbd_bufaddr &&
!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
dma_unmap_single(&fep->pdev->dev,
@@ -1424,17 +1429,24 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
if (unlikely(!budget))
break;
- xdpf = txq->tx_buf[index].xdp;
- if (bdp->cbd_bufaddr)
- dma_unmap_single(&fep->pdev->dev,
- fec32_to_cpu(bdp->cbd_bufaddr),
- fec16_to_cpu(bdp->cbd_datlen),
- DMA_TO_DEVICE);
+ if (txq->tx_buf[index].type == FEC_TXBUF_T_XDP_NDO) {
+ xdpf = txq->tx_buf[index].buf_p;
+ if (bdp->cbd_bufaddr)
+ dma_unmap_single(&fep->pdev->dev,
+ fec32_to_cpu(bdp->cbd_bufaddr),
+ fec16_to_cpu(bdp->cbd_datlen),
+ DMA_TO_DEVICE);
+ } else {
+ page = txq->tx_buf[index].buf_p;
+ }
+
bdp->cbd_bufaddr = cpu_to_fec32(0);
- if (!xdpf) {
+ if (unlikely(!txq->tx_buf[index].buf_p)) {
txq->tx_buf[index].type = FEC_TXBUF_T_SKB;
goto tx_buf_done;
}
+
+ frame_len = fec16_to_cpu(bdp->cbd_datlen);
}
/* Check for errors. */
@@ -1458,7 +1470,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
if (txq->tx_buf[index].type == FEC_TXBUF_T_SKB)
ndev->stats.tx_bytes += skb->len;
else
- ndev->stats.tx_bytes += xdpf->len;
+ ndev->stats.tx_bytes += frame_len;
}
/* Deferred means some collisions occurred during transmit,
@@ -1482,15 +1494,18 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
}
/* Free the sk buffer associated with this last transmit */
- dev_kfree_skb_any(skb);
- } else {
- xdp_return_frame(xdpf);
-
- txq->tx_buf[index].xdp = NULL;
- /* restore default tx buffer type: FEC_TXBUF_T_SKB */
- txq->tx_buf[index].type = FEC_TXBUF_T_SKB;
+ napi_consume_skb(skb, budget);
+ } else if (txq->tx_buf[index].type == FEC_TXBUF_T_XDP_NDO) {
+ xdp_return_frame_rx_napi(xdpf);
+ } else { /* recycle pages of XDP_TX frames */
+ /* The dma_sync_size = 0 as XDP_TX has already synced DMA for_device */
+ page_pool_put_page(page->pp, page, 0, true);
}
+ txq->tx_buf[index].buf_p = NULL;
+ /* restore default tx buffer type: FEC_TXBUF_T_SKB */
+ txq->tx_buf[index].type = FEC_TXBUF_T_SKB;
+
tx_buf_done:
/* Make sure the update to bdp and tx_buf are performed
* before dirty_tx
@@ -1543,7 +1558,7 @@ static void fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq,
static u32
fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
- struct xdp_buff *xdp, struct fec_enet_priv_rx_q *rxq, int index)
+ struct xdp_buff *xdp, struct fec_enet_priv_rx_q *rxq, int cpu)
{
unsigned int sync, len = xdp->data_end - xdp->data;
u32 ret = FEC_ENET_XDP_PASS;
@@ -1553,8 +1568,10 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
act = bpf_prog_run_xdp(prog, xdp);
- /* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
- sync = xdp->data_end - xdp->data_hard_start - FEC_ENET_XDP_HEADROOM;
+ /* Due xdp_adjust_tail and xdp_adjust_head: DMA sync for_device cover
+ * max len CPU touch
+ */
+ sync = xdp->data_end - xdp->data;
sync = max(sync, len);
switch (act) {
@@ -1566,31 +1583,38 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
case XDP_REDIRECT:
rxq->stats[RX_XDP_REDIRECT]++;
err = xdp_do_redirect(fep->netdev, xdp, prog);
- if (!err) {
- ret = FEC_ENET_XDP_REDIR;
- } else {
- ret = FEC_ENET_XDP_CONSUMED;
- page = virt_to_head_page(xdp->data);
- page_pool_put_page(rxq->page_pool, page, sync, true);
+ if (unlikely(err))
+ goto xdp_err;
+
+ ret = FEC_ENET_XDP_REDIR;
+ break;
+
+ case XDP_TX:
+ rxq->stats[RX_XDP_TX]++;
+ err = fec_enet_xdp_tx_xmit(fep, cpu, xdp, sync);
+ if (unlikely(err)) {
+ rxq->stats[RX_XDP_TX_ERRORS]++;
+ goto xdp_err;
}
+
+ ret = FEC_ENET_XDP_TX;
break;
default:
bpf_warn_invalid_xdp_action(fep->netdev, prog, act);
fallthrough;
- case XDP_TX:
- bpf_warn_invalid_xdp_action(fep->netdev, prog, act);
- fallthrough;
-
case XDP_ABORTED:
fallthrough; /* handle aborts by dropping packet */
case XDP_DROP:
rxq->stats[RX_XDP_DROP]++;
+xdp_err:
ret = FEC_ENET_XDP_CONSUMED;
page = virt_to_head_page(xdp->data);
page_pool_put_page(rxq->page_pool, page, sync, true);
+ if (act != XDP_DROP)
+ trace_xdp_exception(fep->netdev, prog, act);
break;
}
@@ -1621,6 +1645,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog);
u32 ret, xdp_result = FEC_ENET_XDP_PASS;
u32 data_start = FEC_ENET_XDP_HEADROOM;
+ int cpu = smp_processor_id();
struct xdp_buff xdp;
struct page *page;
u32 sub_len = 4;
@@ -1699,7 +1724,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
/* subtract 16bit shift and FCS */
xdp_prepare_buff(&xdp, page_address(page),
data_start, pkt_len - sub_len, false);
- ret = fec_enet_run_xdp(fep, xdp_prog, &xdp, rxq, index);
+ ret = fec_enet_run_xdp(fep, xdp_prog, &xdp, rxq, cpu);
xdp_result |= ret;
if (ret != FEC_ENET_XDP_PASS)
goto rx_processing_done;
@@ -3059,44 +3084,6 @@ static int fec_enet_set_coalesce(struct net_device *ndev,
return 0;
}
-static int fec_enet_get_tunable(struct net_device *netdev,
- const struct ethtool_tunable *tuna,
- void *data)
-{
- struct fec_enet_private *fep = netdev_priv(netdev);
- int ret = 0;
-
- switch (tuna->id) {
- case ETHTOOL_RX_COPYBREAK:
- *(u32 *)data = fep->rx_copybreak;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int fec_enet_set_tunable(struct net_device *netdev,
- const struct ethtool_tunable *tuna,
- const void *data)
-{
- struct fec_enet_private *fep = netdev_priv(netdev);
- int ret = 0;
-
- switch (tuna->id) {
- case ETHTOOL_RX_COPYBREAK:
- fep->rx_copybreak = *(u32 *)data;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
/* LPI Sleep Ts count base on tx clk (clk_ref).
* The lpi sleep cnt value = X us / (cycle_ns).
*/
@@ -3234,8 +3221,6 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_sset_count = fec_enet_get_sset_count,
#endif
.get_ts_info = fec_enet_get_ts_info,
- .get_tunable = fec_enet_get_tunable,
- .set_tunable = fec_enet_set_tunable,
.get_wol = fec_enet_get_wol,
.set_wol = fec_enet_set_wol,
.get_eee = fec_enet_get_eee,
@@ -3245,38 +3230,10 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.self_test = net_selftest,
};
-static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-{
- struct fec_enet_private *fep = netdev_priv(ndev);
- struct phy_device *phydev = ndev->phydev;
-
- if (!netif_running(ndev))
- return -EINVAL;
-
- if (!phydev)
- return -ENODEV;
-
- if (fep->bufdesc_ex) {
- bool use_fec_hwts = !phy_has_hwtstamp(phydev);
-
- if (cmd == SIOCSHWTSTAMP) {
- if (use_fec_hwts)
- return fec_ptp_set(ndev, rq);
- fec_ptp_disable_hwts(ndev);
- } else if (cmd == SIOCGHWTSTAMP) {
- if (use_fec_hwts)
- return fec_ptp_get(ndev, rq);
- }
- }
-
- return phy_mii_ioctl(phydev, rq, cmd);
-}
-
static void fec_enet_free_buffers(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
unsigned int i;
- struct sk_buff *skb;
struct fec_enet_priv_tx_q *txq;
struct fec_enet_priv_rx_q *rxq;
unsigned int q;
@@ -3301,18 +3258,23 @@ static void fec_enet_free_buffers(struct net_device *ndev)
kfree(txq->tx_bounce[i]);
txq->tx_bounce[i] = NULL;
+ if (!txq->tx_buf[i].buf_p) {
+ txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
+ continue;
+ }
+
if (txq->tx_buf[i].type == FEC_TXBUF_T_SKB) {
- skb = txq->tx_buf[i].skb;
- txq->tx_buf[i].skb = NULL;
- dev_kfree_skb(skb);
+ dev_kfree_skb(txq->tx_buf[i].buf_p);
+ } else if (txq->tx_buf[i].type == FEC_TXBUF_T_XDP_NDO) {
+ xdp_return_frame(txq->tx_buf[i].buf_p);
} else {
- if (txq->tx_buf[i].xdp) {
- xdp_return_frame(txq->tx_buf[i].xdp);
- txq->tx_buf[i].xdp = NULL;
- }
+ struct page *page = txq->tx_buf[i].buf_p;
- txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
+ page_pool_put_page(page->pp, page, 0, false);
}
+
+ txq->tx_buf[i].buf_p = NULL;
+ txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
}
}
}
@@ -3835,12 +3797,14 @@ fec_enet_xdp_get_tx_queue(struct fec_enet_private *fep, int index)
static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,
struct fec_enet_priv_tx_q *txq,
- struct xdp_frame *frame)
+ void *frame, u32 dma_sync_len,
+ bool ndo_xmit)
{
unsigned int index, status, estatus;
struct bufdesc *bdp;
dma_addr_t dma_addr;
int entries_free;
+ u16 frame_len;
entries_free = fec_enet_get_free_txdesc_num(txq);
if (entries_free < MAX_SKB_FRAGS + 1) {
@@ -3855,17 +3819,37 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,
index = fec_enet_get_bd_index(bdp, &txq->bd);
- dma_addr = dma_map_single(&fep->pdev->dev, frame->data,
- frame->len, DMA_TO_DEVICE);
- if (dma_mapping_error(&fep->pdev->dev, dma_addr))
- return -ENOMEM;
+ if (ndo_xmit) {
+ struct xdp_frame *xdpf = frame;
+
+ dma_addr = dma_map_single(&fep->pdev->dev, xdpf->data,
+ xdpf->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&fep->pdev->dev, dma_addr))
+ return -ENOMEM;
+
+ frame_len = xdpf->len;
+ txq->tx_buf[index].buf_p = xdpf;
+ txq->tx_buf[index].type = FEC_TXBUF_T_XDP_NDO;
+ } else {
+ struct xdp_buff *xdpb = frame;
+ struct page *page;
+
+ page = virt_to_page(xdpb->data);
+ dma_addr = page_pool_get_dma_addr(page) +
+ (xdpb->data - xdpb->data_hard_start);
+ dma_sync_single_for_device(&fep->pdev->dev, dma_addr,
+ dma_sync_len, DMA_BIDIRECTIONAL);
+ frame_len = xdpb->data_end - xdpb->data;
+ txq->tx_buf[index].buf_p = page;
+ txq->tx_buf[index].type = FEC_TXBUF_T_XDP_TX;
+ }
status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST);
if (fep->bufdesc_ex)
estatus = BD_ENET_TX_INT;
bdp->cbd_bufaddr = cpu_to_fec32(dma_addr);
- bdp->cbd_datlen = cpu_to_fec16(frame->len);
+ bdp->cbd_datlen = cpu_to_fec16(frame_len);
if (fep->bufdesc_ex) {
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
@@ -3877,9 +3861,6 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,
ebdp->cbd_esc = cpu_to_fec32(estatus);
}
- txq->tx_buf[index].type = FEC_TXBUF_T_XDP_NDO;
- txq->tx_buf[index].xdp = frame;
-
/* Make sure the updates to rest of the descriptor are performed before
* transferring ownership.
*/
@@ -3905,6 +3886,29 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep,
return 0;
}
+static int fec_enet_xdp_tx_xmit(struct fec_enet_private *fep,
+ int cpu, struct xdp_buff *xdp,
+ u32 dma_sync_len)
+{
+ struct fec_enet_priv_tx_q *txq;
+ struct netdev_queue *nq;
+ int queue, ret;
+
+ queue = fec_enet_xdp_get_tx_queue(fep, cpu);
+ txq = fep->tx_queue[queue];
+ nq = netdev_get_tx_queue(fep->netdev, queue);
+
+ __netif_tx_lock(nq, cpu);
+
+ /* Avoid tx timeout as XDP shares the queue with kernel stack */
+ txq_trans_cond_update(nq);
+ ret = fec_enet_txq_xmit_frame(fep, txq, xdp, dma_sync_len, false);
+
+ __netif_tx_unlock(nq);
+
+ return ret;
+}
+
static int fec_enet_xdp_xmit(struct net_device *dev,
int num_frames,
struct xdp_frame **frames,
@@ -3927,7 +3931,7 @@ static int fec_enet_xdp_xmit(struct net_device *dev,
/* Avoid tx timeout as XDP shares the queue with kernel stack */
txq_trans_cond_update(nq);
for (i = 0; i < num_frames; i++) {
- if (fec_enet_txq_xmit_frame(fep, txq, frames[i]) < 0)
+ if (fec_enet_txq_xmit_frame(fep, txq, frames[i], 0, true) < 0)
break;
sent_frames++;
}
@@ -3937,6 +3941,37 @@ static int fec_enet_xdp_xmit(struct net_device *dev,
return sent_frames;
}
+static int fec_hwtstamp_get(struct net_device *ndev,
+ struct kernel_hwtstamp_config *config)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (!netif_running(ndev))
+ return -EINVAL;
+
+ if (!fep->bufdesc_ex)
+ return -EOPNOTSUPP;
+
+ fec_ptp_get(ndev, config);
+
+ return 0;
+}
+
+static int fec_hwtstamp_set(struct net_device *ndev,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (!netif_running(ndev))
+ return -EINVAL;
+
+ if (!fep->bufdesc_ex)
+ return -EOPNOTSUPP;
+
+ return fec_ptp_set(ndev, config, extack);
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
@@ -3946,13 +3981,15 @@ static const struct net_device_ops fec_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = fec_timeout,
.ndo_set_mac_address = fec_set_mac_address,
- .ndo_eth_ioctl = fec_enet_ioctl,
+ .ndo_eth_ioctl = phy_do_ioctl_running,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = fec_poll_controller,
#endif
.ndo_set_features = fec_set_features,
.ndo_bpf = fec_enet_bpf,
.ndo_xdp_xmit = fec_enet_xdp_xmit,
+ .ndo_hwtstamp_get = fec_hwtstamp_get,
+ .ndo_hwtstamp_set = fec_hwtstamp_set,
};
static const unsigned short offset_des_active_rxq[] = {
@@ -4018,9 +4055,6 @@ static int fec_enet_init(struct net_device *ndev)
if (ret)
goto free_queue_mem;
- /* make sure MAC we just acquired is programmed into the hw */
- fec_set_mac_address(ndev, NULL);
-
/* Set receive and transmit descriptor base. */
for (i = 0; i < fep->num_rx_queues; i++) {
struct fec_enet_priv_rx_q *rxq = fep->rx_queue[i];
@@ -4486,7 +4520,6 @@ fec_probe(struct platform_device *pdev)
if (fep->bufdesc_ex && fep->ptp_clock)
netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
- fep->rx_copybreak = COPYBREAK_DEFAULT;
INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
pm_runtime_mark_last_busy(&pdev->dev);
@@ -4526,7 +4559,7 @@ failed_ioremap:
return ret;
}
-static int
+static void
fec_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
@@ -4562,7 +4595,6 @@ fec_drv_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
- return 0;
}
static int __maybe_unused fec_suspend(struct device *dev)
@@ -4718,7 +4750,7 @@ static struct platform_driver fec_driver = {
},
.id_table = fec_devtype,
.probe = fec_probe,
- .remove = fec_drv_remove,
+ .remove_new = fec_drv_remove,
};
module_platform_driver(fec_driver);
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index b88816b71ddf..ebae71ec26c6 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -29,12 +29,12 @@
#include <linux/crc32.h>
#include <linux/hardirq.h>
#include <linux/delay.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -974,7 +974,7 @@ err_netdev:
return rv;
}
-static int
+static void
mpc52xx_fec_remove(struct platform_device *op)
{
struct net_device *ndev;
@@ -998,8 +998,6 @@ mpc52xx_fec_remove(struct platform_device *op)
release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
free_netdev(ndev);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1042,7 +1040,7 @@ static struct platform_driver mpc52xx_fec_driver = {
.of_match_table = mpc52xx_fec_match,
},
.probe = mpc52xx_fec_probe,
- .remove = mpc52xx_fec_remove,
+ .remove_new = mpc52xx_fec_remove,
#ifdef CONFIG_PM
.suspend = mpc52xx_fec_of_suspend,
.resume = mpc52xx_fec_of_resume,
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c
index 95f778cce98c..39689826cc8f 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c
@@ -13,10 +13,11 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
-#include <linux/of_platform.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/mpc52xx.h>
#include "fec_mpc52xx.h"
@@ -117,7 +118,7 @@ static int mpc52xx_fec_mdio_probe(struct platform_device *of)
return err;
}
-static int mpc52xx_fec_mdio_remove(struct platform_device *of)
+static void mpc52xx_fec_mdio_remove(struct platform_device *of)
{
struct mii_bus *bus = platform_get_drvdata(of);
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
@@ -126,8 +127,6 @@ static int mpc52xx_fec_mdio_remove(struct platform_device *of)
iounmap(priv->regs);
kfree(priv);
mdiobus_free(bus);
-
- return 0;
}
static const struct of_device_id mpc52xx_fec_mdio_match[] = {
@@ -145,7 +144,7 @@ struct platform_driver mpc52xx_fec_mdio_driver = {
.of_match_table = mpc52xx_fec_mdio_match,
},
.probe = mpc52xx_fec_mdio_probe,
- .remove = mpc52xx_fec_mdio_remove,
+ .remove_new = mpc52xx_fec_mdio_remove,
};
/* let fec driver call it, since this has to be registered before it */
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index ab86bb8562ef..181d9bfbee22 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -30,7 +30,6 @@
#include <linux/phy.h>
#include <linux/fec.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
@@ -443,21 +442,21 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
*/
static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
- struct fec_enet_private *adapter =
+ struct fec_enet_private *fep =
container_of(ptp, struct fec_enet_private, ptp_caps);
u64 ns;
unsigned long flags;
- mutex_lock(&adapter->ptp_clk_mutex);
+ mutex_lock(&fep->ptp_clk_mutex);
/* Check the ptp clock */
- if (!adapter->ptp_clk_on) {
- mutex_unlock(&adapter->ptp_clk_mutex);
+ if (!fep->ptp_clk_on) {
+ mutex_unlock(&fep->ptp_clk_mutex);
return -EINVAL;
}
- spin_lock_irqsave(&adapter->tmreg_lock, flags);
- ns = timecounter_read(&adapter->tc);
- spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
- mutex_unlock(&adapter->ptp_clk_mutex);
+ spin_lock_irqsave(&fep->tmreg_lock, flags);
+ ns = timecounter_read(&fep->tc);
+ spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+ mutex_unlock(&fep->ptp_clk_mutex);
*ts = ns_to_timespec64(ns);
@@ -606,28 +605,12 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
}
}
-/**
- * fec_ptp_disable_hwts - disable hardware time stamping
- * @ndev: pointer to net_device
- */
-void fec_ptp_disable_hwts(struct net_device *ndev)
-{
- struct fec_enet_private *fep = netdev_priv(ndev);
-
- fep->hwts_tx_en = 0;
- fep->hwts_rx_en = 0;
-}
-
-int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
+int fec_ptp_set(struct net_device *ndev, struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct hwtstamp_config config;
-
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- switch (config.tx_type) {
+ switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
fep->hwts_tx_en = 0;
break;
@@ -638,33 +621,28 @@ int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr)
return -ERANGE;
}
- switch (config.rx_filter) {
+ switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
fep->hwts_rx_en = 0;
break;
default:
fep->hwts_rx_en = 1;
- config.rx_filter = HWTSTAMP_FILTER_ALL;
+ config->rx_filter = HWTSTAMP_FILTER_ALL;
break;
}
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
- -EFAULT : 0;
+ return 0;
}
-int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr)
+void fec_ptp_get(struct net_device *ndev, struct kernel_hwtstamp_config *config)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct hwtstamp_config config;
-
- config.flags = 0;
- config.tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
- config.rx_filter = (fep->hwts_rx_en ?
- HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
- -EFAULT : 0;
+ config->flags = 0;
+ config->tx_type = fep->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ config->rx_filter = (fep->hwts_rx_en ?
+ HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
}
/*
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 9d85fb136e34..d96028f01770 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/fsl/guts.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c
index ab90fe2bee5e..406e75e9e5ea 100644
--- a/drivers/net/ethernet/freescale/fman/fman_port.c
+++ b/drivers/net/ethernet/freescale/fman/fman_port.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 43665806c590..9767586b4eb3 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -18,6 +18,7 @@
#include <linux/phylink.h>
#include <linux/etherdevice.h>
#include <linux/libfdt_env.h>
+#include <linux/platform_device.h>
#include "mac.h"
#include "fman_mac.h"
@@ -331,12 +332,11 @@ _return_of_node_put:
return err;
}
-static int mac_remove(struct platform_device *pdev)
+static void mac_remove(struct platform_device *pdev)
{
struct mac_device *mac_dev = platform_get_drvdata(pdev);
platform_device_unregister(mac_dev->priv->eth_dev);
- return 0;
}
static struct platform_driver mac_driver = {
@@ -345,7 +345,7 @@ static struct platform_driver mac_driver = {
.of_match_table = mac_match,
},
.probe = mac_probe,
- .remove = mac_remove,
+ .remove_new = mac_remove,
};
builtin_platform_driver(mac_driver);
diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h
index ad06f8d7924b..fe747915cc73 100644
--- a/drivers/net/ethernet/freescale/fman/mac.h
+++ b/drivers/net/ethernet/freescale/fman/mac.h
@@ -68,10 +68,6 @@ struct dpaa_eth_data {
extern const char *mac_driver_description;
-int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx);
-
-void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause,
- bool *tx_pause);
int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev);
#endif /* __MAC_H */
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 8844a9a04fcf..a6dfc8807d3d 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -318,14 +318,12 @@ fs_enet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct fs_enet_private *fep;
- const struct fs_platform_info *fpi;
u32 int_events;
u32 int_clr_events;
int nr, napi_ok;
int handled;
fep = netdev_priv(dev);
- fpi = fep->fpi;
nr = 0;
while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {
@@ -1051,7 +1049,7 @@ out_free_fpi:
return ret;
}
-static int fs_enet_remove(struct platform_device *ofdev)
+static void fs_enet_remove(struct platform_device *ofdev)
{
struct net_device *ndev = platform_get_drvdata(ofdev);
struct fs_enet_private *fep = netdev_priv(ndev);
@@ -1066,7 +1064,6 @@ static int fs_enet_remove(struct platform_device *ofdev)
if (of_phy_is_fixed_link(ofdev->dev.of_node))
of_phy_deregister_fixed_link(ofdev->dev.of_node);
free_netdev(ndev);
- return 0;
}
static const struct of_device_id fs_enet_match[] = {
@@ -1113,7 +1110,7 @@ static struct platform_driver fs_enet_driver = {
.of_match_table = fs_enet_match,
},
.probe = fs_enet_probe,
- .remove = fs_enet_remove,
+ .remove_new = fs_enet_remove,
};
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
index cb419aef8d1b..759bb7080e22 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
@@ -2,6 +2,7 @@
#ifndef FS_ENET_H
#define FS_ENET_H
+#include <linux/clk.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/types.h>
@@ -9,7 +10,6 @@
#include <linux/phy.h>
#include <linux/dma-mapping.h>
-#include <linux/fs_enet_pd.h>
#include <asm/fs_pd.h>
#ifdef CONFIG_CPM1
@@ -118,6 +118,23 @@ struct phy_info {
#define ENET_RX_ALIGN 16
#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
+struct fs_platform_info {
+ /* device specific information */
+ u32 cp_command; /* CPM page/sblock/mcn */
+
+ u32 dpram_offset;
+
+ struct device_node *phy_node;
+
+ int rx_ring, tx_ring; /* number of buffers on rx */
+ int rx_copybreak; /* limit we copy small frames */
+ int napi_weight; /* NAPI weight */
+
+ int use_rmii; /* use RMII mode */
+
+ struct clk *clk_per; /* 'per' clock for register access */
+};
+
struct fs_enet_private {
struct napi_struct napi;
struct device *dev; /* pointer back to the device (must be initialized first) */
@@ -192,11 +209,6 @@ void fs_cleanup_bds(struct net_device *dev);
#define PFX DRV_MODULE_NAME ": "
/***************************************************************************/
-
-int fs_enet_platform_init(void);
-void fs_enet_platform_cleanup(void);
-
-/***************************************************************************/
/* buffer descriptor access macros */
/* access macros */
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
index b47490be872c..d903a9012db0 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
@@ -32,7 +32,6 @@
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/gfp.h>
#include <linux/pgtable.h>
@@ -106,7 +105,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
goto out_ep;
fep->fcc.mem = (void __iomem *)cpm2_immr;
- fpi->dpram_offset = cpm_dpalloc(128, 32);
+ fpi->dpram_offset = cpm_muram_alloc(128, 32);
if (IS_ERR_VALUE(fpi->dpram_offset)) {
ret = fpi->dpram_offset;
goto out_fcccp;
@@ -548,7 +547,7 @@ static void tx_restart(struct net_device *dev)
}
/* Now update the TBPTR and dirty flag to the current buffer */
W32(ep, fen_genfcc.fcc_tbptr,
- (uint) (((void *)recheck_bd - fep->ring_base) +
+ (uint)(((void __iomem *)recheck_bd - fep->ring_base) +
fep->ring_mem_addr));
fep->dirty_tx = recheck_bd;
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
index 61f4b6e50d29..cdc89d83cf07 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c
@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/gfp.h>
@@ -340,11 +339,7 @@ static void restart(struct net_device *dev)
static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
struct fec __iomem *fecp = fep->fec.fecp;
-
- struct fec_info *feci = dev->phydev->mdio.bus->priv;
-
int i;
if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)
@@ -364,16 +359,6 @@ static void stop(struct net_device *dev)
FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);
fs_cleanup_bds(dev);
-
- /* shut down FEC1? that's where the mii bus is */
- if (fpi->has_phy) {
- FS(fecp, r_cntrl, fpi->use_rmii ?
- FEC_RCNTRL_RMII_MODE :
- FEC_RCNTRL_MII_MODE); /* MII/RMII enable */
- FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
- FW(fecp, ievent, FEC_ENET_MII);
- FW(fecp, mii_speed, feci->mii_speed);
- }
}
static void napi_clear_event_fs(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
index 64300ac13e02..a64cb6270515 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c
@@ -32,7 +32,6 @@
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <asm/irq.h>
#include <linux/uaccess.h>
@@ -134,13 +133,13 @@ static int allocate_bd(struct net_device *dev)
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) *
- sizeof(cbd_t), 8);
+ fep->ring_mem_addr = cpm_muram_alloc((fpi->tx_ring + fpi->rx_ring) *
+ sizeof(cbd_t), 8);
if (IS_ERR_VALUE(fep->ring_mem_addr))
return -ENOMEM;
fep->ring_base = (void __iomem __force*)
- cpm_dpram_addr(fep->ring_mem_addr);
+ cpm_muram_addr(fep->ring_mem_addr);
return 0;
}
@@ -150,7 +149,7 @@ static void free_bd(struct net_device *dev)
struct fs_enet_private *fep = netdev_priv(dev);
if (fep->ring_base)
- cpm_dpfree(fep->ring_mem_addr);
+ cpm_muram_free(fep->ring_mem_addr);
}
static void cleanup_data(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
index 21de56345503..f965a2329055 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
@@ -29,8 +29,8 @@
struct bb_info {
struct mdiobb_ctrl ctrl;
- __be32 __iomem *dir;
- __be32 __iomem *dat;
+ u32 __iomem *dir;
+ u32 __iomem *dat;
u32 mdio_msk;
u32 mdc_msk;
};
@@ -192,7 +192,7 @@ out:
return ret;
}
-static int fs_enet_mdio_remove(struct platform_device *ofdev)
+static void fs_enet_mdio_remove(struct platform_device *ofdev)
{
struct mii_bus *bus = platform_get_drvdata(ofdev);
struct bb_info *bitbang = bus->priv;
@@ -201,8 +201,6 @@ static int fs_enet_mdio_remove(struct platform_device *ofdev)
free_mdio_bitbang(bus);
iounmap(bitbang->dir);
kfree(bitbang);
-
- return 0;
}
static const struct of_device_id fs_enet_mdio_bb_match[] = {
@@ -219,7 +217,7 @@ static struct platform_driver fs_enet_bb_mdio_driver = {
.of_match_table = fs_enet_mdio_bb_match,
},
.probe = fs_enet_mdio_probe,
- .remove = fs_enet_mdio_remove,
+ .remove_new = fs_enet_mdio_remove,
};
module_platform_driver(fs_enet_bb_mdio_driver);
diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
index 59a8f0bd0f5c..a1e777a4b75f 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
@@ -31,6 +31,7 @@
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/pgtable.h>
@@ -187,7 +188,7 @@ out:
return ret;
}
-static int fs_enet_mdio_remove(struct platform_device *ofdev)
+static void fs_enet_mdio_remove(struct platform_device *ofdev)
{
struct mii_bus *bus = platform_get_drvdata(ofdev);
struct fec_info *fec = bus->priv;
@@ -196,8 +197,6 @@ static int fs_enet_mdio_remove(struct platform_device *ofdev)
iounmap(fec->fecp);
kfree(fec);
mdiobus_free(bus);
-
- return 0;
}
static const struct of_device_id fs_enet_mdio_fec_match[] = {
@@ -220,7 +219,7 @@ static struct platform_driver fs_enet_fec_mdio_driver = {
.of_match_table = fs_enet_mdio_fec_match,
},
.probe = fs_enet_mdio_probe,
- .remove = fs_enet_mdio_remove,
+ .remove_new = fs_enet_mdio_remove,
};
module_platform_driver(fs_enet_fec_mdio_driver);
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 9d58d8334467..eee675a25b2c 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -12,6 +12,7 @@
*/
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -511,7 +512,7 @@ error:
}
-static int fsl_pq_mdio_remove(struct platform_device *pdev)
+static void fsl_pq_mdio_remove(struct platform_device *pdev)
{
struct device *device = &pdev->dev;
struct mii_bus *bus = dev_get_drvdata(device);
@@ -521,8 +522,6 @@ static int fsl_pq_mdio_remove(struct platform_device *pdev)
iounmap(priv->map);
mdiobus_free(bus);
-
- return 0;
}
static struct platform_driver fsl_pq_mdio_driver = {
@@ -531,7 +530,7 @@ static struct platform_driver fsl_pq_mdio_driver = {
.of_match_table = fsl_pq_mdio_match,
},
.probe = fsl_pq_mdio_probe,
- .remove = fsl_pq_mdio_remove,
+ .remove_new = fsl_pq_mdio_remove,
};
module_platform_driver(fsl_pq_mdio_driver);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 38d5013c6fed..e3dfbd7a4236 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -60,6 +60,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -75,7 +76,6 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
@@ -3364,7 +3364,7 @@ register_fail:
return err;
}
-static int gfar_remove(struct platform_device *ofdev)
+static void gfar_remove(struct platform_device *ofdev)
{
struct gfar_private *priv = platform_get_drvdata(ofdev);
struct device_node *np = ofdev->dev.of_node;
@@ -3381,8 +3381,6 @@ static int gfar_remove(struct platform_device *ofdev)
gfar_free_rx_queues(priv);
gfar_free_tx_queues(priv);
free_gfar_dev(priv);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -3642,7 +3640,7 @@ static struct platform_driver gfar_driver = {
.of_match_table = gfar_match,
},
.probe = gfar_probe,
- .remove = gfar_remove,
+ .remove_new = gfar_remove,
};
module_platform_driver(gfar_driver);
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index b2b0d3c26fcc..7a15b9245698 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -38,7 +38,9 @@
#include <linux/phy.h>
#include <linux/sort.h>
#include <linux/if_vlan.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/fsl/ptp_qoriq.h>
#include "gianfar.h"
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 7a4cb4f07c32..ab421243a419 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -28,11 +28,12 @@
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/workqueue.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
@@ -3753,7 +3754,7 @@ err_free_info:
return err;
}
-static int ucc_geth_remove(struct platform_device* ofdev)
+static void ucc_geth_remove(struct platform_device* ofdev)
{
struct net_device *dev = platform_get_drvdata(ofdev);
struct ucc_geth_private *ugeth = netdev_priv(dev);
@@ -3767,8 +3768,6 @@ static int ucc_geth_remove(struct platform_device* ofdev)
of_node_put(ugeth->ug_info->phy_node);
kfree(ugeth->ug_info);
free_netdev(dev);
-
- return 0;
}
static const struct of_device_id ucc_geth_match[] = {
@@ -3787,7 +3786,7 @@ static struct platform_driver ucc_geth_driver = {
.of_match_table = ucc_geth_match,
},
.probe = ucc_geth_probe,
- .remove = ucc_geth_remove,
+ .remove_new = ucc_geth_remove,
.suspend = ucc_geth_suspend,
.resume = ucc_geth_resume,
};
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c
index a13b4ba4d6e1..65dc07d0df0f 100644
--- a/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ b/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -19,10 +19,10 @@
#include <linux/kernel.h>
#include <linux/mdio.h>
#include <linux/module.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
#include <linux/phy.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
/* Number of microseconds to wait for a register to respond */
diff --git a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h
index 53b7e95213a8..5eec552a1f24 100644
--- a/drivers/net/ethernet/fungible/funeth/funeth_txrx.h
+++ b/drivers/net/ethernet/fungible/funeth/funeth_txrx.h
@@ -5,6 +5,7 @@
#include <linux/netdevice.h>
#include <linux/u64_stats_sync.h>
+#include <net/xdp.h>
/* Tx descriptor size */
#define FUNETH_SQE_SIZE 64U
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
index 4b425bf71ede..0d1e681be250 100644
--- a/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/u64_stats_sync.h>
+#include <net/xdp.h>
#include "gve_desc.h"
#include "gve_desc_dqo.h"
@@ -51,6 +52,26 @@
#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define DQO_QPL_DEFAULT_TX_PAGES 512
+#define DQO_QPL_DEFAULT_RX_PAGES 2048
+
+/* Maximum TSO size supported on DQO */
+#define GVE_DQO_TX_MAX 0x3FFFF
+
+#define GVE_TX_BUF_SHIFT_DQO 11
+
+/* 2K buffers for DQO-QPL */
+#define GVE_TX_BUF_SIZE_DQO BIT(GVE_TX_BUF_SHIFT_DQO)
+#define GVE_TX_BUFS_PER_PAGE_DQO (PAGE_SIZE >> GVE_TX_BUF_SHIFT_DQO)
+#define GVE_MAX_TX_BUFS_PER_PKT (DIV_ROUND_UP(GVE_DQO_TX_MAX, GVE_TX_BUF_SIZE_DQO))
+
+/* If number of free/recyclable buffers are less than this threshold; driver
+ * allocs and uses a non-qpl page on the receive path of DQO QPL to free
+ * up buffers.
+ * Value is set big enough to post at least 3 64K LRO packet via 2K buffer to NIC.
+ */
+#define GVE_DQO_QPL_ONDEMAND_ALLOC_THRESHOLD 96
+
/* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */
struct gve_rx_desc_queue {
struct gve_rx_desc *desc_ring; /* the descriptor ring */
@@ -217,6 +238,15 @@ struct gve_rx_ring {
* which cannot be reused yet.
*/
struct gve_index_list used_buf_states;
+
+ /* qpl assigned to this queue */
+ struct gve_queue_page_list *qpl;
+
+ /* index into queue page list */
+ u32 next_qpl_page_idx;
+
+ /* track number of used buffers */
+ u16 used_buf_states_cnt;
} dqo;
};
@@ -328,8 +358,14 @@ struct gve_tx_pending_packet_dqo {
* All others correspond to `skb`'s frags and should be unmapped with
* `dma_unmap_page`.
*/
- DEFINE_DMA_UNMAP_ADDR(dma[MAX_SKB_FRAGS + 1]);
- DEFINE_DMA_UNMAP_LEN(len[MAX_SKB_FRAGS + 1]);
+ union {
+ struct {
+ DEFINE_DMA_UNMAP_ADDR(dma[MAX_SKB_FRAGS + 1]);
+ DEFINE_DMA_UNMAP_LEN(len[MAX_SKB_FRAGS + 1]);
+ };
+ s16 tx_qpl_buf_ids[GVE_MAX_TX_BUFS_PER_PKT];
+ };
+
u16 num_bufs;
/* Linked list index to next element in the list, or -1 if none */
@@ -384,6 +420,32 @@ struct gve_tx_ring {
* set.
*/
u32 last_re_idx;
+
+ /* free running number of packet buf descriptors posted */
+ u16 posted_packet_desc_cnt;
+ /* free running number of packet buf descriptors completed */
+ u16 completed_packet_desc_cnt;
+
+ /* QPL fields */
+ struct {
+ /* Linked list of gve_tx_buf_dqo. Index into
+ * tx_qpl_buf_next, or -1 if empty.
+ *
+ * This is a consumer list owned by the TX path. When it
+ * runs out, the producer list is stolen from the
+ * completion handling path
+ * (dqo_compl.free_tx_qpl_buf_head).
+ */
+ s16 free_tx_qpl_buf_head;
+
+ /* Free running count of the number of QPL tx buffers
+ * allocated
+ */
+ u32 alloc_tx_qpl_buf_cnt;
+
+ /* Cached value of `dqo_compl.free_tx_qpl_buf_cnt` */
+ u32 free_tx_qpl_buf_cnt;
+ };
} dqo_tx;
};
@@ -427,6 +489,24 @@ struct gve_tx_ring {
* reached a specified timeout.
*/
struct gve_index_list timed_out_completions;
+
+ /* QPL fields */
+ struct {
+ /* Linked list of gve_tx_buf_dqo. Index into
+ * tx_qpl_buf_next, or -1 if empty.
+ *
+ * This is the producer list, owned by the completion
+ * handling path. When the consumer list
+ * (dqo_tx.free_tx_qpl_buf_head) is runs out, this list
+ * will be stolen.
+ */
+ atomic_t free_tx_qpl_buf_head;
+
+ /* Free running count of the number of tx buffers
+ * freed
+ */
+ atomic_t free_tx_qpl_buf_cnt;
+ };
} dqo_compl;
} ____cacheline_aligned;
u64 pkt_done; /* free-running - total packets completed */
@@ -453,6 +533,21 @@ struct gve_tx_ring {
s16 num_pending_packets;
u32 complq_mask; /* complq size is complq_mask + 1 */
+
+ /* QPL fields */
+ struct {
+ /* qpl assigned to this queue */
+ struct gve_queue_page_list *qpl;
+
+ /* Each QPL page is divided into TX bounce buffers
+ * of size GVE_TX_BUF_SIZE_DQO. tx_qpl_buf_next is
+ * an array to manage linked lists of TX buffers.
+ * An entry j at index i implies that j'th buffer
+ * is next on the list after i
+ */
+ s16 *tx_qpl_buf_next;
+ u32 num_tx_qpl_bufs;
+ };
} dqo;
} ____cacheline_aligned;
struct netdev_queue *netdev_txq;
@@ -531,6 +626,7 @@ enum gve_queue_format {
GVE_GQI_RDA_FORMAT = 0x1,
GVE_GQI_QPL_FORMAT = 0x2,
GVE_DQO_RDA_FORMAT = 0x3,
+ GVE_DQO_QPL_FORMAT = 0x4,
};
struct gve_priv {
@@ -550,7 +646,8 @@ struct gve_priv {
u16 num_event_counters;
u16 tx_desc_cnt; /* num desc per ring */
u16 rx_desc_cnt; /* num desc per ring */
- u16 tx_pages_per_qpl; /* tx buffer length */
+ u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */
+ u16 rx_pages_per_qpl; /* Suggested number of pages per qpl for RX queues by NIC */
u16 rx_data_slot_cnt; /* rx buffer length */
u64 max_registered_pages;
u64 num_registered_pages; /* num pages registered with NIC */
@@ -808,11 +905,17 @@ static inline u32 gve_rx_idx_to_ntfy(struct gve_priv *priv, u32 queue_idx)
return (priv->num_ntfy_blks / 2) + queue_idx;
}
+static inline bool gve_is_qpl(struct gve_priv *priv)
+{
+ return priv->queue_format == GVE_GQI_QPL_FORMAT ||
+ priv->queue_format == GVE_DQO_QPL_FORMAT;
+}
+
/* Returns the number of tx queue page lists
*/
static inline u32 gve_num_tx_qpls(struct gve_priv *priv)
{
- if (priv->queue_format != GVE_GQI_QPL_FORMAT)
+ if (!gve_is_qpl(priv))
return 0;
return priv->tx_cfg.num_queues + priv->num_xdp_queues;
@@ -832,7 +935,7 @@ static inline u32 gve_num_xdp_qpls(struct gve_priv *priv)
*/
static inline u32 gve_num_rx_qpls(struct gve_priv *priv)
{
- if (priv->queue_format != GVE_GQI_QPL_FORMAT)
+ if (!gve_is_qpl(priv))
return 0;
return priv->rx_cfg.num_queues;
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
index 252974202a3f..79db7a6d42bc 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -39,7 +39,8 @@ void gve_parse_device_option(struct gve_priv *priv,
struct gve_device_option_gqi_rda **dev_op_gqi_rda,
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
- struct gve_device_option_jumbo_frames **dev_op_jumbo_frames)
+ struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
+ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
{
u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
u16 option_length = be16_to_cpu(option->option_length);
@@ -112,6 +113,22 @@ void gve_parse_device_option(struct gve_priv *priv,
}
*dev_op_dqo_rda = (void *)(option + 1);
break;
+ case GVE_DEV_OPT_ID_DQO_QPL:
+ if (option_length < sizeof(**dev_op_dqo_qpl) ||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL) {
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
+ "DQO QPL", (int)sizeof(**dev_op_dqo_qpl),
+ GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL,
+ option_length, req_feat_mask);
+ break;
+ }
+
+ if (option_length > sizeof(**dev_op_dqo_qpl)) {
+ dev_warn(&priv->pdev->dev,
+ GVE_DEVICE_OPTION_TOO_BIG_FMT, "DQO QPL");
+ }
+ *dev_op_dqo_qpl = (void *)(option + 1);
+ break;
case GVE_DEV_OPT_ID_JUMBO_FRAMES:
if (option_length < sizeof(**dev_op_jumbo_frames) ||
req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES) {
@@ -146,7 +163,8 @@ gve_process_device_options(struct gve_priv *priv,
struct gve_device_option_gqi_rda **dev_op_gqi_rda,
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
- struct gve_device_option_jumbo_frames **dev_op_jumbo_frames)
+ struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
+ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
{
const int num_options = be16_to_cpu(descriptor->num_device_options);
struct gve_device_option *dev_opt;
@@ -166,7 +184,8 @@ gve_process_device_options(struct gve_priv *priv,
gve_parse_device_option(priv, descriptor, dev_opt,
dev_op_gqi_rda, dev_op_gqi_qpl,
- dev_op_dqo_rda, dev_op_jumbo_frames);
+ dev_op_dqo_rda, dev_op_jumbo_frames,
+ dev_op_dqo_qpl);
dev_opt = next_opt;
}
@@ -505,12 +524,24 @@ static int gve_adminq_create_tx_queue(struct gve_priv *priv, u32 queue_index)
cmd.create_tx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
} else {
+ u16 comp_ring_size;
+ u32 qpl_id = 0;
+
+ if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
+ qpl_id = GVE_RAW_ADDRESSING_QPL_ID;
+ comp_ring_size =
+ priv->options_dqo_rda.tx_comp_ring_entries;
+ } else {
+ qpl_id = tx->dqo.qpl->id;
+ comp_ring_size = priv->tx_desc_cnt;
+ }
+ cmd.create_tx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
cmd.create_tx_queue.tx_ring_size =
cpu_to_be16(priv->tx_desc_cnt);
cmd.create_tx_queue.tx_comp_ring_addr =
cpu_to_be64(tx->complq_bus_dqo);
cmd.create_tx_queue.tx_comp_ring_size =
- cpu_to_be16(priv->options_dqo_rda.tx_comp_ring_entries);
+ cpu_to_be16(comp_ring_size);
}
return gve_adminq_issue_cmd(priv, &cmd);
@@ -555,6 +586,18 @@ static int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index)
cmd.create_rx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
cmd.create_rx_queue.packet_buffer_size = cpu_to_be16(rx->packet_buffer_size);
} else {
+ u16 rx_buff_ring_entries;
+ u32 qpl_id = 0;
+
+ if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
+ qpl_id = GVE_RAW_ADDRESSING_QPL_ID;
+ rx_buff_ring_entries =
+ priv->options_dqo_rda.rx_buff_ring_entries;
+ } else {
+ qpl_id = rx->dqo.qpl->id;
+ rx_buff_ring_entries = priv->rx_desc_cnt;
+ }
+ cmd.create_rx_queue.queue_page_list_id = cpu_to_be32(qpl_id);
cmd.create_rx_queue.rx_ring_size =
cpu_to_be16(priv->rx_desc_cnt);
cmd.create_rx_queue.rx_desc_ring_addr =
@@ -564,7 +607,7 @@ static int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index)
cmd.create_rx_queue.packet_buffer_size =
cpu_to_be16(priv->data_buffer_size_dqo);
cmd.create_rx_queue.rx_buff_ring_size =
- cpu_to_be16(priv->options_dqo_rda.rx_buff_ring_entries);
+ cpu_to_be16(rx_buff_ring_entries);
cmd.create_rx_queue.enable_rsc =
!!(priv->dev->features & NETIF_F_LRO);
}
@@ -675,9 +718,13 @@ gve_set_desc_cnt_dqo(struct gve_priv *priv,
const struct gve_device_option_dqo_rda *dev_op_dqo_rda)
{
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
+ priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
+
+ if (priv->queue_format == GVE_DQO_QPL_FORMAT)
+ return 0;
+
priv->options_dqo_rda.tx_comp_ring_entries =
be16_to_cpu(dev_op_dqo_rda->tx_comp_ring_entries);
- priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
priv->options_dqo_rda.rx_buff_ring_entries =
be16_to_cpu(dev_op_dqo_rda->rx_buff_ring_entries);
@@ -687,7 +734,9 @@ gve_set_desc_cnt_dqo(struct gve_priv *priv,
static void gve_enable_supported_features(struct gve_priv *priv,
u32 supported_features_mask,
const struct gve_device_option_jumbo_frames
- *dev_op_jumbo_frames)
+ *dev_op_jumbo_frames,
+ const struct gve_device_option_dqo_qpl
+ *dev_op_dqo_qpl)
{
/* Before control reaches this point, the page-size-capped max MTU from
* the gve_device_descriptor field has already been stored in
@@ -699,6 +748,18 @@ static void gve_enable_supported_features(struct gve_priv *priv,
"JUMBO FRAMES device option enabled.\n");
priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu);
}
+
+ /* Override pages for qpl for DQO-QPL */
+ if (dev_op_dqo_qpl) {
+ priv->tx_pages_per_qpl =
+ be16_to_cpu(dev_op_dqo_qpl->tx_pages_per_qpl);
+ priv->rx_pages_per_qpl =
+ be16_to_cpu(dev_op_dqo_qpl->rx_pages_per_qpl);
+ if (priv->tx_pages_per_qpl == 0)
+ priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
+ if (priv->rx_pages_per_qpl == 0)
+ priv->rx_pages_per_qpl = DQO_QPL_DEFAULT_RX_PAGES;
+ }
}
int gve_adminq_describe_device(struct gve_priv *priv)
@@ -707,6 +768,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL;
struct gve_device_option_dqo_rda *dev_op_dqo_rda = NULL;
+ struct gve_device_option_dqo_qpl *dev_op_dqo_qpl = NULL;
struct gve_device_descriptor *descriptor;
u32 supported_features_mask = 0;
union gve_adminq_command cmd;
@@ -733,13 +795,14 @@ int gve_adminq_describe_device(struct gve_priv *priv)
err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda,
&dev_op_gqi_qpl, &dev_op_dqo_rda,
- &dev_op_jumbo_frames);
+ &dev_op_jumbo_frames,
+ &dev_op_dqo_qpl);
if (err)
goto free_device_descriptor;
/* If the GQI_RAW_ADDRESSING option is not enabled and the queue format
* is not set to GqiRda, choose the queue format in a priority order:
- * DqoRda, GqiRda, GqiQpl. Use GqiQpl as default.
+ * DqoRda, DqoQpl, GqiRda, GqiQpl. Use GqiQpl as default.
*/
if (dev_op_dqo_rda) {
priv->queue_format = GVE_DQO_RDA_FORMAT;
@@ -747,7 +810,11 @@ int gve_adminq_describe_device(struct gve_priv *priv)
"Driver is running with DQO RDA queue format.\n");
supported_features_mask =
be32_to_cpu(dev_op_dqo_rda->supported_features_mask);
- } else if (dev_op_gqi_rda) {
+ } else if (dev_op_dqo_qpl) {
+ priv->queue_format = GVE_DQO_QPL_FORMAT;
+ supported_features_mask =
+ be32_to_cpu(dev_op_dqo_qpl->supported_features_mask);
+ } else if (dev_op_gqi_rda) {
priv->queue_format = GVE_GQI_RDA_FORMAT;
dev_info(&priv->pdev->dev,
"Driver is running with GQI RDA queue format.\n");
@@ -798,7 +865,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
gve_enable_supported_features(priv, supported_features_mask,
- dev_op_jumbo_frames);
+ dev_op_jumbo_frames, dev_op_dqo_qpl);
free_device_descriptor:
dma_free_coherent(&priv->pdev->dev, PAGE_SIZE, descriptor,
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
index f894beb3deaf..38a22279e863 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -109,6 +109,14 @@ struct gve_device_option_dqo_rda {
static_assert(sizeof(struct gve_device_option_dqo_rda) == 8);
+struct gve_device_option_dqo_qpl {
+ __be32 supported_features_mask;
+ __be16 tx_pages_per_qpl;
+ __be16 rx_pages_per_qpl;
+};
+
+static_assert(sizeof(struct gve_device_option_dqo_qpl) == 8);
+
struct gve_device_option_jumbo_frames {
__be32 supported_features_mask;
__be16 max_mtu;
@@ -130,6 +138,7 @@ enum gve_dev_opt_id {
GVE_DEV_OPT_ID_GQI_RDA = 0x2,
GVE_DEV_OPT_ID_GQI_QPL = 0x3,
GVE_DEV_OPT_ID_DQO_RDA = 0x4,
+ GVE_DEV_OPT_ID_DQO_QPL = 0x7,
GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
};
@@ -139,6 +148,7 @@ enum gve_dev_opt_req_feat_mask {
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0,
+ GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0,
};
enum gve_sup_feature_mask {
diff --git a/drivers/net/ethernet/google/gve/gve_desc.h b/drivers/net/ethernet/google/gve/gve_desc.h
index f4ae9e19b844..c2874cdcf40c 100644
--- a/drivers/net/ethernet/google/gve/gve_desc.h
+++ b/drivers/net/ethernet/google/gve/gve_desc.h
@@ -105,10 +105,10 @@ union gve_rx_data_slot {
__be64 addr;
};
-/* GVE Recive Packet Descriptor Seq No */
+/* GVE Receive Packet Descriptor Seq No */
#define GVE_SEQNO(x) (be16_to_cpu(x) & 0x7)
-/* GVE Recive Packet Descriptor Flags */
+/* GVE Receive Packet Descriptor Flags */
#define GVE_RXFLG(x) cpu_to_be16(1 << (3 + (x)))
#define GVE_RXF_FRAG GVE_RXFLG(3) /* IP Fragment */
#define GVE_RXF_IPV4 GVE_RXFLG(4) /* IPv4 */
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index e6f1711d9be0..5704b5f57cd0 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -31,7 +31,6 @@
// Minimum amount of time between queue kicks in msec (10 seconds)
#define MIN_TX_TIMEOUT_GAP (1000 * 10)
-#define DQO_TX_MAX 0x3FFFF
char gve_driver_name[] = "gve";
const char gve_version_str[] = GVE_VERSION;
@@ -494,7 +493,7 @@ static int gve_setup_device_resources(struct gve_priv *priv)
goto abort_with_stats_report;
}
- if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
+ if (!gve_is_gqi(priv)) {
priv->ptype_lut_dqo = kvzalloc(sizeof(*priv->ptype_lut_dqo),
GFP_KERNEL);
if (!priv->ptype_lut_dqo) {
@@ -1083,11 +1082,12 @@ free_qpls:
static int gve_alloc_qpls(struct gve_priv *priv)
{
int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues;
+ int page_count;
int start_id;
int i, j;
int err;
- if (priv->queue_format != GVE_GQI_QPL_FORMAT)
+ if (!gve_is_qpl(priv))
return 0;
priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL);
@@ -1095,17 +1095,25 @@ static int gve_alloc_qpls(struct gve_priv *priv)
return -ENOMEM;
start_id = gve_tx_start_qpl_id(priv);
+ page_count = priv->tx_pages_per_qpl;
for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) {
err = gve_alloc_queue_page_list(priv, i,
- priv->tx_pages_per_qpl);
+ page_count);
if (err)
goto free_qpls;
}
start_id = gve_rx_start_qpl_id(priv);
+
+ /* For GQI_QPL number of pages allocated have 1:1 relationship with
+ * number of descriptors. For DQO, number of pages required are
+ * more than descriptors (because of out of order completions).
+ */
+ page_count = priv->queue_format == GVE_GQI_QPL_FORMAT ?
+ priv->rx_data_slot_cnt : priv->rx_pages_per_qpl;
for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) {
err = gve_alloc_queue_page_list(priv, i,
- priv->rx_data_slot_cnt);
+ page_count);
if (err)
goto free_qpls;
}
@@ -2051,7 +2059,7 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
/* Big TCP is only supported on DQ*/
if (!gve_is_gqi(priv))
- netif_set_tso_max_size(priv->dev, DQO_TX_MAX);
+ netif_set_tso_max_size(priv->dev, GVE_DQO_TX_MAX);
priv->num_registered_pages = 0;
priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK;
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
index e57b73eb70f6..ea0e38b4d9e9 100644
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -22,11 +22,13 @@ static int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs)
}
static void gve_free_page_dqo(struct gve_priv *priv,
- struct gve_rx_buf_state_dqo *bs)
+ struct gve_rx_buf_state_dqo *bs,
+ bool free_page)
{
page_ref_sub(bs->page_info.page, bs->page_info.pagecnt_bias - 1);
- gve_free_page(&priv->pdev->dev, bs->page_info.page, bs->addr,
- DMA_FROM_DEVICE);
+ if (free_page)
+ gve_free_page(&priv->pdev->dev, bs->page_info.page, bs->addr,
+ DMA_FROM_DEVICE);
bs->page_info.page = NULL;
}
@@ -130,12 +132,20 @@ gve_get_recycled_buf_state(struct gve_rx_ring *rx)
*/
for (i = 0; i < 5; i++) {
buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states);
- if (gve_buf_ref_cnt(buf_state) == 0)
+ if (gve_buf_ref_cnt(buf_state) == 0) {
+ rx->dqo.used_buf_states_cnt--;
return buf_state;
+ }
gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
}
+ /* For QPL, we cannot allocate any new buffers and must
+ * wait for the existing ones to be available.
+ */
+ if (rx->dqo.qpl)
+ return NULL;
+
/* If there are no free buf states discard an entry from
* `used_buf_states` so it can be used.
*/
@@ -144,23 +154,39 @@ gve_get_recycled_buf_state(struct gve_rx_ring *rx)
if (gve_buf_ref_cnt(buf_state) == 0)
return buf_state;
- gve_free_page_dqo(rx->gve, buf_state);
+ gve_free_page_dqo(rx->gve, buf_state, true);
gve_free_buf_state(rx, buf_state);
}
return NULL;
}
-static int gve_alloc_page_dqo(struct gve_priv *priv,
+static int gve_alloc_page_dqo(struct gve_rx_ring *rx,
struct gve_rx_buf_state_dqo *buf_state)
{
- int err;
+ struct gve_priv *priv = rx->gve;
+ u32 idx;
- err = gve_alloc_page(priv, &priv->pdev->dev, &buf_state->page_info.page,
- &buf_state->addr, DMA_FROM_DEVICE, GFP_ATOMIC);
- if (err)
- return err;
+ if (!rx->dqo.qpl) {
+ int err;
+ err = gve_alloc_page(priv, &priv->pdev->dev,
+ &buf_state->page_info.page,
+ &buf_state->addr,
+ DMA_FROM_DEVICE, GFP_ATOMIC);
+ if (err)
+ return err;
+ } else {
+ idx = rx->dqo.next_qpl_page_idx;
+ if (idx >= priv->rx_pages_per_qpl) {
+ net_err_ratelimited("%s: Out of QPL pages\n",
+ priv->dev->name);
+ return -ENOMEM;
+ }
+ buf_state->page_info.page = rx->dqo.qpl->pages[idx];
+ buf_state->addr = rx->dqo.qpl->page_buses[idx];
+ rx->dqo.next_qpl_page_idx++;
+ }
buf_state->page_info.page_offset = 0;
buf_state->page_info.page_address =
page_address(buf_state->page_info.page);
@@ -195,9 +221,13 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
for (i = 0; i < rx->dqo.num_buf_states; i++) {
struct gve_rx_buf_state_dqo *bs = &rx->dqo.buf_states[i];
-
+ /* Only free page for RDA. QPL pages are freed in gve_main. */
if (bs->page_info.page)
- gve_free_page_dqo(priv, bs);
+ gve_free_page_dqo(priv, bs, !rx->dqo.qpl);
+ }
+ if (rx->dqo.qpl) {
+ gve_unassign_qpl(priv, rx->dqo.qpl->id);
+ rx->dqo.qpl = NULL;
}
if (rx->dqo.bufq.desc_ring) {
@@ -229,7 +259,8 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
int i;
const u32 buffer_queue_slots =
- priv->options_dqo_rda.rx_buff_ring_entries;
+ priv->queue_format == GVE_DQO_RDA_FORMAT ?
+ priv->options_dqo_rda.rx_buff_ring_entries : priv->rx_desc_cnt;
const u32 completion_queue_slots = priv->rx_desc_cnt;
netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n");
@@ -243,7 +274,9 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
rx->ctx.skb_head = NULL;
rx->ctx.skb_tail = NULL;
- rx->dqo.num_buf_states = min_t(s16, S16_MAX, buffer_queue_slots * 4);
+ rx->dqo.num_buf_states = priv->queue_format == GVE_DQO_RDA_FORMAT ?
+ min_t(s16, S16_MAX, buffer_queue_slots * 4) :
+ priv->rx_pages_per_qpl;
rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
sizeof(rx->dqo.buf_states[0]),
GFP_KERNEL);
@@ -275,6 +308,13 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
if (!rx->dqo.bufq.desc_ring)
goto err;
+ if (priv->queue_format != GVE_DQO_RDA_FORMAT) {
+ rx->dqo.qpl = gve_assign_rx_qpl(priv, rx->q_num);
+ if (!rx->dqo.qpl)
+ goto err;
+ rx->dqo.next_qpl_page_idx = 0;
+ }
+
rx->q_resources = dma_alloc_coherent(hdev, sizeof(*rx->q_resources),
&rx->q_resources_bus, GFP_KERNEL);
if (!rx->q_resources)
@@ -352,7 +392,7 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
if (unlikely(!buf_state))
break;
- if (unlikely(gve_alloc_page_dqo(priv, buf_state))) {
+ if (unlikely(gve_alloc_page_dqo(rx, buf_state))) {
u64_stats_update_begin(&rx->statss);
rx->rx_buf_alloc_fail++;
u64_stats_update_end(&rx->statss);
@@ -415,6 +455,7 @@ static void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx,
mark_used:
gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state);
+ rx->dqo.used_buf_states_cnt++;
}
static void gve_rx_skb_csum(struct sk_buff *skb,
@@ -475,6 +516,43 @@ static void gve_rx_free_skb(struct gve_rx_ring *rx)
rx->ctx.skb_tail = NULL;
}
+static bool gve_rx_should_trigger_copy_ondemand(struct gve_rx_ring *rx)
+{
+ if (!rx->dqo.qpl)
+ return false;
+ if (rx->dqo.used_buf_states_cnt <
+ (rx->dqo.num_buf_states -
+ GVE_DQO_QPL_ONDEMAND_ALLOC_THRESHOLD))
+ return false;
+ return true;
+}
+
+static int gve_rx_copy_ondemand(struct gve_rx_ring *rx,
+ struct gve_rx_buf_state_dqo *buf_state,
+ u16 buf_len)
+{
+ struct page *page = alloc_page(GFP_ATOMIC);
+ int num_frags;
+
+ if (!page)
+ return -ENOMEM;
+
+ memcpy(page_address(page),
+ buf_state->page_info.page_address +
+ buf_state->page_info.page_offset,
+ buf_len);
+ num_frags = skb_shinfo(rx->ctx.skb_tail)->nr_frags;
+ skb_add_rx_frag(rx->ctx.skb_tail, num_frags, page,
+ 0, buf_len, PAGE_SIZE);
+
+ u64_stats_update_begin(&rx->statss);
+ rx->rx_frag_alloc_cnt++;
+ u64_stats_update_end(&rx->statss);
+ /* Return unused buffer. */
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state);
+ return 0;
+}
+
/* Chains multi skbs for single rx packet.
* Returns 0 if buffer is appended, -1 otherwise.
*/
@@ -502,12 +580,20 @@ static int gve_rx_append_frags(struct napi_struct *napi,
rx->ctx.skb_head->truesize += priv->data_buffer_size_dqo;
}
+ /* Trigger ondemand page allocation if we are running low on buffers */
+ if (gve_rx_should_trigger_copy_ondemand(rx))
+ return gve_rx_copy_ondemand(rx, buf_state, buf_len);
+
skb_add_rx_frag(rx->ctx.skb_tail, num_frags,
buf_state->page_info.page,
buf_state->page_info.page_offset,
buf_len, priv->data_buffer_size_dqo);
gve_dec_pagecnt_bias(&buf_state->page_info);
+ /* Advances buffer page-offset if page is partially used.
+ * Marks buffer as used if page is full.
+ */
+ gve_try_recycle_buf(priv, rx, buf_state);
return 0;
}
@@ -561,8 +647,6 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
priv)) != 0) {
goto error;
}
-
- gve_try_recycle_buf(priv, rx, buf_state);
return 0;
}
@@ -588,6 +672,12 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
goto error;
rx->ctx.skb_tail = rx->ctx.skb_head;
+ if (gve_rx_should_trigger_copy_ondemand(rx)) {
+ if (gve_rx_copy_ondemand(rx, buf_state, buf_len) < 0)
+ goto error;
+ return 0;
+ }
+
skb_add_rx_frag(rx->ctx.skb_head, 0, buf_state->page_info.page,
buf_state->page_info.page_offset, buf_len,
priv->data_buffer_size_dqo);
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
index 3c09e66ba1ab..1e19b834a613 100644
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -13,6 +13,89 @@
#include <linux/slab.h>
#include <linux/skbuff.h>
+/* Returns true if tx_bufs are available. */
+static bool gve_has_free_tx_qpl_bufs(struct gve_tx_ring *tx, int count)
+{
+ int num_avail;
+
+ if (!tx->dqo.qpl)
+ return true;
+
+ num_avail = tx->dqo.num_tx_qpl_bufs -
+ (tx->dqo_tx.alloc_tx_qpl_buf_cnt -
+ tx->dqo_tx.free_tx_qpl_buf_cnt);
+
+ if (count <= num_avail)
+ return true;
+
+ /* Update cached value from dqo_compl. */
+ tx->dqo_tx.free_tx_qpl_buf_cnt =
+ atomic_read_acquire(&tx->dqo_compl.free_tx_qpl_buf_cnt);
+
+ num_avail = tx->dqo.num_tx_qpl_bufs -
+ (tx->dqo_tx.alloc_tx_qpl_buf_cnt -
+ tx->dqo_tx.free_tx_qpl_buf_cnt);
+
+ return count <= num_avail;
+}
+
+static s16
+gve_alloc_tx_qpl_buf(struct gve_tx_ring *tx)
+{
+ s16 index;
+
+ index = tx->dqo_tx.free_tx_qpl_buf_head;
+
+ /* No TX buffers available, try to steal the list from the
+ * completion handler.
+ */
+ if (unlikely(index == -1)) {
+ tx->dqo_tx.free_tx_qpl_buf_head =
+ atomic_xchg(&tx->dqo_compl.free_tx_qpl_buf_head, -1);
+ index = tx->dqo_tx.free_tx_qpl_buf_head;
+
+ if (unlikely(index == -1))
+ return index;
+ }
+
+ /* Remove TX buf from free list */
+ tx->dqo_tx.free_tx_qpl_buf_head = tx->dqo.tx_qpl_buf_next[index];
+
+ return index;
+}
+
+static void
+gve_free_tx_qpl_bufs(struct gve_tx_ring *tx,
+ struct gve_tx_pending_packet_dqo *pkt)
+{
+ s16 index;
+ int i;
+
+ if (!pkt->num_bufs)
+ return;
+
+ index = pkt->tx_qpl_buf_ids[0];
+ /* Create a linked list of buffers to be added to the free list */
+ for (i = 1; i < pkt->num_bufs; i++) {
+ tx->dqo.tx_qpl_buf_next[index] = pkt->tx_qpl_buf_ids[i];
+ index = pkt->tx_qpl_buf_ids[i];
+ }
+
+ while (true) {
+ s16 old_head = atomic_read_acquire(&tx->dqo_compl.free_tx_qpl_buf_head);
+
+ tx->dqo.tx_qpl_buf_next[index] = old_head;
+ if (atomic_cmpxchg(&tx->dqo_compl.free_tx_qpl_buf_head,
+ old_head,
+ pkt->tx_qpl_buf_ids[0]) == old_head) {
+ break;
+ }
+ }
+
+ atomic_add(pkt->num_bufs, &tx->dqo_compl.free_tx_qpl_buf_cnt);
+ pkt->num_bufs = 0;
+}
+
/* Returns true if a gve_tx_pending_packet_dqo object is available. */
static bool gve_has_pending_packet(struct gve_tx_ring *tx)
{
@@ -136,9 +219,40 @@ static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx)
kvfree(tx->dqo.pending_packets);
tx->dqo.pending_packets = NULL;
+ kvfree(tx->dqo.tx_qpl_buf_next);
+ tx->dqo.tx_qpl_buf_next = NULL;
+
+ if (tx->dqo.qpl) {
+ gve_unassign_qpl(priv, tx->dqo.qpl->id);
+ tx->dqo.qpl = NULL;
+ }
+
netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx);
}
+static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx)
+{
+ int num_tx_qpl_bufs = GVE_TX_BUFS_PER_PAGE_DQO *
+ tx->dqo.qpl->num_entries;
+ int i;
+
+ tx->dqo.tx_qpl_buf_next = kvcalloc(num_tx_qpl_bufs,
+ sizeof(tx->dqo.tx_qpl_buf_next[0]),
+ GFP_KERNEL);
+ if (!tx->dqo.tx_qpl_buf_next)
+ return -ENOMEM;
+
+ tx->dqo.num_tx_qpl_bufs = num_tx_qpl_bufs;
+
+ /* Generate free TX buf list */
+ for (i = 0; i < num_tx_qpl_bufs - 1; i++)
+ tx->dqo.tx_qpl_buf_next[i] = i + 1;
+ tx->dqo.tx_qpl_buf_next[num_tx_qpl_bufs - 1] = -1;
+
+ atomic_set_release(&tx->dqo_compl.free_tx_qpl_buf_head, -1);
+ return 0;
+}
+
static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
{
struct gve_tx_ring *tx = &priv->tx[idx];
@@ -155,7 +269,9 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
/* Queue sizes must be a power of 2 */
tx->mask = priv->tx_desc_cnt - 1;
- tx->dqo.complq_mask = priv->options_dqo_rda.tx_comp_ring_entries - 1;
+ tx->dqo.complq_mask = priv->queue_format == GVE_DQO_RDA_FORMAT ?
+ priv->options_dqo_rda.tx_comp_ring_entries - 1 :
+ tx->mask;
/* The max number of pending packets determines the maximum number of
* descriptors which maybe written to the completion queue.
@@ -211,6 +327,15 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx)
if (!tx->q_resources)
goto err;
+ if (gve_is_qpl(priv)) {
+ tx->dqo.qpl = gve_assign_tx_qpl(priv, idx);
+ if (!tx->dqo.qpl)
+ goto err;
+
+ if (gve_tx_qpl_buf_init(tx))
+ goto err;
+ }
+
gve_tx_add_to_block(priv, idx);
return 0;
@@ -267,20 +392,27 @@ static u32 num_avail_tx_slots(const struct gve_tx_ring *tx)
return tx->mask - num_used;
}
+static bool gve_has_avail_slots_tx_dqo(struct gve_tx_ring *tx,
+ int desc_count, int buf_count)
+{
+ return gve_has_pending_packet(tx) &&
+ num_avail_tx_slots(tx) >= desc_count &&
+ gve_has_free_tx_qpl_bufs(tx, buf_count);
+}
+
/* Stops the queue if available descriptors is less than 'count'.
* Return: 0 if stop is not required.
*/
-static int gve_maybe_stop_tx_dqo(struct gve_tx_ring *tx, int count)
+static int gve_maybe_stop_tx_dqo(struct gve_tx_ring *tx,
+ int desc_count, int buf_count)
{
- if (likely(gve_has_pending_packet(tx) &&
- num_avail_tx_slots(tx) >= count))
+ if (likely(gve_has_avail_slots_tx_dqo(tx, desc_count, buf_count)))
return 0;
/* Update cached TX head pointer */
tx->dqo_tx.head = atomic_read_acquire(&tx->dqo_compl.hw_tx_head);
- if (likely(gve_has_pending_packet(tx) &&
- num_avail_tx_slots(tx) >= count))
+ if (likely(gve_has_avail_slots_tx_dqo(tx, desc_count, buf_count)))
return 0;
/* No space, so stop the queue */
@@ -295,8 +427,7 @@ static int gve_maybe_stop_tx_dqo(struct gve_tx_ring *tx, int count)
*/
tx->dqo_tx.head = atomic_read_acquire(&tx->dqo_compl.hw_tx_head);
- if (likely(!gve_has_pending_packet(tx) ||
- num_avail_tx_slots(tx) < count))
+ if (likely(!gve_has_avail_slots_tx_dqo(tx, desc_count, buf_count)))
return -EBUSY;
netif_tx_start_queue(tx->netdev_txq);
@@ -444,44 +575,16 @@ gve_tx_fill_general_ctx_desc(struct gve_tx_general_context_desc_dqo *desc,
};
}
-/* Returns 0 on success, or < 0 on error.
- *
- * Before this function is called, the caller must ensure
- * gve_has_pending_packet(tx) returns true.
- */
static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ struct gve_tx_pending_packet_dqo *pkt,
+ s16 completion_tag,
+ u32 *desc_idx,
+ bool is_gso)
{
const struct skb_shared_info *shinfo = skb_shinfo(skb);
- const bool is_gso = skb_is_gso(skb);
- u32 desc_idx = tx->dqo_tx.tail;
-
- struct gve_tx_pending_packet_dqo *pkt;
- struct gve_tx_metadata_dqo metadata;
- s16 completion_tag;
int i;
- pkt = gve_alloc_pending_packet(tx);
- pkt->skb = skb;
- pkt->num_bufs = 0;
- completion_tag = pkt - tx->dqo.pending_packets;
-
- gve_extract_tx_metadata_dqo(skb, &metadata);
- if (is_gso) {
- int header_len = gve_prep_tso(skb);
-
- if (unlikely(header_len < 0))
- goto err;
-
- gve_tx_fill_tso_ctx_desc(&tx->dqo.tx_ring[desc_idx].tso_ctx,
- skb, &metadata, header_len);
- desc_idx = (desc_idx + 1) & tx->mask;
- }
-
- gve_tx_fill_general_ctx_desc(&tx->dqo.tx_ring[desc_idx].general_ctx,
- &metadata);
- desc_idx = (desc_idx + 1) & tx->mask;
-
/* Note: HW requires that the size of a non-TSO packet be within the
* range of [17, 9728].
*
@@ -490,6 +593,7 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
* - Hypervisor won't allow MTU larger than 9216.
*/
+ pkt->num_bufs = 0;
/* Map the linear portion of skb */
{
u32 len = skb_headlen(skb);
@@ -503,7 +607,7 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
dma_unmap_addr_set(pkt, dma[pkt->num_bufs], addr);
++pkt->num_bufs;
- gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ gve_tx_fill_pkt_desc_dqo(tx, desc_idx, skb, len, addr,
completion_tag,
/*eop=*/shinfo->nr_frags == 0, is_gso);
}
@@ -522,10 +626,139 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
dma_unmap_addr_set(pkt, dma[pkt->num_bufs], addr);
++pkt->num_bufs;
- gve_tx_fill_pkt_desc_dqo(tx, &desc_idx, skb, len, addr,
+ gve_tx_fill_pkt_desc_dqo(tx, desc_idx, skb, len, addr,
completion_tag, is_eop, is_gso);
}
+ return 0;
+err:
+ for (i = 0; i < pkt->num_bufs; i++) {
+ if (i == 0) {
+ dma_unmap_single(tx->dev,
+ dma_unmap_addr(pkt, dma[i]),
+ dma_unmap_len(pkt, len[i]),
+ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(tx->dev,
+ dma_unmap_addr(pkt, dma[i]),
+ dma_unmap_len(pkt, len[i]),
+ DMA_TO_DEVICE);
+ }
+ }
+ pkt->num_bufs = 0;
+ return -1;
+}
+
+/* Tx buffer i corresponds to
+ * qpl_page_id = i / GVE_TX_BUFS_PER_PAGE_DQO
+ * qpl_page_offset = (i % GVE_TX_BUFS_PER_PAGE_DQO) * GVE_TX_BUF_SIZE_DQO
+ */
+static void gve_tx_buf_get_addr(struct gve_tx_ring *tx,
+ s16 index,
+ void **va, dma_addr_t *dma_addr)
+{
+ int page_id = index >> (PAGE_SHIFT - GVE_TX_BUF_SHIFT_DQO);
+ int offset = (index & (GVE_TX_BUFS_PER_PAGE_DQO - 1)) << GVE_TX_BUF_SHIFT_DQO;
+
+ *va = page_address(tx->dqo.qpl->pages[page_id]) + offset;
+ *dma_addr = tx->dqo.qpl->page_buses[page_id] + offset;
+}
+
+static int gve_tx_add_skb_copy_dqo(struct gve_tx_ring *tx,
+ struct sk_buff *skb,
+ struct gve_tx_pending_packet_dqo *pkt,
+ s16 completion_tag,
+ u32 *desc_idx,
+ bool is_gso)
+{
+ u32 copy_offset = 0;
+ dma_addr_t dma_addr;
+ u32 copy_len;
+ s16 index;
+ void *va;
+
+ /* Break the packet into buffer size chunks */
+ pkt->num_bufs = 0;
+ while (copy_offset < skb->len) {
+ index = gve_alloc_tx_qpl_buf(tx);
+ if (unlikely(index == -1))
+ goto err;
+
+ gve_tx_buf_get_addr(tx, index, &va, &dma_addr);
+ copy_len = min_t(u32, GVE_TX_BUF_SIZE_DQO,
+ skb->len - copy_offset);
+ skb_copy_bits(skb, copy_offset, va, copy_len);
+
+ copy_offset += copy_len;
+ dma_sync_single_for_device(tx->dev, dma_addr,
+ copy_len, DMA_TO_DEVICE);
+ gve_tx_fill_pkt_desc_dqo(tx, desc_idx, skb,
+ copy_len,
+ dma_addr,
+ completion_tag,
+ copy_offset == skb->len,
+ is_gso);
+
+ pkt->tx_qpl_buf_ids[pkt->num_bufs] = index;
+ ++tx->dqo_tx.alloc_tx_qpl_buf_cnt;
+ ++pkt->num_bufs;
+ }
+
+ return 0;
+err:
+ /* Should not be here if gve_has_free_tx_qpl_bufs() check is correct */
+ gve_free_tx_qpl_bufs(tx, pkt);
+ return -ENOMEM;
+}
+
+/* Returns 0 on success, or < 0 on error.
+ *
+ * Before this function is called, the caller must ensure
+ * gve_has_pending_packet(tx) returns true.
+ */
+static int gve_tx_add_skb_dqo(struct gve_tx_ring *tx,
+ struct sk_buff *skb)
+{
+ const bool is_gso = skb_is_gso(skb);
+ u32 desc_idx = tx->dqo_tx.tail;
+ struct gve_tx_pending_packet_dqo *pkt;
+ struct gve_tx_metadata_dqo metadata;
+ s16 completion_tag;
+
+ pkt = gve_alloc_pending_packet(tx);
+ pkt->skb = skb;
+ completion_tag = pkt - tx->dqo.pending_packets;
+
+ gve_extract_tx_metadata_dqo(skb, &metadata);
+ if (is_gso) {
+ int header_len = gve_prep_tso(skb);
+
+ if (unlikely(header_len < 0))
+ goto err;
+
+ gve_tx_fill_tso_ctx_desc(&tx->dqo.tx_ring[desc_idx].tso_ctx,
+ skb, &metadata, header_len);
+ desc_idx = (desc_idx + 1) & tx->mask;
+ }
+
+ gve_tx_fill_general_ctx_desc(&tx->dqo.tx_ring[desc_idx].general_ctx,
+ &metadata);
+ desc_idx = (desc_idx + 1) & tx->mask;
+
+ if (tx->dqo.qpl) {
+ if (gve_tx_add_skb_copy_dqo(tx, skb, pkt,
+ completion_tag,
+ &desc_idx, is_gso))
+ goto err;
+ } else {
+ if (gve_tx_add_skb_no_copy_dqo(tx, skb, pkt,
+ completion_tag,
+ &desc_idx, is_gso))
+ goto err;
+ }
+
+ tx->dqo_tx.posted_packet_desc_cnt += pkt->num_bufs;
+
/* Commit the changes to our state */
tx->dqo_tx.tail = desc_idx;
@@ -547,22 +780,7 @@ static int gve_tx_add_skb_no_copy_dqo(struct gve_tx_ring *tx,
return 0;
err:
- for (i = 0; i < pkt->num_bufs; i++) {
- if (i == 0) {
- dma_unmap_single(tx->dev,
- dma_unmap_addr(pkt, dma[i]),
- dma_unmap_len(pkt, len[i]),
- DMA_TO_DEVICE);
- } else {
- dma_unmap_page(tx->dev,
- dma_unmap_addr(pkt, dma[i]),
- dma_unmap_len(pkt, len[i]),
- DMA_TO_DEVICE);
- }
- }
-
pkt->skb = NULL;
- pkt->num_bufs = 0;
gve_free_pending_packet(tx, pkt);
return -1;
@@ -636,40 +854,56 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx,
int num_buffer_descs;
int total_num_descs;
- if (skb_is_gso(skb)) {
- /* If TSO doesn't meet HW requirements, attempt to linearize the
- * packet.
- */
- if (unlikely(!gve_can_send_tso(skb) &&
- skb_linearize(skb) < 0)) {
- net_err_ratelimited("%s: Failed to transmit TSO packet\n",
- priv->dev->name);
- goto drop;
- }
-
- if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
- goto drop;
+ if (tx->dqo.qpl) {
+ if (skb_is_gso(skb))
+ if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
+ goto drop;
- num_buffer_descs = gve_num_buffer_descs_needed(skb);
+ /* We do not need to verify the number of buffers used per
+ * packet or per segment in case of TSO as with 2K size buffers
+ * none of the TX packet rules would be violated.
+ *
+ * gve_can_send_tso() checks that each TCP segment of gso_size is
+ * not distributed over more than 9 SKB frags..
+ */
+ num_buffer_descs = DIV_ROUND_UP(skb->len, GVE_TX_BUF_SIZE_DQO);
} else {
- num_buffer_descs = gve_num_buffer_descs_needed(skb);
+ if (skb_is_gso(skb)) {
+ /* If TSO doesn't meet HW requirements, attempt to linearize the
+ * packet.
+ */
+ if (unlikely(!gve_can_send_tso(skb) &&
+ skb_linearize(skb) < 0)) {
+ net_err_ratelimited("%s: Failed to transmit TSO packet\n",
+ priv->dev->name);
+ goto drop;
+ }
- if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) {
- if (unlikely(skb_linearize(skb) < 0))
+ if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
goto drop;
- num_buffer_descs = 1;
+ num_buffer_descs = gve_num_buffer_descs_needed(skb);
+ } else {
+ num_buffer_descs = gve_num_buffer_descs_needed(skb);
+
+ if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) {
+ if (unlikely(skb_linearize(skb) < 0))
+ goto drop;
+
+ num_buffer_descs = 1;
+ }
}
}
/* Metadata + (optional TSO) + data descriptors. */
total_num_descs = 1 + skb_is_gso(skb) + num_buffer_descs;
if (unlikely(gve_maybe_stop_tx_dqo(tx, total_num_descs +
- GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP))) {
+ GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP,
+ num_buffer_descs))) {
return -1;
}
- if (unlikely(gve_tx_add_skb_no_copy_dqo(tx, skb) < 0))
+ if (unlikely(gve_tx_add_skb_dqo(tx, skb) < 0))
goto drop;
netdev_tx_sent_queue(tx->netdev_txq, skb->len);
@@ -817,7 +1051,11 @@ static void gve_handle_packet_completion(struct gve_priv *priv,
return;
}
}
- gve_unmap_packet(tx->dev, pending_packet);
+ tx->dqo_tx.completed_packet_desc_cnt += pending_packet->num_bufs;
+ if (tx->dqo.qpl)
+ gve_free_tx_qpl_bufs(tx, pending_packet);
+ else
+ gve_unmap_packet(tx->dev, pending_packet);
*bytes += pending_packet->skb->len;
(*pkts)++;
@@ -875,12 +1113,16 @@ static void remove_miss_completions(struct gve_priv *priv,
remove_from_list(tx, &tx->dqo_compl.miss_completions,
pending_packet);
- /* Unmap buffers and free skb but do not unallocate packet i.e.
+ /* Unmap/free TX buffers and free skb but do not unallocate packet i.e.
* the completion tag is not freed to ensure that the driver
* can take appropriate action if a corresponding valid
* completion is received later.
*/
- gve_unmap_packet(tx->dev, pending_packet);
+ if (tx->dqo.qpl)
+ gve_free_tx_qpl_bufs(tx, pending_packet);
+ else
+ gve_unmap_packet(tx->dev, pending_packet);
+
/* This indicates the packet was dropped. */
dev_kfree_skb_any(pending_packet->skb);
pending_packet->skb = NULL;
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
index 50c3f5d6611f..ecf92a5d56bb 100644
--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -960,8 +960,8 @@ static int hip04_mac_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- ret = -EINVAL;
+ if (irq < 0) {
+ ret = irq;
goto init_fail;
}
diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c
index ce2571c16e43..cb7b0293fe85 100644
--- a/drivers/net/ethernet/hisilicon/hisi_femac.c
+++ b/drivers/net/ethernet/hisilicon/hisi_femac.c
@@ -862,8 +862,8 @@ static int hisi_femac_drv_probe(struct platform_device *pdev)
goto out_disconnect_phy;
ndev->irq = platform_get_irq(pdev, 0);
- if (ndev->irq <= 0) {
- ret = -ENODEV;
+ if (ndev->irq < 0) {
+ ret = ndev->irq;
goto out_disconnect_phy;
}
diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
index f867e9531117..26d22bb04b87 100644
--- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c
@@ -1206,9 +1206,8 @@ static int hix5hd2_dev_probe(struct platform_device *pdev)
}
ndev->irq = platform_get_irq(pdev, 0);
- if (ndev->irq <= 0) {
- netdev_err(ndev, "No irq resource\n");
- ret = -EINVAL;
+ if (ndev->irq < 0) {
+ ret = ndev->irq;
goto out_phy_node;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index e3bb05959ba9..edf0bcf76ac9 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -422,7 +422,6 @@ void *hns_xgmac_config(struct hns_mac_cb *mac_cb,
struct mac_params *mac_param);
int hns_mac_init(struct dsaf_device *dsaf_dev);
-void mac_adjust_link(struct net_device *net_dev);
bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex);
void hns_mac_get_link_status(struct hns_mac_cb *mac_cb, u32 *link_status);
int hns_mac_change_vf_addr(struct hns_mac_cb *mac_cb, u32 vmid,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index a7eb87da4e70..a08d1f0a5a16 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -9,9 +9,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include "hns_dsaf_ppe.h"
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index e2ff3ca198d1..93344563a259 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -11,10 +11,6 @@
#include <linux/etherdevice.h>
#include <asm/cacheflush.h>
#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include "hns_dsaf_main.h"
diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile
index 6efea4662858..e214bfaece1f 100644
--- a/drivers/net/ethernet/hisilicon/hns3/Makefile
+++ b/drivers/net/ethernet/hisilicon/hns3/Makefile
@@ -17,11 +17,11 @@ hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o
obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o
-hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o \
+hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o \
hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
-hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o \
+hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_regs.o \
hns3pf/hclge_mbx.o hns3pf/hclge_err.o hns3pf/hclge_debugfs.o hns3pf/hclge_ptp.o hns3pf/hclge_devlink.o \
hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 514a20bce4f4..a4b43bcd2f0c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -382,6 +382,7 @@ struct hnae3_dev_specs {
u16 umv_size;
u16 mc_mac_size;
u32 mac_stats_num;
+ u8 tnl_num;
};
struct hnae3_client_ops {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index b7b51e56b030..eac2d0573241 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -18,6 +18,7 @@
#include <net/gre.h>
#include <net/gro.h>
#include <net/ip6_checksum.h>
+#include <net/page_pool/helpers.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include <net/tcp.h>
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index 88af34bbee34..acd756b0c7c9 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -6,7 +6,7 @@
#include <linux/dim.h>
#include <linux/if_vlan.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <asm/barrier.h>
#include "hnae3.h"
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 407d30ee55d2..36858a72d771 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -569,8 +569,8 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data)
{
- struct hns3_nic_priv *nic_priv = (struct hns3_nic_priv *)handle->priv;
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ struct hns3_nic_priv *nic_priv = handle->priv;
struct hns3_enet_ring *ring;
u8 *stat;
int i, j;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 91c173f40701..4d15eb73b972 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -826,7 +826,9 @@ struct hclge_dev_specs_1_cmd {
u8 rsv0[2];
__le16 umv_size;
__le16 mc_mac_size;
- u8 rsv1[12];
+ u8 rsv1[6];
+ u8 tnl_num;
+ u8 rsv2[5];
};
/* mac speed type defined in firmware command */
@@ -886,8 +888,4 @@ struct hclge_query_wol_supported_cmd {
struct hclge_hw;
int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
-enum hclge_comm_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw,
- struct hclge_desc *desc);
-enum hclge_comm_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw,
- struct hclge_desc *desc);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index 0fb2eaee3e8a..f01a7a9ee02c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -7,6 +7,7 @@
#include "hclge_debugfs.h"
#include "hclge_err.h"
#include "hclge_main.h"
+#include "hclge_regs.h"
#include "hclge_tm.h"
#include "hnae3.h"
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index a940e35aef29..0f50dba6cc47 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -20,6 +20,7 @@
#include "hclge_main.h"
#include "hclge_mbx.h"
#include "hclge_mdio.h"
+#include "hclge_regs.h"
#include "hclge_tm.h"
#include "hclge_err.h"
#include "hnae3.h"
@@ -40,20 +41,6 @@
#define HCLGE_PF_RESET_SYNC_TIME 20
#define HCLGE_PF_RESET_SYNC_CNT 1500
-/* Get DFX BD number offset */
-#define HCLGE_DFX_BIOS_BD_OFFSET 1
-#define HCLGE_DFX_SSU_0_BD_OFFSET 2
-#define HCLGE_DFX_SSU_1_BD_OFFSET 3
-#define HCLGE_DFX_IGU_BD_OFFSET 4
-#define HCLGE_DFX_RPU_0_BD_OFFSET 5
-#define HCLGE_DFX_RPU_1_BD_OFFSET 6
-#define HCLGE_DFX_NCSI_BD_OFFSET 7
-#define HCLGE_DFX_RTC_BD_OFFSET 8
-#define HCLGE_DFX_PPP_BD_OFFSET 9
-#define HCLGE_DFX_RCB_BD_OFFSET 10
-#define HCLGE_DFX_TQP_BD_OFFSET 11
-#define HCLGE_DFX_SSU_2_BD_OFFSET 12
-
#define HCLGE_LINK_STATUS_MS 10
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps);
@@ -94,62 +81,6 @@ static const struct pci_device_id ae_algo_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl);
-static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
- HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
- HCLGE_COMM_NIC_CSQ_DEPTH_REG,
- HCLGE_COMM_NIC_CSQ_TAIL_REG,
- HCLGE_COMM_NIC_CSQ_HEAD_REG,
- HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
- HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
- HCLGE_COMM_NIC_CRQ_DEPTH_REG,
- HCLGE_COMM_NIC_CRQ_TAIL_REG,
- HCLGE_COMM_NIC_CRQ_HEAD_REG,
- HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
- HCLGE_COMM_CMDQ_INTR_STS_REG,
- HCLGE_COMM_CMDQ_INTR_EN_REG,
- HCLGE_COMM_CMDQ_INTR_GEN_REG};
-
-static const u32 common_reg_addr_list[] = {HCLGE_MISC_VECTOR_REG_BASE,
- HCLGE_PF_OTHER_INT_REG,
- HCLGE_MISC_RESET_STS_REG,
- HCLGE_MISC_VECTOR_INT_STS,
- HCLGE_GLOBAL_RESET_REG,
- HCLGE_FUN_RST_ING,
- HCLGE_GRO_EN_REG};
-
-static const u32 ring_reg_addr_list[] = {HCLGE_RING_RX_ADDR_L_REG,
- HCLGE_RING_RX_ADDR_H_REG,
- HCLGE_RING_RX_BD_NUM_REG,
- HCLGE_RING_RX_BD_LENGTH_REG,
- HCLGE_RING_RX_MERGE_EN_REG,
- HCLGE_RING_RX_TAIL_REG,
- HCLGE_RING_RX_HEAD_REG,
- HCLGE_RING_RX_FBD_NUM_REG,
- HCLGE_RING_RX_OFFSET_REG,
- HCLGE_RING_RX_FBD_OFFSET_REG,
- HCLGE_RING_RX_STASH_REG,
- HCLGE_RING_RX_BD_ERR_REG,
- HCLGE_RING_TX_ADDR_L_REG,
- HCLGE_RING_TX_ADDR_H_REG,
- HCLGE_RING_TX_BD_NUM_REG,
- HCLGE_RING_TX_PRIORITY_REG,
- HCLGE_RING_TX_TC_REG,
- HCLGE_RING_TX_MERGE_EN_REG,
- HCLGE_RING_TX_TAIL_REG,
- HCLGE_RING_TX_HEAD_REG,
- HCLGE_RING_TX_FBD_NUM_REG,
- HCLGE_RING_TX_OFFSET_REG,
- HCLGE_RING_TX_EBD_NUM_REG,
- HCLGE_RING_TX_EBD_OFFSET_REG,
- HCLGE_RING_TX_BD_ERR_REG,
- HCLGE_RING_EN_REG};
-
-static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG,
- HCLGE_TQP_INTR_GL0_REG,
- HCLGE_TQP_INTR_GL1_REG,
- HCLGE_TQP_INTR_GL2_REG,
- HCLGE_TQP_INTR_RL_REG};
-
static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = {
"External Loopback test",
"App Loopback test",
@@ -375,36 +306,6 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = {
},
};
-static const u32 hclge_dfx_bd_offset_list[] = {
- HCLGE_DFX_BIOS_BD_OFFSET,
- HCLGE_DFX_SSU_0_BD_OFFSET,
- HCLGE_DFX_SSU_1_BD_OFFSET,
- HCLGE_DFX_IGU_BD_OFFSET,
- HCLGE_DFX_RPU_0_BD_OFFSET,
- HCLGE_DFX_RPU_1_BD_OFFSET,
- HCLGE_DFX_NCSI_BD_OFFSET,
- HCLGE_DFX_RTC_BD_OFFSET,
- HCLGE_DFX_PPP_BD_OFFSET,
- HCLGE_DFX_RCB_BD_OFFSET,
- HCLGE_DFX_TQP_BD_OFFSET,
- HCLGE_DFX_SSU_2_BD_OFFSET
-};
-
-static const enum hclge_opcode_type hclge_dfx_reg_opcode_list[] = {
- HCLGE_OPC_DFX_BIOS_COMMON_REG,
- HCLGE_OPC_DFX_SSU_REG_0,
- HCLGE_OPC_DFX_SSU_REG_1,
- HCLGE_OPC_DFX_IGU_EGU_REG,
- HCLGE_OPC_DFX_RPU_REG_0,
- HCLGE_OPC_DFX_RPU_REG_1,
- HCLGE_OPC_DFX_NCSI_REG,
- HCLGE_OPC_DFX_RTC_REG,
- HCLGE_OPC_DFX_PPP_REG,
- HCLGE_OPC_DFX_RCB_REG,
- HCLGE_OPC_DFX_TQP_REG,
- HCLGE_OPC_DFX_SSU_REG_2
-};
-
static const struct key_info meta_data_key_info[] = {
{ PACKET_TYPE_ID, 6 },
{ IP_FRAGEMENT, 1 },
@@ -1425,6 +1326,7 @@ static void hclge_set_default_dev_specs(struct hclge_dev *hdev)
ae_dev->dev_specs.max_frm_size = HCLGE_MAC_MAX_FRAME;
ae_dev->dev_specs.max_qset_num = HCLGE_MAX_QSET_NUM;
ae_dev->dev_specs.umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF;
+ ae_dev->dev_specs.tnl_num = 0;
}
static void hclge_parse_dev_specs(struct hclge_dev *hdev,
@@ -1448,6 +1350,7 @@ static void hclge_parse_dev_specs(struct hclge_dev *hdev,
ae_dev->dev_specs.max_frm_size = le16_to_cpu(req1->max_frm_size);
ae_dev->dev_specs.umv_size = le16_to_cpu(req1->umv_size);
ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size);
+ ae_dev->dev_specs.tnl_num = req1->tnl_num;
}
static void hclge_check_dev_specs(struct hclge_dev *hdev)
@@ -7317,14 +7220,14 @@ static int hclge_parse_cls_flower(struct hclge_dev *hdev,
struct flow_dissector *dissector = flow->match.dissector;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS))) {
- dev_err(&hdev->pdev->dev, "unsupported key set: %#x\n",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS))) {
+ dev_err(&hdev->pdev->dev, "unsupported key set: %#llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
@@ -12383,463 +12286,6 @@ out:
return ret;
}
-static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit,
- u32 *regs_num_64_bit)
-{
- struct hclge_desc desc;
- u32 total_num;
- int ret;
-
- hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true);
- ret = hclge_cmd_send(&hdev->hw, &desc, 1);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Query register number cmd failed, ret = %d.\n", ret);
- return ret;
- }
-
- *regs_num_32_bit = le32_to_cpu(desc.data[0]);
- *regs_num_64_bit = le32_to_cpu(desc.data[1]);
-
- total_num = *regs_num_32_bit + *regs_num_64_bit;
- if (!total_num)
- return -EINVAL;
-
- return 0;
-}
-
-static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
- void *data)
-{
-#define HCLGE_32_BIT_REG_RTN_DATANUM 8
-#define HCLGE_32_BIT_DESC_NODATA_LEN 2
-
- struct hclge_desc *desc;
- u32 *reg_val = data;
- __le32 *desc_data;
- int nodata_num;
- int cmd_num;
- int i, k, n;
- int ret;
-
- if (regs_num == 0)
- return 0;
-
- nodata_num = HCLGE_32_BIT_DESC_NODATA_LEN;
- cmd_num = DIV_ROUND_UP(regs_num + nodata_num,
- HCLGE_32_BIT_REG_RTN_DATANUM);
- desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true);
- ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Query 32 bit register cmd failed, ret = %d.\n", ret);
- kfree(desc);
- return ret;
- }
-
- for (i = 0; i < cmd_num; i++) {
- if (i == 0) {
- desc_data = (__le32 *)(&desc[i].data[0]);
- n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num;
- } else {
- desc_data = (__le32 *)(&desc[i]);
- n = HCLGE_32_BIT_REG_RTN_DATANUM;
- }
- for (k = 0; k < n; k++) {
- *reg_val++ = le32_to_cpu(*desc_data++);
-
- regs_num--;
- if (!regs_num)
- break;
- }
- }
-
- kfree(desc);
- return 0;
-}
-
-static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
- void *data)
-{
-#define HCLGE_64_BIT_REG_RTN_DATANUM 4
-#define HCLGE_64_BIT_DESC_NODATA_LEN 1
-
- struct hclge_desc *desc;
- u64 *reg_val = data;
- __le64 *desc_data;
- int nodata_len;
- int cmd_num;
- int i, k, n;
- int ret;
-
- if (regs_num == 0)
- return 0;
-
- nodata_len = HCLGE_64_BIT_DESC_NODATA_LEN;
- cmd_num = DIV_ROUND_UP(regs_num + nodata_len,
- HCLGE_64_BIT_REG_RTN_DATANUM);
- desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true);
- ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Query 64 bit register cmd failed, ret = %d.\n", ret);
- kfree(desc);
- return ret;
- }
-
- for (i = 0; i < cmd_num; i++) {
- if (i == 0) {
- desc_data = (__le64 *)(&desc[i].data[0]);
- n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len;
- } else {
- desc_data = (__le64 *)(&desc[i]);
- n = HCLGE_64_BIT_REG_RTN_DATANUM;
- }
- for (k = 0; k < n; k++) {
- *reg_val++ = le64_to_cpu(*desc_data++);
-
- regs_num--;
- if (!regs_num)
- break;
- }
- }
-
- kfree(desc);
- return 0;
-}
-
-#define MAX_SEPARATE_NUM 4
-#define SEPARATOR_VALUE 0xFDFCFBFA
-#define REG_NUM_PER_LINE 4
-#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(u32))
-#define REG_SEPARATOR_LINE 1
-#define REG_NUM_REMAIN_MASK 3
-
-int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc)
-{
- int i;
-
- /* initialize command BD except the last one */
- for (i = 0; i < HCLGE_GET_DFX_REG_TYPE_CNT - 1; i++) {
- hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM,
- true);
- desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
- }
-
- /* initialize the last command BD */
- hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, true);
-
- return hclge_cmd_send(&hdev->hw, desc, HCLGE_GET_DFX_REG_TYPE_CNT);
-}
-
-static int hclge_get_dfx_reg_bd_num(struct hclge_dev *hdev,
- int *bd_num_list,
- u32 type_num)
-{
- u32 entries_per_desc, desc_index, index, offset, i;
- struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
- int ret;
-
- ret = hclge_query_bd_num_cmd_send(hdev, desc);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get dfx bd num fail, status is %d.\n", ret);
- return ret;
- }
-
- entries_per_desc = ARRAY_SIZE(desc[0].data);
- for (i = 0; i < type_num; i++) {
- offset = hclge_dfx_bd_offset_list[i];
- index = offset % entries_per_desc;
- desc_index = offset / entries_per_desc;
- bd_num_list[i] = le32_to_cpu(desc[desc_index].data[index]);
- }
-
- return ret;
-}
-
-static int hclge_dfx_reg_cmd_send(struct hclge_dev *hdev,
- struct hclge_desc *desc_src, int bd_num,
- enum hclge_opcode_type cmd)
-{
- struct hclge_desc *desc = desc_src;
- int i, ret;
-
- hclge_cmd_setup_basic_desc(desc, cmd, true);
- for (i = 0; i < bd_num - 1; i++) {
- desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
- desc++;
- hclge_cmd_setup_basic_desc(desc, cmd, true);
- }
-
- desc = desc_src;
- ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Query dfx reg cmd(0x%x) send fail, status is %d.\n",
- cmd, ret);
-
- return ret;
-}
-
-static int hclge_dfx_reg_fetch_data(struct hclge_desc *desc_src, int bd_num,
- void *data)
-{
- int entries_per_desc, reg_num, separator_num, desc_index, index, i;
- struct hclge_desc *desc = desc_src;
- u32 *reg = data;
-
- entries_per_desc = ARRAY_SIZE(desc->data);
- reg_num = entries_per_desc * bd_num;
- separator_num = REG_NUM_PER_LINE - (reg_num & REG_NUM_REMAIN_MASK);
- for (i = 0; i < reg_num; i++) {
- index = i % entries_per_desc;
- desc_index = i / entries_per_desc;
- *reg++ = le32_to_cpu(desc[desc_index].data[index]);
- }
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
-
- return reg_num + separator_num;
-}
-
-static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len)
-{
- u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
- int data_len_per_desc, bd_num, i;
- int *bd_num_list;
- u32 data_len;
- int ret;
-
- bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL);
- if (!bd_num_list)
- return -ENOMEM;
-
- ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get dfx reg bd num fail, status is %d.\n", ret);
- goto out;
- }
-
- data_len_per_desc = sizeof_field(struct hclge_desc, data);
- *len = 0;
- for (i = 0; i < dfx_reg_type_num; i++) {
- bd_num = bd_num_list[i];
- data_len = data_len_per_desc * bd_num;
- *len += (data_len / REG_LEN_PER_LINE + 1) * REG_LEN_PER_LINE;
- }
-
-out:
- kfree(bd_num_list);
- return ret;
-}
-
-static int hclge_get_dfx_reg(struct hclge_dev *hdev, void *data)
-{
- u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
- int bd_num, bd_num_max, buf_len, i;
- struct hclge_desc *desc_src;
- int *bd_num_list;
- u32 *reg = data;
- int ret;
-
- bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL);
- if (!bd_num_list)
- return -ENOMEM;
-
- ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get dfx reg bd num fail, status is %d.\n", ret);
- goto out;
- }
-
- bd_num_max = bd_num_list[0];
- for (i = 1; i < dfx_reg_type_num; i++)
- bd_num_max = max_t(int, bd_num_max, bd_num_list[i]);
-
- buf_len = sizeof(*desc_src) * bd_num_max;
- desc_src = kzalloc(buf_len, GFP_KERNEL);
- if (!desc_src) {
- ret = -ENOMEM;
- goto out;
- }
-
- for (i = 0; i < dfx_reg_type_num; i++) {
- bd_num = bd_num_list[i];
- ret = hclge_dfx_reg_cmd_send(hdev, desc_src, bd_num,
- hclge_dfx_reg_opcode_list[i]);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get dfx reg fail, status is %d.\n", ret);
- break;
- }
-
- reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg);
- }
-
- kfree(desc_src);
-out:
- kfree(bd_num_list);
- return ret;
-}
-
-static int hclge_fetch_pf_reg(struct hclge_dev *hdev, void *data,
- struct hnae3_knic_private_info *kinfo)
-{
-#define HCLGE_RING_REG_OFFSET 0x200
-#define HCLGE_RING_INT_REG_OFFSET 0x4
-
- int i, j, reg_num, separator_num;
- int data_num_sum;
- u32 *reg = data;
-
- /* fetching per-PF registers valus from PF PCIe register space */
- reg_num = ARRAY_SIZE(cmdq_reg_addr_list);
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (i = 0; i < reg_num; i++)
- *reg++ = hclge_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- data_num_sum = reg_num + separator_num;
-
- reg_num = ARRAY_SIZE(common_reg_addr_list);
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (i = 0; i < reg_num; i++)
- *reg++ = hclge_read_dev(&hdev->hw, common_reg_addr_list[i]);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- data_num_sum += reg_num + separator_num;
-
- reg_num = ARRAY_SIZE(ring_reg_addr_list);
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (j = 0; j < kinfo->num_tqps; j++) {
- for (i = 0; i < reg_num; i++)
- *reg++ = hclge_read_dev(&hdev->hw,
- ring_reg_addr_list[i] +
- HCLGE_RING_REG_OFFSET * j);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- }
- data_num_sum += (reg_num + separator_num) * kinfo->num_tqps;
-
- reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list);
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (j = 0; j < hdev->num_msi_used - 1; j++) {
- for (i = 0; i < reg_num; i++)
- *reg++ = hclge_read_dev(&hdev->hw,
- tqp_intr_reg_addr_list[i] +
- HCLGE_RING_INT_REG_OFFSET * j);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- }
- data_num_sum += (reg_num + separator_num) * (hdev->num_msi_used - 1);
-
- return data_num_sum;
-}
-
-static int hclge_get_regs_len(struct hnae3_handle *handle)
-{
- int cmdq_lines, common_lines, ring_lines, tqp_intr_lines;
- struct hnae3_knic_private_info *kinfo = &handle->kinfo;
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- int regs_num_32_bit, regs_num_64_bit, dfx_regs_len;
- int regs_lines_32_bit, regs_lines_64_bit;
- int ret;
-
- ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get register number failed, ret = %d.\n", ret);
- return ret;
- }
-
- ret = hclge_get_dfx_reg_len(hdev, &dfx_regs_len);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get dfx reg len failed, ret = %d.\n", ret);
- return ret;
- }
-
- cmdq_lines = sizeof(cmdq_reg_addr_list) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
- common_lines = sizeof(common_reg_addr_list) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
- ring_lines = sizeof(ring_reg_addr_list) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
- tqp_intr_lines = sizeof(tqp_intr_reg_addr_list) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
- regs_lines_32_bit = regs_num_32_bit * sizeof(u32) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
- regs_lines_64_bit = regs_num_64_bit * sizeof(u64) / REG_LEN_PER_LINE +
- REG_SEPARATOR_LINE;
-
- return (cmdq_lines + common_lines + ring_lines * kinfo->num_tqps +
- tqp_intr_lines * (hdev->num_msi_used - 1) + regs_lines_32_bit +
- regs_lines_64_bit) * REG_LEN_PER_LINE + dfx_regs_len;
-}
-
-static void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
- void *data)
-{
- struct hnae3_knic_private_info *kinfo = &handle->kinfo;
- struct hclge_vport *vport = hclge_get_vport(handle);
- struct hclge_dev *hdev = vport->back;
- u32 regs_num_32_bit, regs_num_64_bit;
- int i, reg_num, separator_num, ret;
- u32 *reg = data;
-
- *version = hdev->fw_version;
-
- ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get register number failed, ret = %d.\n", ret);
- return;
- }
-
- reg += hclge_fetch_pf_reg(hdev, reg, kinfo);
-
- ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, reg);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get 32 bit register failed, ret = %d.\n", ret);
- return;
- }
- reg_num = regs_num_32_bit;
- reg += reg_num;
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
-
- ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit, reg);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "Get 64 bit register failed, ret = %d.\n", ret);
- return;
- }
- reg_num = regs_num_64_bit * 2;
- reg += reg_num;
- separator_num = MAX_SEPARATE_NUM - (reg_num & REG_NUM_REMAIN_MASK);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
-
- ret = hclge_get_dfx_reg(hdev, reg);
- if (ret)
- dev_err(&hdev->pdev->dev,
- "Get dfx register failed, ret = %d.\n", ret);
-}
-
static int hclge_set_led_status(struct hclge_dev *hdev, u8 locate_led_status)
{
struct hclge_set_led_state_cmd *req;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index 6a43d1515585..ec233ec57222 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -1142,11 +1142,8 @@ int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
u16 state,
struct hclge_vlan_info *vlan_info);
void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time);
-int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
- struct hclge_desc *desc);
void hclge_report_hw_error(struct hclge_dev *hdev,
enum hnae3_hw_error_type type);
-void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
int hclge_push_vf_link_status(struct hclge_vport *vport);
int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c
new file mode 100644
index 000000000000..43c1c18fa81f
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.c
@@ -0,0 +1,668 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2023 Hisilicon Limited.
+
+#include "hclge_cmd.h"
+#include "hclge_main.h"
+#include "hclge_regs.h"
+#include "hnae3.h"
+
+static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
+ HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
+ HCLGE_COMM_NIC_CSQ_DEPTH_REG,
+ HCLGE_COMM_NIC_CSQ_TAIL_REG,
+ HCLGE_COMM_NIC_CSQ_HEAD_REG,
+ HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
+ HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
+ HCLGE_COMM_NIC_CRQ_DEPTH_REG,
+ HCLGE_COMM_NIC_CRQ_TAIL_REG,
+ HCLGE_COMM_NIC_CRQ_HEAD_REG,
+ HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
+ HCLGE_COMM_CMDQ_INTR_STS_REG,
+ HCLGE_COMM_CMDQ_INTR_EN_REG,
+ HCLGE_COMM_CMDQ_INTR_GEN_REG};
+
+static const u32 common_reg_addr_list[] = {HCLGE_MISC_VECTOR_REG_BASE,
+ HCLGE_PF_OTHER_INT_REG,
+ HCLGE_MISC_RESET_STS_REG,
+ HCLGE_MISC_VECTOR_INT_STS,
+ HCLGE_GLOBAL_RESET_REG,
+ HCLGE_FUN_RST_ING,
+ HCLGE_GRO_EN_REG};
+
+static const u32 ring_reg_addr_list[] = {HCLGE_RING_RX_ADDR_L_REG,
+ HCLGE_RING_RX_ADDR_H_REG,
+ HCLGE_RING_RX_BD_NUM_REG,
+ HCLGE_RING_RX_BD_LENGTH_REG,
+ HCLGE_RING_RX_MERGE_EN_REG,
+ HCLGE_RING_RX_TAIL_REG,
+ HCLGE_RING_RX_HEAD_REG,
+ HCLGE_RING_RX_FBD_NUM_REG,
+ HCLGE_RING_RX_OFFSET_REG,
+ HCLGE_RING_RX_FBD_OFFSET_REG,
+ HCLGE_RING_RX_STASH_REG,
+ HCLGE_RING_RX_BD_ERR_REG,
+ HCLGE_RING_TX_ADDR_L_REG,
+ HCLGE_RING_TX_ADDR_H_REG,
+ HCLGE_RING_TX_BD_NUM_REG,
+ HCLGE_RING_TX_PRIORITY_REG,
+ HCLGE_RING_TX_TC_REG,
+ HCLGE_RING_TX_MERGE_EN_REG,
+ HCLGE_RING_TX_TAIL_REG,
+ HCLGE_RING_TX_HEAD_REG,
+ HCLGE_RING_TX_FBD_NUM_REG,
+ HCLGE_RING_TX_OFFSET_REG,
+ HCLGE_RING_TX_EBD_NUM_REG,
+ HCLGE_RING_TX_EBD_OFFSET_REG,
+ HCLGE_RING_TX_BD_ERR_REG,
+ HCLGE_RING_EN_REG};
+
+static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG,
+ HCLGE_TQP_INTR_GL0_REG,
+ HCLGE_TQP_INTR_GL1_REG,
+ HCLGE_TQP_INTR_GL2_REG,
+ HCLGE_TQP_INTR_RL_REG};
+
+/* Get DFX BD number offset */
+#define HCLGE_DFX_BIOS_BD_OFFSET 1
+#define HCLGE_DFX_SSU_0_BD_OFFSET 2
+#define HCLGE_DFX_SSU_1_BD_OFFSET 3
+#define HCLGE_DFX_IGU_BD_OFFSET 4
+#define HCLGE_DFX_RPU_0_BD_OFFSET 5
+#define HCLGE_DFX_RPU_1_BD_OFFSET 6
+#define HCLGE_DFX_NCSI_BD_OFFSET 7
+#define HCLGE_DFX_RTC_BD_OFFSET 8
+#define HCLGE_DFX_PPP_BD_OFFSET 9
+#define HCLGE_DFX_RCB_BD_OFFSET 10
+#define HCLGE_DFX_TQP_BD_OFFSET 11
+#define HCLGE_DFX_SSU_2_BD_OFFSET 12
+
+static const u32 hclge_dfx_bd_offset_list[] = {
+ HCLGE_DFX_BIOS_BD_OFFSET,
+ HCLGE_DFX_SSU_0_BD_OFFSET,
+ HCLGE_DFX_SSU_1_BD_OFFSET,
+ HCLGE_DFX_IGU_BD_OFFSET,
+ HCLGE_DFX_RPU_0_BD_OFFSET,
+ HCLGE_DFX_RPU_1_BD_OFFSET,
+ HCLGE_DFX_NCSI_BD_OFFSET,
+ HCLGE_DFX_RTC_BD_OFFSET,
+ HCLGE_DFX_PPP_BD_OFFSET,
+ HCLGE_DFX_RCB_BD_OFFSET,
+ HCLGE_DFX_TQP_BD_OFFSET,
+ HCLGE_DFX_SSU_2_BD_OFFSET
+};
+
+static const enum hclge_opcode_type hclge_dfx_reg_opcode_list[] = {
+ HCLGE_OPC_DFX_BIOS_COMMON_REG,
+ HCLGE_OPC_DFX_SSU_REG_0,
+ HCLGE_OPC_DFX_SSU_REG_1,
+ HCLGE_OPC_DFX_IGU_EGU_REG,
+ HCLGE_OPC_DFX_RPU_REG_0,
+ HCLGE_OPC_DFX_RPU_REG_1,
+ HCLGE_OPC_DFX_NCSI_REG,
+ HCLGE_OPC_DFX_RTC_REG,
+ HCLGE_OPC_DFX_PPP_REG,
+ HCLGE_OPC_DFX_RCB_REG,
+ HCLGE_OPC_DFX_TQP_REG,
+ HCLGE_OPC_DFX_SSU_REG_2
+};
+
+enum hclge_reg_tag {
+ HCLGE_REG_TAG_CMDQ = 0,
+ HCLGE_REG_TAG_COMMON,
+ HCLGE_REG_TAG_RING,
+ HCLGE_REG_TAG_TQP_INTR,
+ HCLGE_REG_TAG_QUERY_32_BIT,
+ HCLGE_REG_TAG_QUERY_64_BIT,
+ HCLGE_REG_TAG_DFX_BIOS_COMMON,
+ HCLGE_REG_TAG_DFX_SSU_0,
+ HCLGE_REG_TAG_DFX_SSU_1,
+ HCLGE_REG_TAG_DFX_IGU_EGU,
+ HCLGE_REG_TAG_DFX_RPU_0,
+ HCLGE_REG_TAG_DFX_RPU_1,
+ HCLGE_REG_TAG_DFX_NCSI,
+ HCLGE_REG_TAG_DFX_RTC,
+ HCLGE_REG_TAG_DFX_PPP,
+ HCLGE_REG_TAG_DFX_RCB,
+ HCLGE_REG_TAG_DFX_TQP,
+ HCLGE_REG_TAG_DFX_SSU_2,
+ HCLGE_REG_TAG_RPU_TNL,
+};
+
+#pragma pack(4)
+struct hclge_reg_tlv {
+ u16 tag;
+ u16 len;
+};
+
+struct hclge_reg_header {
+ u64 magic_number;
+ u8 is_vf;
+ u8 rsv[7];
+};
+
+#pragma pack()
+
+#define HCLGE_REG_TLV_SIZE sizeof(struct hclge_reg_tlv)
+#define HCLGE_REG_HEADER_SIZE sizeof(struct hclge_reg_header)
+#define HCLGE_REG_TLV_SPACE (sizeof(struct hclge_reg_tlv) / sizeof(u32))
+#define HCLGE_REG_HEADER_SPACE (sizeof(struct hclge_reg_header) / sizeof(u32))
+#define HCLGE_REG_MAGIC_NUMBER 0x686e733372656773 /* meaning is hns3regs */
+
+#define HCLGE_REG_RPU_TNL_ID_0 1
+
+static u32 hclge_reg_get_header(void *data)
+{
+ struct hclge_reg_header *header = data;
+
+ header->magic_number = HCLGE_REG_MAGIC_NUMBER;
+ header->is_vf = 0x0;
+
+ return HCLGE_REG_HEADER_SPACE;
+}
+
+static u32 hclge_reg_get_tlv(u32 tag, u32 regs_num, void *data)
+{
+ struct hclge_reg_tlv *tlv = data;
+
+ tlv->tag = tag;
+ tlv->len = regs_num * sizeof(u32) + HCLGE_REG_TLV_SIZE;
+
+ return HCLGE_REG_TLV_SPACE;
+}
+
+static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
+ void *data)
+{
+#define HCLGE_32_BIT_REG_RTN_DATANUM 8
+#define HCLGE_32_BIT_DESC_NODATA_LEN 2
+
+ struct hclge_desc *desc;
+ u32 *reg_val = data;
+ __le32 *desc_data;
+ int nodata_num;
+ int cmd_num;
+ int i, k, n;
+ int ret;
+
+ if (regs_num == 0)
+ return 0;
+
+ nodata_num = HCLGE_32_BIT_DESC_NODATA_LEN;
+ cmd_num = DIV_ROUND_UP(regs_num + nodata_num,
+ HCLGE_32_BIT_REG_RTN_DATANUM);
+ desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true);
+ ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Query 32 bit register cmd failed, ret = %d.\n", ret);
+ kfree(desc);
+ return ret;
+ }
+
+ for (i = 0; i < cmd_num; i++) {
+ if (i == 0) {
+ desc_data = (__le32 *)(&desc[i].data[0]);
+ n = HCLGE_32_BIT_REG_RTN_DATANUM - nodata_num;
+ } else {
+ desc_data = (__le32 *)(&desc[i]);
+ n = HCLGE_32_BIT_REG_RTN_DATANUM;
+ }
+ for (k = 0; k < n; k++) {
+ *reg_val++ = le32_to_cpu(*desc_data++);
+
+ regs_num--;
+ if (!regs_num)
+ break;
+ }
+ }
+
+ kfree(desc);
+ return 0;
+}
+
+static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
+ void *data)
+{
+#define HCLGE_64_BIT_REG_RTN_DATANUM 4
+#define HCLGE_64_BIT_DESC_NODATA_LEN 1
+
+ struct hclge_desc *desc;
+ u64 *reg_val = data;
+ __le64 *desc_data;
+ int nodata_len;
+ int cmd_num;
+ int i, k, n;
+ int ret;
+
+ if (regs_num == 0)
+ return 0;
+
+ nodata_len = HCLGE_64_BIT_DESC_NODATA_LEN;
+ cmd_num = DIV_ROUND_UP(regs_num + nodata_len,
+ HCLGE_64_BIT_REG_RTN_DATANUM);
+ desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true);
+ ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Query 64 bit register cmd failed, ret = %d.\n", ret);
+ kfree(desc);
+ return ret;
+ }
+
+ for (i = 0; i < cmd_num; i++) {
+ if (i == 0) {
+ desc_data = (__le64 *)(&desc[i].data[0]);
+ n = HCLGE_64_BIT_REG_RTN_DATANUM - nodata_len;
+ } else {
+ desc_data = (__le64 *)(&desc[i]);
+ n = HCLGE_64_BIT_REG_RTN_DATANUM;
+ }
+ for (k = 0; k < n; k++) {
+ *reg_val++ = le64_to_cpu(*desc_data++);
+
+ regs_num--;
+ if (!regs_num)
+ break;
+ }
+ }
+
+ kfree(desc);
+ return 0;
+}
+
+int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc)
+{
+ int i;
+
+ /* initialize command BD except the last one */
+ for (i = 0; i < HCLGE_GET_DFX_REG_TYPE_CNT - 1; i++) {
+ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM,
+ true);
+ desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
+ }
+
+ /* initialize the last command BD */
+ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_BD_NUM, true);
+
+ return hclge_cmd_send(&hdev->hw, desc, HCLGE_GET_DFX_REG_TYPE_CNT);
+}
+
+static int hclge_get_dfx_reg_bd_num(struct hclge_dev *hdev,
+ int *bd_num_list,
+ u32 type_num)
+{
+ u32 entries_per_desc, desc_index, index, offset, i;
+ struct hclge_desc desc[HCLGE_GET_DFX_REG_TYPE_CNT];
+ int ret;
+
+ ret = hclge_query_bd_num_cmd_send(hdev, desc);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get dfx bd num fail, status is %d.\n", ret);
+ return ret;
+ }
+
+ entries_per_desc = ARRAY_SIZE(desc[0].data);
+ for (i = 0; i < type_num; i++) {
+ offset = hclge_dfx_bd_offset_list[i];
+ index = offset % entries_per_desc;
+ desc_index = offset / entries_per_desc;
+ bd_num_list[i] = le32_to_cpu(desc[desc_index].data[index]);
+ }
+
+ return ret;
+}
+
+static int hclge_dfx_reg_cmd_send(struct hclge_dev *hdev,
+ struct hclge_desc *desc_src, int bd_num,
+ enum hclge_opcode_type cmd)
+{
+ struct hclge_desc *desc = desc_src;
+ int i, ret;
+
+ hclge_cmd_setup_basic_desc(desc, cmd, true);
+ for (i = 0; i < bd_num - 1; i++) {
+ desc->flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
+ desc++;
+ hclge_cmd_setup_basic_desc(desc, cmd, true);
+ }
+
+ desc = desc_src;
+ ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "Query dfx reg cmd(0x%x) send fail, status is %d.\n",
+ cmd, ret);
+
+ return ret;
+}
+
+/* tnl_id = 0 means get sum of all tnl reg's value */
+static int hclge_dfx_reg_rpu_tnl_cmd_send(struct hclge_dev *hdev, u32 tnl_id,
+ struct hclge_desc *desc, int bd_num)
+{
+ int i, ret;
+
+ for (i = 0; i < bd_num; i++) {
+ hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_DFX_RPU_REG_0,
+ true);
+ if (i != bd_num - 1)
+ desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
+ }
+
+ desc[0].data[0] = cpu_to_le32(tnl_id);
+ ret = hclge_cmd_send(&hdev->hw, desc, bd_num);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to query dfx rpu tnl reg, ret = %d\n",
+ ret);
+ return ret;
+}
+
+static int hclge_dfx_reg_fetch_data(struct hclge_desc *desc_src, int bd_num,
+ void *data)
+{
+ int entries_per_desc, reg_num, desc_index, index, i;
+ struct hclge_desc *desc = desc_src;
+ u32 *reg = data;
+
+ entries_per_desc = ARRAY_SIZE(desc->data);
+ reg_num = entries_per_desc * bd_num;
+ for (i = 0; i < reg_num; i++) {
+ index = i % entries_per_desc;
+ desc_index = i / entries_per_desc;
+ *reg++ = le32_to_cpu(desc[desc_index].data[index]);
+ }
+
+ return reg_num;
+}
+
+static int hclge_get_dfx_reg_len(struct hclge_dev *hdev, int *len)
+{
+ u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+ int data_len_per_desc;
+ int *bd_num_list;
+ int ret;
+ u32 i;
+
+ bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL);
+ if (!bd_num_list)
+ return -ENOMEM;
+
+ ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get dfx reg bd num fail, status is %d.\n", ret);
+ goto out;
+ }
+
+ data_len_per_desc = sizeof_field(struct hclge_desc, data);
+ *len = 0;
+ for (i = 0; i < dfx_reg_type_num; i++)
+ *len += bd_num_list[i] * data_len_per_desc + HCLGE_REG_TLV_SIZE;
+
+ /**
+ * the num of dfx_rpu_0 is reused by each dfx_rpu_tnl
+ * HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is
+ * starting at 0, so offset need '- 1'.
+ */
+ *len += (bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1] * data_len_per_desc +
+ HCLGE_REG_TLV_SIZE) * ae_dev->dev_specs.tnl_num;
+
+out:
+ kfree(bd_num_list);
+ return ret;
+}
+
+static int hclge_get_dfx_rpu_tnl_reg(struct hclge_dev *hdev, u32 *reg,
+ struct hclge_desc *desc_src,
+ int bd_num)
+{
+ struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
+ int ret = 0;
+ u8 i;
+
+ for (i = HCLGE_REG_RPU_TNL_ID_0; i <= ae_dev->dev_specs.tnl_num; i++) {
+ ret = hclge_dfx_reg_rpu_tnl_cmd_send(hdev, i, desc_src, bd_num);
+ if (ret)
+ break;
+
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RPU_TNL,
+ ARRAY_SIZE(desc_src->data) * bd_num,
+ reg);
+ reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg);
+ }
+
+ return ret;
+}
+
+static int hclge_get_dfx_reg(struct hclge_dev *hdev, void *data)
+{
+ u32 dfx_reg_type_num = ARRAY_SIZE(hclge_dfx_bd_offset_list);
+ int bd_num, bd_num_max, buf_len;
+ struct hclge_desc *desc_src;
+ int *bd_num_list;
+ u32 *reg = data;
+ int ret;
+ u32 i;
+
+ bd_num_list = kcalloc(dfx_reg_type_num, sizeof(int), GFP_KERNEL);
+ if (!bd_num_list)
+ return -ENOMEM;
+
+ ret = hclge_get_dfx_reg_bd_num(hdev, bd_num_list, dfx_reg_type_num);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get dfx reg bd num fail, status is %d.\n", ret);
+ goto out;
+ }
+
+ bd_num_max = bd_num_list[0];
+ for (i = 1; i < dfx_reg_type_num; i++)
+ bd_num_max = max_t(int, bd_num_max, bd_num_list[i]);
+
+ buf_len = sizeof(*desc_src) * bd_num_max;
+ desc_src = kzalloc(buf_len, GFP_KERNEL);
+ if (!desc_src) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < dfx_reg_type_num; i++) {
+ bd_num = bd_num_list[i];
+ ret = hclge_dfx_reg_cmd_send(hdev, desc_src, bd_num,
+ hclge_dfx_reg_opcode_list[i]);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get dfx reg fail, status is %d.\n", ret);
+ goto free;
+ }
+
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_DFX_BIOS_COMMON + i,
+ ARRAY_SIZE(desc_src->data) * bd_num,
+ reg);
+ reg += hclge_dfx_reg_fetch_data(desc_src, bd_num, reg);
+ }
+
+ /**
+ * HCLGE_DFX_BD_OFFSET is starting at 1, but the array subscript is
+ * starting at 0, so offset need '- 1'.
+ */
+ bd_num = bd_num_list[HCLGE_DFX_RPU_0_BD_OFFSET - 1];
+ ret = hclge_get_dfx_rpu_tnl_reg(hdev, reg, desc_src, bd_num);
+
+free:
+ kfree(desc_src);
+out:
+ kfree(bd_num_list);
+ return ret;
+}
+
+static int hclge_fetch_pf_reg(struct hclge_dev *hdev, void *data,
+ struct hnae3_knic_private_info *kinfo)
+{
+#define HCLGE_RING_REG_OFFSET 0x200
+#define HCLGE_RING_INT_REG_OFFSET 0x4
+
+ int i, j, reg_num;
+ int data_num_sum;
+ u32 *reg = data;
+
+ /* fetching per-PF registers valus from PF PCIe register space */
+ reg_num = ARRAY_SIZE(cmdq_reg_addr_list);
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_CMDQ, reg_num, reg);
+ for (i = 0; i < reg_num; i++)
+ *reg++ = hclge_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
+ data_num_sum = reg_num + HCLGE_REG_TLV_SPACE;
+
+ reg_num = ARRAY_SIZE(common_reg_addr_list);
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_COMMON, reg_num, reg);
+ for (i = 0; i < reg_num; i++)
+ *reg++ = hclge_read_dev(&hdev->hw, common_reg_addr_list[i]);
+ data_num_sum += reg_num + HCLGE_REG_TLV_SPACE;
+
+ reg_num = ARRAY_SIZE(ring_reg_addr_list);
+ for (j = 0; j < kinfo->num_tqps; j++) {
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_RING, reg_num, reg);
+ for (i = 0; i < reg_num; i++)
+ *reg++ = hclge_read_dev(&hdev->hw,
+ ring_reg_addr_list[i] +
+ HCLGE_RING_REG_OFFSET * j);
+ }
+ data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) * kinfo->num_tqps;
+
+ reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list);
+ for (j = 0; j < hdev->num_msi_used - 1; j++) {
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_TQP_INTR, reg_num, reg);
+ for (i = 0; i < reg_num; i++)
+ *reg++ = hclge_read_dev(&hdev->hw,
+ tqp_intr_reg_addr_list[i] +
+ HCLGE_RING_INT_REG_OFFSET * j);
+ }
+ data_num_sum += (reg_num + HCLGE_REG_TLV_SPACE) *
+ (hdev->num_msi_used - 1);
+
+ return data_num_sum;
+}
+
+static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit,
+ u32 *regs_num_64_bit)
+{
+ struct hclge_desc desc;
+ u32 total_num;
+ int ret;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Query register number cmd failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ *regs_num_32_bit = le32_to_cpu(desc.data[0]);
+ *regs_num_64_bit = le32_to_cpu(desc.data[1]);
+
+ total_num = *regs_num_32_bit + *regs_num_64_bit;
+ if (!total_num)
+ return -EINVAL;
+
+ return 0;
+}
+
+int hclge_get_regs_len(struct hnae3_handle *handle)
+{
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ int regs_num_32_bit, regs_num_64_bit, dfx_regs_len;
+ int cmdq_len, common_len, ring_len, tqp_intr_len;
+ int regs_len_32_bit, regs_len_64_bit;
+ struct hclge_dev *hdev = vport->back;
+ int ret;
+
+ ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get register number failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ ret = hclge_get_dfx_reg_len(hdev, &dfx_regs_len);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get dfx reg len failed, ret = %d.\n", ret);
+ return ret;
+ }
+
+ cmdq_len = HCLGE_REG_TLV_SIZE + sizeof(cmdq_reg_addr_list);
+ common_len = HCLGE_REG_TLV_SIZE + sizeof(common_reg_addr_list);
+ ring_len = HCLGE_REG_TLV_SIZE + sizeof(ring_reg_addr_list);
+ tqp_intr_len = HCLGE_REG_TLV_SIZE + sizeof(tqp_intr_reg_addr_list);
+ regs_len_32_bit = HCLGE_REG_TLV_SIZE + regs_num_32_bit * sizeof(u32);
+ regs_len_64_bit = HCLGE_REG_TLV_SIZE + regs_num_64_bit * sizeof(u64);
+
+ /* return the total length of all register values */
+ return HCLGE_REG_HEADER_SIZE + cmdq_len + common_len + ring_len *
+ kinfo->num_tqps + tqp_intr_len * (hdev->num_msi_used - 1) +
+ regs_len_32_bit + regs_len_64_bit + dfx_regs_len;
+}
+
+void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
+ void *data)
+{
+#define HCLGE_REG_64_BIT_SPACE_MULTIPLE 2
+
+ struct hnae3_knic_private_info *kinfo = &handle->kinfo;
+ struct hclge_vport *vport = hclge_get_vport(handle);
+ struct hclge_dev *hdev = vport->back;
+ u32 regs_num_32_bit, regs_num_64_bit;
+ u32 *reg = data;
+ int ret;
+
+ *version = hdev->fw_version;
+
+ ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get register number failed, ret = %d.\n", ret);
+ return;
+ }
+
+ reg += hclge_reg_get_header(reg);
+ reg += hclge_fetch_pf_reg(hdev, reg, kinfo);
+
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_32_BIT,
+ regs_num_32_bit, reg);
+ ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, reg);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get 32 bit register failed, ret = %d.\n", ret);
+ return;
+ }
+ reg += regs_num_32_bit;
+
+ reg += hclge_reg_get_tlv(HCLGE_REG_TAG_QUERY_64_BIT,
+ regs_num_64_bit *
+ HCLGE_REG_64_BIT_SPACE_MULTIPLE, reg);
+ ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit, reg);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "Get 64 bit register failed, ret = %d.\n", ret);
+ return;
+ }
+ reg += regs_num_64_bit * HCLGE_REG_64_BIT_SPACE_MULTIPLE;
+
+ ret = hclge_get_dfx_reg(hdev, reg);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "Get dfx register failed, ret = %d.\n", ret);
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h
new file mode 100644
index 000000000000..b6bc1ecb8054
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_regs.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+// Copyright (c) 2023 Hisilicon Limited.
+
+#ifndef __HCLGE_REGS_H
+#define __HCLGE_REGS_H
+#include <linux/types.h>
+#include "hclge_comm_cmd.h"
+
+struct hnae3_handle;
+struct hclge_dev;
+
+int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
+ struct hclge_desc *desc);
+int hclge_get_regs_len(struct hnae3_handle *handle);
+void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
+ void *data);
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 34f02ca8d1d2..7a2f9233d695 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -6,6 +6,7 @@
#include <net/rtnetlink.h>
#include "hclgevf_cmd.h"
#include "hclgevf_main.h"
+#include "hclgevf_regs.h"
#include "hclge_mbx.h"
#include "hnae3.h"
#include "hclgevf_devlink.h"
@@ -33,58 +34,6 @@ static const struct pci_device_id ae_algovf_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, ae_algovf_pci_tbl);
-static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
- HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
- HCLGE_COMM_NIC_CSQ_DEPTH_REG,
- HCLGE_COMM_NIC_CSQ_TAIL_REG,
- HCLGE_COMM_NIC_CSQ_HEAD_REG,
- HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
- HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
- HCLGE_COMM_NIC_CRQ_DEPTH_REG,
- HCLGE_COMM_NIC_CRQ_TAIL_REG,
- HCLGE_COMM_NIC_CRQ_HEAD_REG,
- HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
- HCLGE_COMM_VECTOR0_CMDQ_STATE_REG,
- HCLGE_COMM_CMDQ_INTR_EN_REG,
- HCLGE_COMM_CMDQ_INTR_GEN_REG};
-
-static const u32 common_reg_addr_list[] = {HCLGEVF_MISC_VECTOR_REG_BASE,
- HCLGEVF_RST_ING,
- HCLGEVF_GRO_EN_REG};
-
-static const u32 ring_reg_addr_list[] = {HCLGEVF_RING_RX_ADDR_L_REG,
- HCLGEVF_RING_RX_ADDR_H_REG,
- HCLGEVF_RING_RX_BD_NUM_REG,
- HCLGEVF_RING_RX_BD_LENGTH_REG,
- HCLGEVF_RING_RX_MERGE_EN_REG,
- HCLGEVF_RING_RX_TAIL_REG,
- HCLGEVF_RING_RX_HEAD_REG,
- HCLGEVF_RING_RX_FBD_NUM_REG,
- HCLGEVF_RING_RX_OFFSET_REG,
- HCLGEVF_RING_RX_FBD_OFFSET_REG,
- HCLGEVF_RING_RX_STASH_REG,
- HCLGEVF_RING_RX_BD_ERR_REG,
- HCLGEVF_RING_TX_ADDR_L_REG,
- HCLGEVF_RING_TX_ADDR_H_REG,
- HCLGEVF_RING_TX_BD_NUM_REG,
- HCLGEVF_RING_TX_PRIORITY_REG,
- HCLGEVF_RING_TX_TC_REG,
- HCLGEVF_RING_TX_MERGE_EN_REG,
- HCLGEVF_RING_TX_TAIL_REG,
- HCLGEVF_RING_TX_HEAD_REG,
- HCLGEVF_RING_TX_FBD_NUM_REG,
- HCLGEVF_RING_TX_OFFSET_REG,
- HCLGEVF_RING_TX_EBD_NUM_REG,
- HCLGEVF_RING_TX_EBD_OFFSET_REG,
- HCLGEVF_RING_TX_BD_ERR_REG,
- HCLGEVF_RING_EN_REG};
-
-static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG,
- HCLGEVF_TQP_INTR_GL0_REG,
- HCLGEVF_TQP_INTR_GL1_REG,
- HCLGEVF_TQP_INTR_GL2_REG,
- HCLGEVF_TQP_INTR_RL_REG};
-
/* hclgevf_cmd_send - send command to command queue
* @hw: pointer to the hw struct
* @desc: prefilled descriptor for describing the command
@@ -111,7 +60,7 @@ void hclgevf_arq_init(struct hclgevf_dev *hdev)
spin_unlock(&cmdq->crq.lock);
}
-static struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle)
+struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle)
{
if (!handle->client)
return container_of(handle, struct hclgevf_dev, nic);
@@ -3258,72 +3207,6 @@ static void hclgevf_get_link_mode(struct hnae3_handle *handle,
*advertising = hdev->hw.mac.advertising;
}
-#define MAX_SEPARATE_NUM 4
-#define SEPARATOR_VALUE 0xFDFCFBFA
-#define REG_NUM_PER_LINE 4
-#define REG_LEN_PER_LINE (REG_NUM_PER_LINE * sizeof(u32))
-
-static int hclgevf_get_regs_len(struct hnae3_handle *handle)
-{
- int cmdq_lines, common_lines, ring_lines, tqp_intr_lines;
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
-
- cmdq_lines = sizeof(cmdq_reg_addr_list) / REG_LEN_PER_LINE + 1;
- common_lines = sizeof(common_reg_addr_list) / REG_LEN_PER_LINE + 1;
- ring_lines = sizeof(ring_reg_addr_list) / REG_LEN_PER_LINE + 1;
- tqp_intr_lines = sizeof(tqp_intr_reg_addr_list) / REG_LEN_PER_LINE + 1;
-
- return (cmdq_lines + common_lines + ring_lines * hdev->num_tqps +
- tqp_intr_lines * (hdev->num_msi_used - 1)) * REG_LEN_PER_LINE;
-}
-
-static void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
- void *data)
-{
- struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
- int i, j, reg_um, separator_num;
- u32 *reg = data;
-
- *version = hdev->fw_version;
-
- /* fetching per-VF registers values from VF PCIe register space */
- reg_um = sizeof(cmdq_reg_addr_list) / sizeof(u32);
- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
- for (i = 0; i < reg_um; i++)
- *reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
-
- reg_um = sizeof(common_reg_addr_list) / sizeof(u32);
- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
- for (i = 0; i < reg_um; i++)
- *reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
-
- reg_um = sizeof(ring_reg_addr_list) / sizeof(u32);
- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
- for (j = 0; j < hdev->num_tqps; j++) {
- for (i = 0; i < reg_um; i++)
- *reg++ = hclgevf_read_dev(&hdev->hw,
- ring_reg_addr_list[i] +
- HCLGEVF_TQP_REG_SIZE * j);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- }
-
- reg_um = sizeof(tqp_intr_reg_addr_list) / sizeof(u32);
- separator_num = MAX_SEPARATE_NUM - reg_um % REG_NUM_PER_LINE;
- for (j = 0; j < hdev->num_msi_used - 1; j++) {
- for (i = 0; i < reg_um; i++)
- *reg++ = hclgevf_read_dev(&hdev->hw,
- tqp_intr_reg_addr_list[i] +
- 4 * j);
- for (i = 0; i < separator_num; i++)
- *reg++ = SEPARATOR_VALUE;
- }
-}
-
void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state,
struct hclge_mbx_port_base_vlan *port_base_vlan)
{
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
index 59ca6c794d6d..81c16b8c8da2 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h
@@ -294,4 +294,5 @@ void hclgevf_reset_task_schedule(struct hclgevf_dev *hdev);
void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev);
void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state,
struct hclge_mbx_port_base_vlan *port_base_vlan);
+struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c
new file mode 100644
index 000000000000..65b9dcd38137
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2023 Hisilicon Limited.
+
+#include "hclgevf_main.h"
+#include "hclgevf_regs.h"
+#include "hnae3.h"
+
+static const u32 cmdq_reg_addr_list[] = {HCLGE_COMM_NIC_CSQ_BASEADDR_L_REG,
+ HCLGE_COMM_NIC_CSQ_BASEADDR_H_REG,
+ HCLGE_COMM_NIC_CSQ_DEPTH_REG,
+ HCLGE_COMM_NIC_CSQ_TAIL_REG,
+ HCLGE_COMM_NIC_CSQ_HEAD_REG,
+ HCLGE_COMM_NIC_CRQ_BASEADDR_L_REG,
+ HCLGE_COMM_NIC_CRQ_BASEADDR_H_REG,
+ HCLGE_COMM_NIC_CRQ_DEPTH_REG,
+ HCLGE_COMM_NIC_CRQ_TAIL_REG,
+ HCLGE_COMM_NIC_CRQ_HEAD_REG,
+ HCLGE_COMM_VECTOR0_CMDQ_SRC_REG,
+ HCLGE_COMM_VECTOR0_CMDQ_STATE_REG,
+ HCLGE_COMM_CMDQ_INTR_EN_REG,
+ HCLGE_COMM_CMDQ_INTR_GEN_REG};
+
+static const u32 common_reg_addr_list[] = {HCLGEVF_MISC_VECTOR_REG_BASE,
+ HCLGEVF_RST_ING,
+ HCLGEVF_GRO_EN_REG};
+
+static const u32 ring_reg_addr_list[] = {HCLGEVF_RING_RX_ADDR_L_REG,
+ HCLGEVF_RING_RX_ADDR_H_REG,
+ HCLGEVF_RING_RX_BD_NUM_REG,
+ HCLGEVF_RING_RX_BD_LENGTH_REG,
+ HCLGEVF_RING_RX_MERGE_EN_REG,
+ HCLGEVF_RING_RX_TAIL_REG,
+ HCLGEVF_RING_RX_HEAD_REG,
+ HCLGEVF_RING_RX_FBD_NUM_REG,
+ HCLGEVF_RING_RX_OFFSET_REG,
+ HCLGEVF_RING_RX_FBD_OFFSET_REG,
+ HCLGEVF_RING_RX_STASH_REG,
+ HCLGEVF_RING_RX_BD_ERR_REG,
+ HCLGEVF_RING_TX_ADDR_L_REG,
+ HCLGEVF_RING_TX_ADDR_H_REG,
+ HCLGEVF_RING_TX_BD_NUM_REG,
+ HCLGEVF_RING_TX_PRIORITY_REG,
+ HCLGEVF_RING_TX_TC_REG,
+ HCLGEVF_RING_TX_MERGE_EN_REG,
+ HCLGEVF_RING_TX_TAIL_REG,
+ HCLGEVF_RING_TX_HEAD_REG,
+ HCLGEVF_RING_TX_FBD_NUM_REG,
+ HCLGEVF_RING_TX_OFFSET_REG,
+ HCLGEVF_RING_TX_EBD_NUM_REG,
+ HCLGEVF_RING_TX_EBD_OFFSET_REG,
+ HCLGEVF_RING_TX_BD_ERR_REG,
+ HCLGEVF_RING_EN_REG};
+
+static const u32 tqp_intr_reg_addr_list[] = {HCLGEVF_TQP_INTR_CTRL_REG,
+ HCLGEVF_TQP_INTR_GL0_REG,
+ HCLGEVF_TQP_INTR_GL1_REG,
+ HCLGEVF_TQP_INTR_GL2_REG,
+ HCLGEVF_TQP_INTR_RL_REG};
+
+enum hclgevf_reg_tag {
+ HCLGEVF_REG_TAG_CMDQ = 0,
+ HCLGEVF_REG_TAG_COMMON,
+ HCLGEVF_REG_TAG_RING,
+ HCLGEVF_REG_TAG_TQP_INTR,
+};
+
+#pragma pack(4)
+struct hclgevf_reg_tlv {
+ u16 tag;
+ u16 len;
+};
+
+struct hclgevf_reg_header {
+ u64 magic_number;
+ u8 is_vf;
+ u8 rsv[7];
+};
+
+#pragma pack()
+
+#define HCLGEVF_REG_TLV_SIZE sizeof(struct hclgevf_reg_tlv)
+#define HCLGEVF_REG_HEADER_SIZE sizeof(struct hclgevf_reg_header)
+#define HCLGEVF_REG_TLV_SPACE (sizeof(struct hclgevf_reg_tlv) / sizeof(u32))
+#define HCLGEVF_REG_HEADER_SPACE (sizeof(struct hclgevf_reg_header) / sizeof(u32))
+#define HCLGEVF_REG_MAGIC_NUMBER 0x686e733372656773 /* meaning is hns3regs */
+
+static u32 hclgevf_reg_get_header(void *data)
+{
+ struct hclgevf_reg_header *header = data;
+
+ header->magic_number = HCLGEVF_REG_MAGIC_NUMBER;
+ header->is_vf = 0x1;
+
+ return HCLGEVF_REG_HEADER_SPACE;
+}
+
+static u32 hclgevf_reg_get_tlv(u32 tag, u32 regs_num, void *data)
+{
+ struct hclgevf_reg_tlv *tlv = data;
+
+ tlv->tag = tag;
+ tlv->len = regs_num * sizeof(u32) + HCLGEVF_REG_TLV_SIZE;
+
+ return HCLGEVF_REG_TLV_SPACE;
+}
+
+int hclgevf_get_regs_len(struct hnae3_handle *handle)
+{
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ int cmdq_len, common_len, ring_len, tqp_intr_len;
+
+ cmdq_len = HCLGEVF_REG_TLV_SIZE + sizeof(cmdq_reg_addr_list);
+ common_len = HCLGEVF_REG_TLV_SIZE + sizeof(common_reg_addr_list);
+ ring_len = HCLGEVF_REG_TLV_SIZE + sizeof(ring_reg_addr_list);
+ tqp_intr_len = HCLGEVF_REG_TLV_SIZE + sizeof(tqp_intr_reg_addr_list);
+
+ /* return the total length of all register values */
+ return HCLGEVF_REG_HEADER_SIZE + cmdq_len + common_len +
+ tqp_intr_len * (hdev->num_msi_used - 1) +
+ ring_len * hdev->num_tqps;
+}
+
+void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
+ void *data)
+{
+#define HCLGEVF_RING_REG_OFFSET 0x200
+#define HCLGEVF_RING_INT_REG_OFFSET 0x4
+
+ struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+ int i, j, reg_um;
+ u32 *reg = data;
+
+ *version = hdev->fw_version;
+ reg += hclgevf_reg_get_header(reg);
+
+ /* fetching per-VF registers values from VF PCIe register space */
+ reg_um = sizeof(cmdq_reg_addr_list) / sizeof(u32);
+ reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_CMDQ, reg_um, reg);
+ for (i = 0; i < reg_um; i++)
+ *reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]);
+
+ reg_um = sizeof(common_reg_addr_list) / sizeof(u32);
+ reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_COMMON, reg_um, reg);
+ for (i = 0; i < reg_um; i++)
+ *reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]);
+
+ reg_um = sizeof(ring_reg_addr_list) / sizeof(u32);
+ for (j = 0; j < hdev->num_tqps; j++) {
+ reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_RING, reg_um, reg);
+ for (i = 0; i < reg_um; i++)
+ *reg++ = hclgevf_read_dev(&hdev->hw,
+ ring_reg_addr_list[i] +
+ HCLGEVF_RING_REG_OFFSET * j);
+ }
+
+ reg_um = sizeof(tqp_intr_reg_addr_list) / sizeof(u32);
+ for (j = 0; j < hdev->num_msi_used - 1; j++) {
+ reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_TQP_INTR, reg_um, reg);
+ for (i = 0; i < reg_um; i++)
+ *reg++ = hclgevf_read_dev(&hdev->hw,
+ tqp_intr_reg_addr_list[i] +
+ HCLGEVF_RING_INT_REG_OFFSET * j);
+ }
+}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h
new file mode 100644
index 000000000000..77bdcf60a1af
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2023 Hisilicon Limited. */
+
+#ifndef __HCLGEVF_REGS_H
+#define __HCLGEVF_REGS_H
+#include <linux/types.h>
+
+struct hnae3_handle;
+
+int hclgevf_get_regs_len(struct hnae3_handle *handle);
+void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version,
+ void *data);
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
index 9232caaf0bdc..409a89d80220 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -217,7 +217,7 @@ static void hns_mdio_cmd_write(struct hns_mdio_device *mdio_dev,
static int hns_mdio_write_c22(struct mii_bus *bus,
int phy_id, int regnum, u16 data)
{
- struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
+ struct hns_mdio_device *mdio_dev = bus->priv;
u16 reg = (u16)(regnum & 0xffff);
u16 cmd_reg_cfg;
int ret;
@@ -259,7 +259,7 @@ static int hns_mdio_write_c22(struct mii_bus *bus,
static int hns_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad,
int regnum, u16 data)
{
- struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
+ struct hns_mdio_device *mdio_dev = bus->priv;
u16 reg = (u16)(regnum & 0xffff);
u16 cmd_reg_cfg;
int ret;
@@ -312,7 +312,7 @@ static int hns_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad,
*/
static int hns_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
{
- struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
+ struct hns_mdio_device *mdio_dev = bus->priv;
u16 reg = (u16)(regnum & 0xffff);
u16 reg_val;
int ret;
@@ -363,7 +363,7 @@ static int hns_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
static int hns_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad,
int regnum)
{
- struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
+ struct hns_mdio_device *mdio_dev = bus->priv;
u16 reg = (u16)(regnum & 0xffff);
u16 reg_val;
int ret;
@@ -424,7 +424,7 @@ static int hns_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad,
*/
static int hns_mdio_reset(struct mii_bus *bus)
{
- struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
+ struct hns_mdio_device *mdio_dev = bus->priv;
const struct hns_mdio_sc_reg *sc_reg;
int ret;
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index b4aff59b3eb4..0a56e9752464 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -31,6 +31,7 @@
#include <linux/prefetch.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <net/ip.h>
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index c97095abd26a..0c314bf97480 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -38,6 +38,7 @@
#include <linux/of_irq.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 89a1b0fea158..295516b07662 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -27,7 +27,6 @@
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
-#include <linux/of_platform.h>
#include <linux/slab.h>
#include <asm/io.h>
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index ff5487bbebe3..c3236b59e7e9 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -22,7 +22,9 @@
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include "core.h"
#include <asm/dcr-regs.h>
diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c
index 50358cf00130..fd437f986edf 100644
--- a/drivers/net/ethernet/ibm/emac/rgmii.c
+++ b/drivers/net/ethernet/ibm/emac/rgmii.c
@@ -19,7 +19,9 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
+#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include "emac.h"
diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index 008bbdaf1204..aae9a88d95d7 100644
--- a/drivers/net/ethernet/ibm/emac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
@@ -14,7 +14,9 @@
*
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
*/
+#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include "emac.h"
diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c
index 57a25c7a9e70..6337388ee5f4 100644
--- a/drivers/net/ethernet/ibm/emac/zmii.c
+++ b/drivers/net/ethernet/ibm/emac/zmii.c
@@ -19,7 +19,9 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
+#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include "emac.h"
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 113fcb3e353e..832a2ae01950 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -203,7 +203,7 @@ static inline void ibmveth_flush_buffer(void *addr, unsigned long length)
unsigned long offset;
for (offset = 0; offset < length; offset += SMP_CACHE_BYTES)
- asm("dcbfl %0,%1" :: "b" (addr), "r" (offset));
+ asm("dcbf %0,%1,1" :: "b" (addr), "r" (offset));
}
/* replenish the buffers for a pool. note that we don't need to
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index df76cdaddcfb..cdf5251e5679 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -194,9 +194,8 @@ static void ibmvnic_clean_affinity(struct ibmvnic_adapter *adapter)
struct ibmvnic_sub_crq_queue **rxqs;
struct ibmvnic_sub_crq_queue **txqs;
int num_rxqs, num_txqs;
- int rc, i;
+ int i;
- rc = 0;
rxqs = adapter->rx_scrq;
txqs = adapter->tx_scrq;
num_txqs = adapter->num_active_tx_scrqs;
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 4817eb13ca6f..75f3fd1d8d6e 100644
--- a/drivers/net/ethernet/intel/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -347,6 +347,5 @@ bool e1000_has_link(struct e1000_adapter *adapter);
void e1000_power_up_phy(struct e1000_adapter *);
void e1000_set_ethtool_ops(struct net_device *netdev);
void e1000_check_options(struct e1000_adapter *adapter);
-char *e1000_get_hw_dev_name(struct e1000_hw *hw);
#endif /* _E1000_H_ */
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.h b/drivers/net/ethernet/intel/e1000/e1000_hw.h
index b57a04954ccf..95cdd17134e5 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.h
@@ -343,7 +343,6 @@ struct e1000_host_mng_dhcp_cookie {
};
#endif
-bool e1000_check_mng_mode(struct e1000_hw *hw);
s32 e1000_read_eeprom(struct e1000_hw *hw, u16 reg, u16 words, u16 * data);
s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw);
s32 e1000_update_eeprom_checksum(struct e1000_hw *hw);
@@ -352,7 +351,6 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw);
/* Filters (multicast, vlan, receive) */
u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 * mc_addr);
-void e1000_mta_set(struct e1000_hw *hw, u32 hash_value);
void e1000_rar_set(struct e1000_hw *hw, u8 * mc_addr, u32 rar_index);
void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
@@ -361,7 +359,6 @@ s32 e1000_setup_led(struct e1000_hw *hw);
s32 e1000_cleanup_led(struct e1000_hw *hw);
s32 e1000_led_on(struct e1000_hw *hw);
s32 e1000_led_off(struct e1000_hw *hw);
-s32 e1000_blink_led_start(struct e1000_hw *hw);
/* Adaptive IFS Functions */
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 721f86fd5802..9835e6a90d56 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -917,6 +917,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
mask |= BIT(18);
break;
default:
@@ -1585,6 +1586,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
fext_nvm11 = er32(FEXTNVM11);
fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX;
ew32(FEXTNVM11, fext_nvm11);
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 29f9fae35f42..1fef6bb5a5fb 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -122,6 +122,8 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_PTP_I219_V26 0x57B6
#define E1000_DEV_ID_PCH_PTP_I219_LM27 0x57B7
#define E1000_DEV_ID_PCH_PTP_I219_V27 0x57B8
+#define E1000_DEV_ID_PCH_NVL_I219_LM29 0x57B9
+#define E1000_DEV_ID_PCH_NVL_I219_V29 0x57BA
#define E1000_REVISION_4 4
@@ -150,6 +152,7 @@ enum e1000_mac_type {
e1000_pch_mtp,
e1000_pch_lnp,
e1000_pch_ptp,
+ e1000_pch_nvp,
};
enum e1000_media_type {
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 0c7fd10312c8..39e9fc601bf5 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -323,6 +323,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
if (e1000_phy_is_accessible_pchlan(hw))
break;
@@ -470,6 +471,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
/* In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
@@ -717,6 +719,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
case e1000_pchlan:
/* check management mode */
mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
@@ -1685,6 +1688,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
rc = e1000_init_phy_params_pchlan(hw);
break;
default:
@@ -2142,6 +2146,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
break;
default:
@@ -3188,6 +3193,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
bank1_offset = nvm->flash_bank_size;
act_offset = E1000_ICH_NVM_SIG_WORD;
@@ -4129,6 +4135,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
word = NVM_COMPAT;
valid_csum_mask = NVM_COMPAT_VALID_CSUM;
break;
diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h
index 6ab261119801..563176fd436e 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.h
+++ b/drivers/net/ethernet/intel/e1000e/mac.h
@@ -29,8 +29,6 @@ s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
s32 e1000e_setup_led_generic(struct e1000_hw *hw);
s32 e1000e_setup_link_generic(struct e1000_hw *hw);
-s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw);
-s32 e1000e_validate_mdi_setting_crossover_generic(struct e1000_hw *hw);
void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
void e1000_clear_vfta_generic(struct e1000_hw *hw);
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 771a3c909c45..f536c856727c 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -3545,6 +3545,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
/* Stable 24MHz frequency */
incperiod = INCPERIOD_24MHZ;
@@ -4061,6 +4062,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
fc->refresh_time = 0xFFFF;
fc->pause_time = 0xFFFF;
@@ -7021,6 +7023,8 @@ static __maybe_unused int e1000e_pm_runtime_resume(struct device *dev)
struct e1000_adapter *adapter = netdev_priv(netdev);
int rc;
+ pdev->pme_poll = true;
+
rc = __e1000_resume(pdev);
if (rc)
return rc;
@@ -7682,7 +7686,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
- if (pci_dev_run_wake(pdev) && hw->mac.type != e1000_pch_cnp)
+ if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
return 0;
@@ -7911,6 +7915,8 @@ static const struct pci_device_id e1000_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V26), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_mtp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_mtp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_mtp },
{ 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
};
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index def4566a916f..02d871bc112a 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -288,6 +288,7 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
case e1000_pch_mtp:
case e1000_pch_lnp:
case e1000_pch_ptp:
+ case e1000_pch_nvp:
if ((hw->mac.type < e1000_pch_lpt) ||
(er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
adapter->ptp_clock_info.max_adj = 24000000 - 1;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index 86fac8f959bb..100eb77b8dfe 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
-#include "i40e_status.h"
#include "i40e_type.h"
#include "i40e_register.h"
#include "i40e_adminq.h"
@@ -284,7 +283,7 @@ static int i40e_config_asq_regs(struct i40e_hw *hw)
/* Check one register to verify that config was applied */
reg = rd32(hw, hw->aq.asq.bal);
if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa))
- ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
+ ret_code = -EIO;
return ret_code;
}
@@ -316,7 +315,7 @@ static int i40e_config_arq_regs(struct i40e_hw *hw)
/* Check one register to verify that config was applied */
reg = rd32(hw, hw->aq.arq.bal);
if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa))
- ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
+ ret_code = -EIO;
return ret_code;
}
@@ -340,14 +339,14 @@ static int i40e_init_asq(struct i40e_hw *hw)
if (hw->aq.asq.count > 0) {
/* queue already initialized */
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto init_adminq_exit;
}
/* verify input for valid configuration */
if ((hw->aq.num_asq_entries == 0) ||
(hw->aq.asq_buf_size == 0)) {
- ret_code = I40E_ERR_CONFIG;
+ ret_code = -EIO;
goto init_adminq_exit;
}
@@ -399,14 +398,14 @@ static int i40e_init_arq(struct i40e_hw *hw)
if (hw->aq.arq.count > 0) {
/* queue already initialized */
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto init_adminq_exit;
}
/* verify input for valid configuration */
if ((hw->aq.num_arq_entries == 0) ||
(hw->aq.arq_buf_size == 0)) {
- ret_code = I40E_ERR_CONFIG;
+ ret_code = -EIO;
goto init_adminq_exit;
}
@@ -452,7 +451,7 @@ static int i40e_shutdown_asq(struct i40e_hw *hw)
mutex_lock(&hw->aq.asq_mutex);
if (hw->aq.asq.count == 0) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto shutdown_asq_out;
}
@@ -486,7 +485,7 @@ static int i40e_shutdown_arq(struct i40e_hw *hw)
mutex_lock(&hw->aq.arq_mutex);
if (hw->aq.arq.count == 0) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto shutdown_arq_out;
}
@@ -594,7 +593,7 @@ int i40e_init_adminq(struct i40e_hw *hw)
(hw->aq.num_asq_entries == 0) ||
(hw->aq.arq_buf_size == 0) ||
(hw->aq.asq_buf_size == 0)) {
- ret_code = I40E_ERR_CONFIG;
+ ret_code = -EIO;
goto init_adminq_exit;
}
@@ -626,13 +625,13 @@ int i40e_init_adminq(struct i40e_hw *hw)
&hw->aq.api_maj_ver,
&hw->aq.api_min_ver,
NULL);
- if (ret_code != I40E_ERR_ADMIN_QUEUE_TIMEOUT)
+ if (ret_code != -EIO)
break;
retry++;
msleep(100);
i40e_resume_aq(hw);
} while (retry < 10);
- if (ret_code != I40E_SUCCESS)
+ if (ret_code != 0)
goto init_adminq_free_arq;
/* Some features were introduced in different FW API version
@@ -672,7 +671,7 @@ int i40e_init_adminq(struct i40e_hw *hw)
hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE;
if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
- ret_code = I40E_ERR_FIRMWARE_API_VERSION;
+ ret_code = -EIO;
goto init_adminq_free_arq;
}
@@ -799,7 +798,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
if (hw->aq.asq.count == 0) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: Admin queue not initialized.\n");
- status = I40E_ERR_QUEUE_EMPTY;
+ status = -EIO;
goto asq_send_command_error;
}
@@ -809,7 +808,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
if (val >= hw->aq.num_asq_entries) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
- status = I40E_ERR_ADMIN_QUEUE_FULL;
+ status = -ENOSPC;
goto asq_send_command_error;
}
@@ -840,7 +839,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
I40E_DEBUG_AQ_MESSAGE,
"AQTX: Invalid buffer size: %d.\n",
buff_size);
- status = I40E_ERR_INVALID_SIZE;
+ status = -EINVAL;
goto asq_send_command_error;
}
@@ -848,7 +847,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
i40e_debug(hw,
I40E_DEBUG_AQ_MESSAGE,
"AQTX: Async flag not set along with postpone flag");
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto asq_send_command_error;
}
@@ -863,7 +862,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
i40e_debug(hw,
I40E_DEBUG_AQ_MESSAGE,
"AQTX: Error queue is full.\n");
- status = I40E_ERR_ADMIN_QUEUE_FULL;
+ status = -ENOSPC;
goto asq_send_command_error;
}
@@ -940,9 +939,9 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK)
status = 0;
else if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_EBUSY)
- status = I40E_ERR_NOT_READY;
+ status = -EBUSY;
else
- status = I40E_ERR_ADMIN_QUEUE_ERROR;
+ status = -EIO;
hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
}
@@ -960,11 +959,11 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
if (rd32(hw, hw->aq.asq.len) & I40E_GL_ATQLEN_ATQCRIT_MASK) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
- status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
+ status = -EIO;
} else {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: Writeback timeout.\n");
- status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
+ status = -EIO;
}
}
@@ -1106,7 +1105,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw,
if (hw->aq.arq.count == 0) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQRX: Admin queue not initialized.\n");
- ret_code = I40E_ERR_QUEUE_EMPTY;
+ ret_code = -EIO;
goto clean_arq_element_err;
}
@@ -1114,7 +1113,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw,
ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK;
if (ntu == ntc) {
/* nothing to do - shouldn't need to update ring's values */
- ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK;
+ ret_code = -EALREADY;
goto clean_arq_element_out;
}
@@ -1126,7 +1125,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw,
(enum i40e_admin_queue_err)le16_to_cpu(desc->retval);
flags = le16_to_cpu(desc->flags);
if (flags & I40E_AQ_FLAG_ERR) {
- ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
+ ret_code = -EIO;
i40e_debug(hw,
I40E_DEBUG_AQ_MESSAGE,
"AQRX: Event received with error 0x%X.\n",
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
index ee394aacef4d..267f2e0a21ce 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
@@ -5,7 +5,6 @@
#define _I40E_ADMINQ_H_
#include "i40e_osdep.h"
-#include "i40e_status.h"
#include "i40e_adminq_cmd.h"
#define I40E_ADMINQ_DESC(R, i) \
@@ -117,7 +116,7 @@ static inline int i40e_aq_rc_to_posix(int aq_ret, int aq_rc)
};
/* aq_rc is invalid if AQ timed out */
- if (aq_ret == I40E_ERR_ADMIN_QUEUE_TIMEOUT)
+ if (aq_ret == -EIO)
return -EAGAIN;
if (!((u32)aq_rc < (sizeof(aq_to_posix) / sizeof((aq_to_posix)[0]))))
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index ed88e38d488b..eeef20f77106 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -56,7 +56,7 @@ int i40e_set_mac_type(struct i40e_hw *hw)
break;
}
} else {
- status = I40E_ERR_DEVICE_NOT_SUPPORTED;
+ status = -ENODEV;
}
hw_dbg(hw, "i40e_set_mac_type found mac: %d, returns: %d\n",
@@ -660,7 +660,7 @@ int i40e_init_shared_code(struct i40e_hw *hw)
case I40E_MAC_X722:
break;
default:
- return I40E_ERR_DEVICE_NOT_SUPPORTED;
+ return -ENODEV;
}
hw->phy.get_link_info = true;
@@ -780,7 +780,7 @@ int i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr)
if (flags & I40E_AQC_PORT_ADDR_VALID)
ether_addr_copy(mac_addr, addrs.port_mac);
else
- status = I40E_ERR_INVALID_MAC_ADDR;
+ status = -EINVAL;
return status;
}
@@ -858,7 +858,7 @@ int i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num,
pba_size--;
if (pba_num_size < (((u32)pba_size * 2) + 1)) {
hw_dbg(hw, "Buffer too small for PBA data.\n");
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
for (i = 0; i < pba_size; i++) {
@@ -955,7 +955,7 @@ static int i40e_poll_globr(struct i40e_hw *hw,
hw_dbg(hw, "Global reset failed.\n");
hw_dbg(hw, "I40E_GLGEN_RSTAT = 0x%x\n", reg);
- return I40E_ERR_RESET_FAILED;
+ return -EIO;
}
#define I40E_PF_RESET_WAIT_COUNT_A0 200
@@ -995,7 +995,7 @@ int i40e_pf_reset(struct i40e_hw *hw)
}
if (reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
hw_dbg(hw, "Global reset polling failed to complete.\n");
- return I40E_ERR_RESET_FAILED;
+ return -EIO;
}
/* Now Wait for the FW to be ready */
@@ -1014,7 +1014,7 @@ int i40e_pf_reset(struct i40e_hw *hw)
I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK))) {
hw_dbg(hw, "wait for FW Reset complete timedout\n");
hw_dbg(hw, "I40E_GLNVM_ULD = 0x%x\n", reg);
- return I40E_ERR_RESET_FAILED;
+ return -EIO;
}
/* If there was a Global Reset in progress when we got here,
@@ -1040,10 +1040,10 @@ int i40e_pf_reset(struct i40e_hw *hw)
}
if (reg2 & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
if (i40e_poll_globr(hw, grst_del))
- return I40E_ERR_RESET_FAILED;
+ return -EIO;
} else if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
hw_dbg(hw, "PF reset polling failed to complete.\n");
- return I40E_ERR_RESET_FAILED;
+ return -EIO;
}
}
@@ -1318,7 +1318,7 @@ i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
int status;
if (!abilities)
- return I40E_ERR_PARAM;
+ return -EINVAL;
do {
i40e_fill_default_direct_cmd_desc(&desc,
@@ -1341,12 +1341,12 @@ i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
switch (hw->aq.asq_last_status) {
case I40E_AQ_RC_EIO:
- status = I40E_ERR_UNKNOWN_PHY;
+ status = -EIO;
break;
case I40E_AQ_RC_EAGAIN:
usleep_range(1000, 2000);
total_delay++;
- status = I40E_ERR_TIMEOUT;
+ status = -EIO;
break;
/* also covers I40E_AQ_RC_OK */
default:
@@ -1396,7 +1396,7 @@ int i40e_aq_set_phy_config(struct i40e_hw *hw,
int status;
if (!config)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc,
i40e_aqc_opc_set_phy_config);
@@ -2312,7 +2312,7 @@ int i40e_aq_send_driver_version(struct i40e_hw *hw,
u16 len;
if (dv == NULL)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_driver_version);
@@ -2430,7 +2430,7 @@ int i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
/* SEIDs need to either both be set or both be 0 for floating VEB */
if (!!uplink_seid != !!downlink_seid)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_veb);
@@ -2485,7 +2485,7 @@ int i40e_aq_get_veb_parameters(struct i40e_hw *hw,
int status;
if (veb_seid == 0)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc,
i40e_aqc_opc_get_veb_parameters);
@@ -2575,7 +2575,7 @@ i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
u16 buf_size;
if (count == 0 || !mv_list || !hw)
- return I40E_ERR_PARAM;
+ return -EINVAL;
buf_size = i40e_prepare_add_macvlan(mv_list, &desc, count, seid);
@@ -2608,7 +2608,7 @@ i40e_aq_add_macvlan_v2(struct i40e_hw *hw, u16 seid,
u16 buf_size;
if (count == 0 || !mv_list || !hw)
- return I40E_ERR_PARAM;
+ return -EINVAL;
buf_size = i40e_prepare_add_macvlan(mv_list, &desc, count, seid);
@@ -2638,7 +2638,7 @@ i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
int status;
if (count == 0 || !mv_list || !hw)
- return I40E_ERR_PARAM;
+ return -EINVAL;
buf_size = count * sizeof(*mv_list);
@@ -2685,7 +2685,7 @@ i40e_aq_remove_macvlan_v2(struct i40e_hw *hw, u16 seid,
u16 buf_size;
if (count == 0 || !mv_list || !hw)
- return I40E_ERR_PARAM;
+ return -EINVAL;
buf_size = count * sizeof(*mv_list);
@@ -2791,7 +2791,7 @@ int i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
if (!(rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS ||
rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS)) {
if (count == 0 || !mr_list)
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
return i40e_mirrorrule_op(hw, i40e_aqc_opc_add_mirror_rule, sw_seid,
@@ -2827,7 +2827,7 @@ int i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
* not matter.
*/
if (count == 0 || !mr_list)
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
return i40e_mirrorrule_op(hw, i40e_aqc_opc_delete_mirror_rule, sw_seid,
@@ -2892,7 +2892,7 @@ int i40e_aq_debug_read_register(struct i40e_hw *hw,
int status;
if (reg_val == NULL)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_debug_read_reg);
@@ -3031,7 +3031,7 @@ int i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer,
/* In offset the highest byte must be zeroed. */
if (offset & 0xFF000000) {
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto i40e_aq_read_nvm_exit;
}
@@ -3076,7 +3076,7 @@ int i40e_aq_erase_nvm(struct i40e_hw *hw, u8 module_pointer,
/* In offset the highest byte must be zeroed. */
if (offset & 0xFF000000) {
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto i40e_aq_erase_nvm_exit;
}
@@ -3368,7 +3368,7 @@ int i40e_aq_discover_capabilities(struct i40e_hw *hw,
if (list_type_opc != i40e_aqc_opc_list_func_capabilities &&
list_type_opc != i40e_aqc_opc_list_dev_capabilities) {
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto exit;
}
@@ -3416,7 +3416,7 @@ int i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer,
/* In offset the highest byte must be zeroed. */
if (offset & 0xFF000000) {
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto i40e_aq_update_nvm_exit;
}
@@ -3473,7 +3473,7 @@ int i40e_aq_rearrange_nvm(struct i40e_hw *hw,
I40E_AQ_NVM_REARRANGE_TO_STRUCT);
if (!rearrange_nvm) {
- status = I40E_ERR_PARAM;
+ status = -EINVAL;
goto i40e_aq_rearrange_nvm_exit;
}
@@ -3510,7 +3510,7 @@ int i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
int status;
if (buff_size == 0 || !buff)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_get_mib);
/* Indirect Command */
@@ -3558,7 +3558,7 @@ i40e_aq_set_lldp_mib(struct i40e_hw *hw,
cmd = (struct i40e_aqc_lldp_set_local_mib *)&desc.params.raw;
if (buff_size == 0 || !buff)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc,
i40e_aqc_opc_lldp_set_local_mib);
@@ -3627,7 +3627,7 @@ i40e_aq_restore_lldp(struct i40e_hw *hw, u8 *setting, bool restore,
if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)) {
i40e_debug(hw, I40E_DEBUG_ALL,
"Restore LLDP not supported by current FW version.\n");
- return I40E_ERR_DEVICE_NOT_SUPPORTED;
+ return -ENODEV;
}
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_restore);
@@ -3729,7 +3729,7 @@ i40e_aq_set_dcb_parameters(struct i40e_hw *hw, bool dcb_enable,
int status;
if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))
- return I40E_ERR_DEVICE_NOT_SUPPORTED;
+ return -ENODEV;
i40e_fill_default_direct_cmd_desc(&desc,
i40e_aqc_opc_set_dcb_parameters);
@@ -3760,7 +3760,7 @@ int i40e_aq_get_cee_dcb_config(struct i40e_hw *hw,
int status;
if (buff_size == 0 || !buff)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_cee_dcb_cfg);
@@ -3848,7 +3848,7 @@ int i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
int status;
if (seid == 0)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_delete_element);
@@ -3922,7 +3922,7 @@ static int i40e_aq_tx_sched_cmd(struct i40e_hw *hw, u16 seid,
cmd_param_flag = false;
break;
default:
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
i40e_fill_default_direct_cmd_desc(&desc, opcode);
@@ -4148,7 +4148,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
fcoe_filt_size <<= (u32)settings->fcoe_filt_num;
break;
default:
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
switch (settings->fcoe_cntx_num) {
@@ -4160,7 +4160,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
fcoe_cntx_size <<= (u32)settings->fcoe_cntx_num;
break;
default:
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
/* Validate PE settings passed */
@@ -4178,7 +4178,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
case I40E_HASH_FILTER_SIZE_1M:
break;
default:
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
switch (settings->pe_cntx_num) {
@@ -4194,7 +4194,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
case I40E_DMA_CNTX_SIZE_256K:
break;
default:
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
/* FCHSIZE + FCDSIZE should not be greater than PMFCOEFMAX */
@@ -4202,7 +4202,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
fcoe_fmax = (val & I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK)
>> I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT;
if (fcoe_filt_size + fcoe_cntx_size > fcoe_fmax)
- return I40E_ERR_INVALID_SIZE;
+ return -EINVAL;
return 0;
}
@@ -4224,7 +4224,7 @@ int i40e_set_filter_control(struct i40e_hw *hw,
u32 val;
if (!settings)
- return I40E_ERR_PARAM;
+ return -EINVAL;
/* Validate the input settings */
ret = i40e_validate_filter_settings(hw, settings);
@@ -4306,7 +4306,7 @@ int i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
int status;
if (vsi_seid == 0)
- return I40E_ERR_PARAM;
+ return -EINVAL;
if (is_add) {
i40e_fill_default_direct_cmd_desc(&desc,
@@ -4381,7 +4381,7 @@ static int i40e_aq_alternate_read(struct i40e_hw *hw,
int status;
if (!reg_val0)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_alternate_read);
cmd_resp->address0 = cpu_to_le32(reg_addr0);
@@ -4517,7 +4517,7 @@ int i40e_aq_debug_dump(struct i40e_hw *hw, u8 cluster_id,
int status;
if (buff_size == 0 || !buff)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc,
i40e_aqc_opc_debug_dump_internals);
@@ -4635,7 +4635,7 @@ int i40e_read_phy_register_clause22(struct i40e_hw *hw,
u16 reg, u8 phy_addr, u16 *value)
{
u8 port_num = (u8)hw->func_caps.mdio_port_num;
- int status = I40E_ERR_TIMEOUT;
+ int status = -EIO;
u32 command = 0;
u16 retry = 1000;
@@ -4680,7 +4680,7 @@ int i40e_write_phy_register_clause22(struct i40e_hw *hw,
u16 reg, u8 phy_addr, u16 value)
{
u8 port_num = (u8)hw->func_caps.mdio_port_num;
- int status = I40E_ERR_TIMEOUT;
+ int status = -EIO;
u32 command = 0;
u16 retry = 1000;
@@ -4721,7 +4721,7 @@ int i40e_read_phy_register_clause45(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 *value)
{
u8 port_num = hw->func_caps.mdio_port_num;
- int status = I40E_ERR_TIMEOUT;
+ int status = -EIO;
u32 command = 0;
u16 retry = 1000;
@@ -4755,7 +4755,7 @@ int i40e_read_phy_register_clause45(struct i40e_hw *hw,
(I40E_MDIO_CLAUSE45_STCODE_MASK) |
(I40E_GLGEN_MSCA_MDICMD_MASK) |
(I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
- status = I40E_ERR_TIMEOUT;
+ status = -EIO;
retry = 1000;
wr32(hw, I40E_GLGEN_MSCA(port_num), command);
do {
@@ -4795,7 +4795,7 @@ int i40e_write_phy_register_clause45(struct i40e_hw *hw,
u8 page, u16 reg, u8 phy_addr, u16 value)
{
u8 port_num = hw->func_caps.mdio_port_num;
- int status = I40E_ERR_TIMEOUT;
+ int status = -EIO;
u16 retry = 1000;
u32 command = 0;
@@ -4831,7 +4831,7 @@ int i40e_write_phy_register_clause45(struct i40e_hw *hw,
(I40E_MDIO_CLAUSE45_STCODE_MASK) |
(I40E_GLGEN_MSCA_MDICMD_MASK) |
(I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
- status = I40E_ERR_TIMEOUT;
+ status = -EIO;
retry = 1000;
wr32(hw, I40E_GLGEN_MSCA(port_num), command);
do {
@@ -4880,7 +4880,7 @@ int i40e_write_phy_register(struct i40e_hw *hw,
phy_addr, value);
break;
default:
- status = I40E_ERR_UNKNOWN_PHY;
+ status = -EIO;
break;
}
@@ -4919,7 +4919,7 @@ int i40e_read_phy_register(struct i40e_hw *hw,
phy_addr, value);
break;
default:
- status = I40E_ERR_UNKNOWN_PHY;
+ status = -EIO;
break;
}
@@ -5109,7 +5109,7 @@ int i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
I40E_PHY_COM_REG_PAGE, true,
I40E_PHY_LED_PROV_REG_1,
&reg_val_aq, NULL);
- if (status == I40E_SUCCESS)
+ if (status == 0)
*val = (u16)reg_val_aq;
return status;
}
@@ -5204,7 +5204,7 @@ int i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
int status;
if (!reg_val)
- return I40E_ERR_PARAM;
+ return -EINVAL;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_rx_ctl_reg_read);
@@ -5644,7 +5644,7 @@ i40e_validate_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
if (track_id == I40E_DDP_TRACKID_INVALID) {
i40e_debug(hw, I40E_DEBUG_PACKAGE, "Invalid track_id\n");
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
dev_cnt = profile->device_table_count;
@@ -5657,7 +5657,7 @@ i40e_validate_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
if (dev_cnt && i == dev_cnt) {
i40e_debug(hw, I40E_DEBUG_PACKAGE,
"Device doesn't support DDP\n");
- return I40E_ERR_DEVICE_NOT_SUPPORTED;
+ return -ENODEV;
}
I40E_SECTION_TABLE(profile, sec_tbl);
@@ -5672,14 +5672,14 @@ i40e_validate_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
sec->section.type == SECTION_TYPE_RB_AQ) {
i40e_debug(hw, I40E_DEBUG_PACKAGE,
"Not a roll-back package\n");
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
} else {
if (sec->section.type == SECTION_TYPE_RB_AQ ||
sec->section.type == SECTION_TYPE_RB_MMIO) {
i40e_debug(hw, I40E_DEBUG_PACKAGE,
"Not an original package\n");
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
}
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
index 90638b67f8dc..f81e744c0fb3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
@@ -17,7 +17,7 @@ int i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
u32 reg;
if (!status)
- return I40E_ERR_PARAM;
+ return -EINVAL;
reg = rd32(hw, I40E_PRTDCB_GENS);
*status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
@@ -508,7 +508,7 @@ int i40e_lldp_to_dcb_config(u8 *lldpmib,
u16 type;
if (!lldpmib || !dcbcfg)
- return I40E_ERR_PARAM;
+ return -EINVAL;
/* set to the start of LLDPDU */
lldpmib += ETH_HLEN;
@@ -874,7 +874,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
int ret = 0;
if (!hw->func_caps.dcb)
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
/* Read LLDP NVM area */
if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) {
@@ -885,7 +885,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
else if (hw->mac.type == I40E_MAC_X722)
offset = I40E_LLDP_CURRENT_STATUS_X722_OFFSET;
else
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
ret = i40e_read_nvm_module_data(hw,
I40E_SR_EMP_SR_SETTINGS_PTR,
@@ -897,7 +897,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
}
if (ret)
- return I40E_ERR_NOT_READY;
+ return -EBUSY;
/* Get the LLDP AdminStatus for the current port */
adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
@@ -906,7 +906,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
/* LLDP agent disabled */
if (!adminstatus) {
hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
- return I40E_ERR_NOT_READY;
+ return -EBUSY;
}
/* Get DCBX status */
@@ -922,7 +922,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
if (ret)
return ret;
} else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
- return I40E_ERR_NOT_READY;
+ return -EBUSY;
}
/* Configure the LLDP MIB change event */
@@ -949,7 +949,7 @@ i40e_get_fw_lldp_status(struct i40e_hw *hw,
int ret;
if (!lldp_status)
- return I40E_ERR_PARAM;
+ return -EINVAL;
/* Allocate buffer for the LLDPDU */
ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
@@ -1299,7 +1299,7 @@ int i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
sizeof(tlv->typelength) + length);
} while (tlvid < I40E_TLV_ID_END_OF_LLDPPDU);
*miblen = offset;
- return I40E_SUCCESS;
+ return 0;
}
/**
@@ -1957,7 +1957,7 @@ int i40e_read_lldp_cfg(struct i40e_hw *hw,
u32 mem;
if (!lldp_cfg)
- return I40E_ERR_PARAM;
+ return -EINVAL;
ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
if (ret)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ddp.c b/drivers/net/ethernet/intel/i40e/i40e_ddp.c
index 7e8183762fd9..0e72abd178ae 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ddp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ddp.c
@@ -220,7 +220,7 @@ static bool i40e_ddp_is_pkg_hdr_valid(struct net_device *netdev,
netdev_err(netdev, "Invalid DDP profile - size is bigger than 4G");
return false;
}
- if (size < (sizeof(struct i40e_package_header) +
+ if (size < (sizeof(struct i40e_package_header) + sizeof(u32) +
sizeof(struct i40e_metadata_segment) + sizeof(u32) * 2)) {
netdev_err(netdev, "Invalid DDP profile - size is too small.");
return false;
@@ -281,7 +281,7 @@ int i40e_ddp_load(struct net_device *netdev, const u8 *data, size_t size,
if (!i40e_ddp_is_pkg_hdr_valid(netdev, pkg_hdr, size))
return -EINVAL;
- if (size < (sizeof(struct i40e_package_header) +
+ if (size < (sizeof(struct i40e_package_header) + sizeof(u32) +
sizeof(struct i40e_metadata_segment) + sizeof(u32) * 2)) {
netdev_err(netdev, "Invalid DDP recipe size.");
return -EINVAL;
@@ -344,7 +344,7 @@ int i40e_ddp_load(struct net_device *netdev, const u8 *data, size_t size,
if (is_add) {
status = i40e_write_profile(&pf->hw, profile_hdr, track_id);
if (status) {
- if (status == I40E_ERR_DEVICE_NOT_SUPPORTED) {
+ if (status == -ENODEV) {
netdev_err(netdev,
"Profile is not supported by the device.");
return -EPERM;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 62497f5565c5..1a497cb07710 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1309,7 +1309,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
ret = i40e_asq_send_command(&pf->hw, desc, NULL, 0, NULL);
if (!ret) {
dev_info(&pf->pdev->dev, "AQ command sent Status : Success\n");
- } else if (ret == I40E_ERR_ADMIN_QUEUE_ERROR) {
+ } else if (ret == -EIO) {
dev_info(&pf->pdev->dev,
"AQ command send failed Opcode %x AQ Error: %d\n",
desc->opcode, pf->hw.aq.asq_last_status);
@@ -1370,7 +1370,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
buffer_len, NULL);
if (!ret) {
dev_info(&pf->pdev->dev, "AQ command sent Status : Success\n");
- } else if (ret == I40E_ERR_ADMIN_QUEUE_ERROR) {
+ } else if (ret == -EIO) {
dev_info(&pf->pdev->dev,
"AQ command send failed Opcode %x AQ Error: %d\n",
desc->opcode, pf->hw.aq.asq_last_status);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c
index 97fe1787a8f4..b1ad7c4259b9 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_diag.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c
@@ -28,7 +28,7 @@ static int i40e_diag_reg_pattern_test(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_DIAG,
"%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n",
__func__, reg, pat, val);
- return I40E_ERR_DIAG_TEST_FAILED;
+ return -EIO;
}
}
@@ -38,7 +38,7 @@ static int i40e_diag_reg_pattern_test(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_DIAG,
"%s: reg restore test failed - reg 0x%08x orig_val 0x%08x val 0x%08x\n",
__func__, reg, orig_val, val);
- return I40E_ERR_DIAG_TEST_FAILED;
+ return -EIO;
}
return 0;
@@ -127,5 +127,5 @@ int i40e_diag_eeprom_test(struct i40e_hw *hw)
BIT(I40E_SR_CONTROL_WORD_1_SHIFT)))
return i40e_validate_nvm_checksum(hw, NULL);
else
- return I40E_ERR_DIAG_TEST_FAILED;
+ return -EIO;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index afc4fa8c66af..bd1321bf7e26 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -5699,8 +5699,8 @@ static int i40e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
struct i40e_hw *hw = &pf->hw;
- int status = I40E_SUCCESS;
__le16 eee_capability;
+ int status = 0;
/* Deny parameters we don't support */
if (i40e_is_eee_param_supported(netdev, edata))
diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c
index 46f7950a0049..96ee63aca7a1 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c
@@ -4,7 +4,6 @@
#include "i40e.h"
#include "i40e_osdep.h"
#include "i40e_register.h"
-#include "i40e_status.h"
#include "i40e_alloc.h"
#include "i40e_hmc.h"
#include "i40e_type.h"
@@ -26,18 +25,18 @@ int i40e_add_sd_table_entry(struct i40e_hw *hw,
enum i40e_memory_type mem_type __attribute__((unused));
struct i40e_hmc_sd_entry *sd_entry;
bool dma_mem_alloc_done = false;
- int ret_code = I40E_SUCCESS;
struct i40e_dma_mem mem;
+ int ret_code = 0;
u64 alloc_len;
if (NULL == hmc_info->sd_table.sd_entry) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n");
goto exit;
}
if (sd_index >= hmc_info->sd_table.sd_cnt) {
- ret_code = I40E_ERR_INVALID_SD_INDEX;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n");
goto exit;
}
@@ -121,7 +120,7 @@ int i40e_add_pd_table_entry(struct i40e_hw *hw,
u64 *pd_addr;
if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
- ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n");
goto exit;
}
@@ -200,13 +199,13 @@ int i40e_remove_pd_bp(struct i40e_hw *hw,
sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
if (sd_idx >= hmc_info->sd_table.sd_cnt) {
- ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n");
goto exit;
}
sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
- ret_code = I40E_ERR_INVALID_SD_TYPE;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n");
goto exit;
}
@@ -251,7 +250,7 @@ int i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
sd_entry = &hmc_info->sd_table.sd_entry[idx];
I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
if (sd_entry->u.bp.ref_cnt) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto exit;
}
I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
@@ -276,7 +275,7 @@ int i40e_remove_sd_bp_new(struct i40e_hw *hw,
struct i40e_hmc_sd_entry *sd_entry;
if (!is_pf)
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
/* get the entry and decrease its ref counter */
sd_entry = &hmc_info->sd_table.sd_entry[idx];
@@ -299,7 +298,7 @@ int i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
sd_entry = &hmc_info->sd_table.sd_entry[idx];
if (sd_entry->u.pd_table.ref_cnt) {
- ret_code = I40E_ERR_NOT_READY;
+ ret_code = -EBUSY;
goto exit;
}
@@ -325,7 +324,7 @@ int i40e_remove_pd_page_new(struct i40e_hw *hw,
struct i40e_hmc_sd_entry *sd_entry;
if (!is_pf)
- return I40E_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
sd_entry = &hmc_info->sd_table.sd_entry[idx];
I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
index 40c101f286d1..474365bf0648 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
@@ -111,7 +111,7 @@ int i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
/* validate values requested by driver don't exceed HMC capacity */
if (txq_num > obj->max_cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_init_lan_hmc: Tx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
txq_num, obj->max_cnt, ret_code);
goto init_lan_hmc_out;
@@ -134,7 +134,7 @@ int i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
/* validate values requested by driver don't exceed HMC capacity */
if (rxq_num > obj->max_cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_init_lan_hmc: Rx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
rxq_num, obj->max_cnt, ret_code);
goto init_lan_hmc_out;
@@ -157,7 +157,7 @@ int i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
/* validate values requested by driver don't exceed HMC capacity */
if (fcoe_cntx_num > obj->max_cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_init_lan_hmc: FCoE context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
fcoe_cntx_num, obj->max_cnt, ret_code);
goto init_lan_hmc_out;
@@ -180,7 +180,7 @@ int i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
/* validate values requested by driver don't exceed HMC capacity */
if (fcoe_filt_num > obj->max_cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_init_lan_hmc: FCoE filter: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
fcoe_filt_num, obj->max_cnt, ret_code);
goto init_lan_hmc_out;
@@ -289,30 +289,30 @@ static int i40e_create_lan_hmc_object(struct i40e_hw *hw,
u32 i, j;
if (NULL == info) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_create_lan_hmc_object: bad info ptr\n");
goto exit;
}
if (NULL == info->hmc_info) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_create_lan_hmc_object: bad hmc_info ptr\n");
goto exit;
}
if (I40E_HMC_INFO_SIGNATURE != info->hmc_info->signature) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_create_lan_hmc_object: bad signature\n");
goto exit;
}
if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_create_lan_hmc_object: returns error %d\n",
ret_code);
goto exit;
}
if ((info->start_idx + info->count) >
info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_create_lan_hmc_object: returns error %d\n",
ret_code);
goto exit;
@@ -324,8 +324,8 @@ static int i40e_create_lan_hmc_object(struct i40e_hw *hw,
&sd_idx, &sd_lmt);
if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
sd_lmt > info->hmc_info->sd_table.sd_cnt) {
- ret_code = I40E_ERR_INVALID_SD_INDEX;
- goto exit;
+ ret_code = -EINVAL;
+ goto exit;
}
/* find pd index */
I40E_FIND_PD_INDEX_LIMIT(info->hmc_info, info->rsrc_type,
@@ -393,7 +393,7 @@ static int i40e_create_lan_hmc_object(struct i40e_hw *hw,
j, sd_entry->entry_type);
break;
default:
- ret_code = I40E_ERR_INVALID_SD_TYPE;
+ ret_code = -EINVAL;
goto exit;
}
}
@@ -417,7 +417,7 @@ exit_sd_error:
i40e_remove_sd_bp(hw, info->hmc_info, (j - 1));
break;
default:
- ret_code = I40E_ERR_INVALID_SD_TYPE;
+ ret_code = -EINVAL;
break;
}
j--;
@@ -474,7 +474,7 @@ try_type_paged:
break;
default:
/* unsupported type */
- ret_code = I40E_ERR_INVALID_SD_TYPE;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_configure_lan_hmc: Unknown SD type: %d\n",
ret_code);
goto configure_lan_hmc_out;
@@ -530,34 +530,34 @@ static int i40e_delete_lan_hmc_object(struct i40e_hw *hw,
u32 i, j;
if (NULL == info) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: bad info ptr\n");
goto exit;
}
if (NULL == info->hmc_info) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: bad info->hmc_info ptr\n");
goto exit;
}
if (I40E_HMC_INFO_SIGNATURE != info->hmc_info->signature) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: bad hmc_info->signature\n");
goto exit;
}
if (NULL == info->hmc_info->sd_table.sd_entry) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: bad sd_entry\n");
goto exit;
}
if (NULL == info->hmc_info->hmc_obj) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: bad hmc_info->hmc_obj\n");
goto exit;
}
if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: returns error %d\n",
ret_code);
goto exit;
@@ -565,7 +565,7 @@ static int i40e_delete_lan_hmc_object(struct i40e_hw *hw,
if ((info->start_idx + info->count) >
info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
- ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_delete_hmc_object: returns error %d\n",
ret_code);
goto exit;
@@ -599,7 +599,7 @@ static int i40e_delete_lan_hmc_object(struct i40e_hw *hw,
&sd_idx, &sd_lmt);
if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
sd_lmt > info->hmc_info->sd_table.sd_cnt) {
- ret_code = I40E_ERR_INVALID_SD_INDEX;
+ ret_code = -EINVAL;
goto exit;
}
@@ -987,29 +987,29 @@ int i40e_hmc_get_object_va(struct i40e_hw *hw, u8 **object_base,
int ret_code = 0;
if (NULL == hmc_info) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info ptr\n");
goto exit;
}
if (NULL == hmc_info->hmc_obj) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info->hmc_obj ptr\n");
goto exit;
}
if (NULL == object_base) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_hmc_get_object_va: bad object_base ptr\n");
goto exit;
}
if (I40E_HMC_INFO_SIGNATURE != hmc_info->signature) {
- ret_code = I40E_ERR_BAD_PTR;
+ ret_code = -EINVAL;
hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info->signature\n");
goto exit;
}
if (obj_idx >= hmc_info->hmc_obj[rsrc_type].cnt) {
hw_dbg(hw, "i40e_hmc_get_object_va: returns error %d\n",
ret_code);
- ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+ ret_code = -EINVAL;
goto exit;
}
/* find sd index and limit */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 29ad1797adce..de7fd43dc11c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -2609,7 +2609,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
retval = i40e_correct_mac_vlan_filters
(vsi, &tmp_add_list, &tmp_del_list,
vlan_filters);
- else
+ else if (pf->vf)
retval = i40e_correct_vf_mac_vlan_filters
(vsi, &tmp_add_list, &tmp_del_list,
vlan_filters, pf->vf[vsi->vf_id].trusted);
@@ -2782,7 +2782,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
}
/* if the VF is not trusted do not do promisc */
- if ((vsi->type == I40E_VSI_SRIOV) && !pf->vf[vsi->vf_id].trusted) {
+ if (vsi->type == I40E_VSI_SRIOV && pf->vf &&
+ !pf->vf[vsi->vf_id].trusted) {
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
goto out;
}
@@ -3585,11 +3586,6 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
if (ring->xsk_pool) {
ring->rx_buf_len =
xsk_pool_get_rx_frame_size(ring->xsk_pool);
- /* For AF_XDP ZC, we disallow packets to span on
- * multiple buffers, thus letting us skip that
- * handling in the fast-path.
- */
- chain_len = 1;
ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
@@ -5714,7 +5710,7 @@ int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset)
int ret;
if (!vsi)
- return I40E_ERR_PARAM;
+ return -EINVAL;
pf = vsi->back;
hw = &pf->hw;
@@ -7158,7 +7154,7 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
*/
if (pf->hw_features & I40E_HW_NO_DCB_SUPPORT) {
dev_info(&pf->pdev->dev, "DCB is not supported.\n");
- err = I40E_NOT_SUPPORTED;
+ err = -EOPNOTSUPP;
goto out;
}
if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) {
@@ -7468,7 +7464,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up)
if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)
non_zero_phy_type = true;
else if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)
- return I40E_SUCCESS;
+ return 0;
/* To force link we need to set bits for all supported PHY types,
* but there are now more than 32, so we need to split the bitmap
@@ -7519,7 +7515,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up)
i40e_aq_set_link_restart_an(hw, is_up, NULL);
- return I40E_SUCCESS;
+ return 0;
}
/**
@@ -8366,7 +8362,7 @@ int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
};
if (filter->flags >= ARRAY_SIZE(flag_table))
- return I40E_ERR_CONFIG;
+ return -EIO;
memset(&cld_filter, 0, sizeof(cld_filter));
@@ -8530,15 +8526,15 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
u8 field_flags = 0;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
- dev_err(&pf->pdev->dev, "Unsupported key used: 0x%x\n",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
+ dev_err(&pf->pdev->dev, "Unsupported key used: 0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
@@ -8580,7 +8576,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad ether dest mask %pM\n",
match.mask->dst);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -8590,7 +8586,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad ether src mask %pM\n",
match.mask->src);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
ether_addr_copy(filter->dst_mac, match.key->dst);
@@ -8608,7 +8604,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad vlan mask 0x%04x\n",
match.mask->vlan_id);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -8632,7 +8628,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad ip dst mask %pI4b\n",
&match.mask->dst);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -8642,13 +8638,13 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad ip src mask %pI4b\n",
&match.mask->src);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
if (field_flags & I40E_CLOUD_FIELD_TEN_ID) {
dev_err(&pf->pdev->dev, "Tenant id not allowed for ip filter\n");
- return I40E_ERR_CONFIG;
+ return -EIO;
}
filter->dst_ipv4 = match.key->dst;
filter->src_ipv4 = match.key->src;
@@ -8666,7 +8662,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
ipv6_addr_loopback(&match.key->src)) {
dev_err(&pf->pdev->dev,
"Bad ipv6, addr is LOOPBACK\n");
- return I40E_ERR_CONFIG;
+ return -EIO;
}
if (!ipv6_addr_any(&match.mask->dst) ||
!ipv6_addr_any(&match.mask->src))
@@ -8688,7 +8684,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad src port mask 0x%04x\n",
be16_to_cpu(match.mask->src));
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -8698,7 +8694,7 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
} else {
dev_err(&pf->pdev->dev, "Bad dst port mask 0x%04x\n",
be16_to_cpu(match.mask->dst));
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -9906,11 +9902,11 @@ static void i40e_link_event(struct i40e_pf *pf)
status = i40e_get_link_status(&pf->hw, &new_link);
/* On success, disable temp link polling */
- if (status == I40E_SUCCESS) {
+ if (status == 0) {
clear_bit(__I40E_TEMP_LINK_POLLING, pf->state);
} else {
/* Enable link polling temporarily until i40e_get_link_status
- * returns I40E_SUCCESS
+ * returns 0
*/
set_bit(__I40E_TEMP_LINK_POLLING, pf->state);
dev_dbg(&pf->pdev->dev, "couldn't get link state, status: %d\n",
@@ -10164,7 +10160,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
do {
ret = i40e_clean_arq_element(hw, &event, &pending);
- if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK)
+ if (ret == -EALREADY)
break;
else if (ret) {
dev_info(&pf->pdev->dev, "ARQ event error %d\n", ret);
@@ -12574,7 +12570,7 @@ int i40e_commit_partition_bw_setting(struct i40e_pf *pf)
dev_info(&pf->pdev->dev,
"Commit BW only works on partition 1! This is partition %d",
pf->hw.partition_id);
- ret = I40E_NOT_SUPPORTED;
+ ret = -EOPNOTSUPP;
goto bw_commit_out;
}
@@ -12656,10 +12652,10 @@ static bool i40e_is_total_port_shutdown_enabled(struct i40e_pf *pf)
#define I40E_LINK_BEHAVIOR_WORD_LENGTH 0x1
#define I40E_LINK_BEHAVIOR_OS_FORCED_ENABLED BIT(0)
#define I40E_LINK_BEHAVIOR_PORT_BIT_LENGTH 4
- int read_status = I40E_SUCCESS;
u16 sr_emp_sr_settings_ptr = 0;
u16 features_enable = 0;
u16 link_behavior = 0;
+ int read_status = 0;
bool ret = false;
read_status = i40e_read_nvm_word(&pf->hw,
@@ -13822,6 +13818,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETDEV_XDP_ACT_REDIRECT |
NETDEV_XDP_ACT_XSK_ZEROCOPY |
NETDEV_XDP_ACT_RX_SG;
+ netdev->xdp_zc_max_segs = I40E_MAX_BUFFER_TXD;
} else {
/* Relate the VSI_VMDQ name to the VSI_MAIN name. Note that we
* are still limited by IFNAMSIZ, but we're adding 'v%d\0' to
@@ -15466,12 +15463,12 @@ static int i40e_pf_loop_reset(struct i40e_pf *pf)
int ret;
ret = i40e_pf_reset(hw);
- while (ret != I40E_SUCCESS && time_before(jiffies, time_end)) {
+ while (ret != 0 && time_before(jiffies, time_end)) {
usleep_range(10000, 20000);
ret = i40e_pf_reset(hw);
}
- if (ret == I40E_SUCCESS)
+ if (ret == 0)
pf->pfr_count++;
else
dev_info(&pf->pdev->dev, "PF reset failed: %d\n", ret);
@@ -15514,10 +15511,10 @@ static int i40e_handle_resets(struct i40e_pf *pf)
const int pfr = i40e_pf_loop_reset(pf);
const bool is_empr = i40e_check_fw_empr(pf);
- if (is_empr || pfr != I40E_SUCCESS)
+ if (is_empr || pfr != 0)
dev_crit(&pf->pdev->dev, "Entering recovery mode due to repeated FW resets. This may take several minutes. Refer to the Intel(R) Ethernet Adapters and Devices User Guide.\n");
- return is_empr ? I40E_ERR_RESET_FAILED : pfr;
+ return is_empr ? -EIO : pfr;
}
/**
@@ -15810,7 +15807,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = i40e_init_adminq(hw);
if (err) {
- if (err == I40E_ERR_FIRMWARE_API_VERSION)
+ if (err == -EIO)
dev_info(&pdev->dev,
"The driver for the device stopped because the NVM image v%u.%u is newer than expected v%u.%u. You must install the most recent version of the network driver.\n",
hw->aq.api_maj_ver,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
index f99c1f7fec40..07a46adeab38 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
@@ -37,7 +37,7 @@ int i40e_init_nvm(struct i40e_hw *hw)
nvm->blank_nvm_mode = false;
} else { /* Blank programming mode */
nvm->blank_nvm_mode = true;
- ret_code = I40E_ERR_NVM_BLANK_MODE;
+ ret_code = -EIO;
i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
}
@@ -111,8 +111,8 @@ i40e_i40e_acquire_nvm_exit:
**/
void i40e_release_nvm(struct i40e_hw *hw)
{
- int ret_code = I40E_SUCCESS;
u32 total_delay = 0;
+ int ret_code = 0;
if (hw->nvm.blank_nvm_mode)
return;
@@ -122,7 +122,7 @@ void i40e_release_nvm(struct i40e_hw *hw)
/* there are some rare cases when trying to release the resource
* results in an admin Q timeout, so handle them correctly
*/
- while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
+ while ((ret_code == -EIO) &&
(total_delay < hw->aq.asq_cmd_timeout)) {
usleep_range(1000, 2000);
ret_code = i40e_aq_release_resource(hw,
@@ -140,7 +140,7 @@ void i40e_release_nvm(struct i40e_hw *hw)
**/
static int i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
{
- int ret_code = I40E_ERR_TIMEOUT;
+ int ret_code = -EIO;
u32 srctl, wait_cnt;
/* Poll the I40E_GLNVM_SRCTL until the done bit is set */
@@ -152,7 +152,7 @@ static int i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
}
udelay(5);
}
- if (ret_code == I40E_ERR_TIMEOUT)
+ if (ret_code == -EIO)
i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
return ret_code;
}
@@ -168,14 +168,14 @@ static int i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
static int i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
u16 *data)
{
- int ret_code = I40E_ERR_TIMEOUT;
+ int ret_code = -EIO;
u32 sr_reg;
if (offset >= hw->nvm.sr_size) {
i40e_debug(hw, I40E_DEBUG_NVM,
"NVM read error: offset %d beyond Shadow RAM limit %d\n",
offset, hw->nvm.sr_size);
- ret_code = I40E_ERR_PARAM;
+ ret_code = -EINVAL;
goto read_nvm_exit;
}
@@ -222,7 +222,7 @@ static int i40e_read_nvm_aq(struct i40e_hw *hw,
bool last_command)
{
struct i40e_asq_cmd_details cmd_details;
- int ret_code = I40E_ERR_NVM;
+ int ret_code = -EIO;
memset(&cmd_details, 0, sizeof(cmd_details));
cmd_details.wb_desc = &hw->nvm_wb_desc;
@@ -267,7 +267,7 @@ static int i40e_read_nvm_aq(struct i40e_hw *hw,
static int i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
u16 *data)
{
- int ret_code = I40E_ERR_TIMEOUT;
+ int ret_code = -EIO;
ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true);
*data = le16_to_cpu(*(__le16 *)data);
@@ -348,7 +348,7 @@ int i40e_read_nvm_module_data(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_ALL,
"Reading nvm word failed.Error code: %d.\n",
status);
- return I40E_ERR_NVM;
+ return -EIO;
}
}
#define I40E_NVM_INVALID_PTR_VAL 0x7FFF
@@ -358,7 +358,7 @@ int i40e_read_nvm_module_data(struct i40e_hw *hw,
if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
ptr_value == I40E_NVM_INVALID_VAL) {
i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
- return I40E_ERR_BAD_PTR;
+ return -EINVAL;
}
/* Check whether the module is in SR mapped area or outside */
@@ -367,7 +367,7 @@ int i40e_read_nvm_module_data(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_ALL,
"Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
- return I40E_ERR_PARAM;
+ return -EINVAL;
} else {
/* Read from the Shadow RAM */
@@ -377,7 +377,7 @@ int i40e_read_nvm_module_data(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_ALL,
"Reading nvm word failed.Error code: %d.\n",
status);
- return I40E_ERR_NVM;
+ return -EIO;
}
offset = ptr_value + module_offset + specific_ptr +
@@ -549,7 +549,7 @@ static int i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
bool last_command)
{
struct i40e_asq_cmd_details cmd_details;
- int ret_code = I40E_ERR_NVM;
+ int ret_code = -EIO;
memset(&cmd_details, 0, sizeof(cmd_details));
cmd_details.wb_desc = &hw->nvm_wb_desc;
@@ -614,7 +614,7 @@ static int i40e_calc_nvm_checksum(struct i40e_hw *hw,
/* read pointer to VPD area */
ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
if (ret_code) {
- ret_code = I40E_ERR_NVM_CHECKSUM;
+ ret_code = -EIO;
goto i40e_calc_nvm_checksum_exit;
}
@@ -622,7 +622,7 @@ static int i40e_calc_nvm_checksum(struct i40e_hw *hw,
ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
&pcie_alt_module);
if (ret_code) {
- ret_code = I40E_ERR_NVM_CHECKSUM;
+ ret_code = -EIO;
goto i40e_calc_nvm_checksum_exit;
}
@@ -636,7 +636,7 @@ static int i40e_calc_nvm_checksum(struct i40e_hw *hw,
ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
if (ret_code) {
- ret_code = I40E_ERR_NVM_CHECKSUM;
+ ret_code = -EIO;
goto i40e_calc_nvm_checksum_exit;
}
}
@@ -724,7 +724,7 @@ int i40e_validate_nvm_checksum(struct i40e_hw *hw,
* calculated checksum
*/
if (checksum_local != checksum_sr)
- ret_code = I40E_ERR_NVM_CHECKSUM;
+ ret_code = -EIO;
/* If the user cares, return the calculated checksum */
if (checksum)
@@ -839,7 +839,7 @@ int i40e_nvmupd_command(struct i40e_hw *hw,
if (upd_cmd == I40E_NVMUPD_STATUS) {
if (!cmd->data_size) {
*perrno = -EFAULT;
- return I40E_ERR_BUF_TOO_SHORT;
+ return -EINVAL;
}
bytes[0] = hw->nvmupd_state;
@@ -896,7 +896,7 @@ int i40e_nvmupd_command(struct i40e_hw *hw,
break;
}
- status = I40E_ERR_NOT_READY;
+ status = -EBUSY;
*perrno = -EBUSY;
break;
@@ -904,7 +904,7 @@ int i40e_nvmupd_command(struct i40e_hw *hw,
/* invalid state, should never happen */
i40e_debug(hw, I40E_DEBUG_NVM,
"NVMUPD: no such state %d\n", hw->nvmupd_state);
- status = I40E_NOT_SUPPORTED;
+ status = -EOPNOTSUPP;
*perrno = -ESRCH;
break;
}
@@ -1045,7 +1045,7 @@ static int i40e_nvmupd_state_init(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_NVM,
"NVMUPD: bad cmd %s in init state\n",
i40e_nvm_update_state_str[upd_cmd]);
- status = I40E_ERR_NVM;
+ status = -EIO;
*perrno = -ESRCH;
break;
}
@@ -1087,7 +1087,7 @@ static int i40e_nvmupd_state_reading(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_NVM,
"NVMUPD: bad cmd %s in reading state.\n",
i40e_nvm_update_state_str[upd_cmd]);
- status = I40E_NOT_SUPPORTED;
+ status = -EOPNOTSUPP;
*perrno = -ESRCH;
break;
}
@@ -1174,7 +1174,7 @@ retry:
i40e_debug(hw, I40E_DEBUG_NVM,
"NVMUPD: bad cmd %s in writing state.\n",
i40e_nvm_update_state_str[upd_cmd]);
- status = I40E_NOT_SUPPORTED;
+ status = -EOPNOTSUPP;
*perrno = -ESRCH;
break;
}
@@ -1398,7 +1398,7 @@ static int i40e_nvmupd_exec_aq(struct i40e_hw *hw,
"NVMUPD: not enough aq desc bytes for exec, size %d < %d\n",
cmd->data_size, aq_desc_len);
*perrno = -EINVAL;
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
aq_desc = (struct i40e_aq_desc *)bytes;
@@ -1473,7 +1473,7 @@ static int i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n",
__func__, cmd->offset, aq_total_len);
*perrno = -EINVAL;
- return I40E_ERR_PARAM;
+ return -EINVAL;
}
/* check copylength range */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index fe845987d99a..3eeee224f1fb 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -18,7 +18,6 @@
/* adminq functions */
int i40e_init_adminq(struct i40e_hw *hw);
void i40e_shutdown_adminq(struct i40e_hw *hw);
-void i40e_adminq_init_ring_data(struct i40e_hw *hw);
int i40e_clean_arq_element(struct i40e_hw *hw,
struct i40e_arq_event_info *e,
u16 *events_pending);
@@ -51,7 +50,6 @@ i40e_asq_send_command_atomic_v2(struct i40e_hw *hw,
void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
void *desc, void *buffer, u16 buf_len);
-void i40e_idle_aq(struct i40e_hw *hw);
bool i40e_check_asq_alive(struct i40e_hw *hw);
int i40e_aq_queue_shutdown(struct i40e_hw *hw, bool unloading);
const char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err);
@@ -117,9 +115,6 @@ int i40e_aq_set_link_restart_an(struct i40e_hw *hw,
int i40e_aq_get_link_info(struct i40e_hw *hw,
bool enable_lse, struct i40e_link_status *link,
struct i40e_asq_cmd_details *cmd_details);
-int i40e_aq_set_local_advt_reg(struct i40e_hw *hw,
- u64 advt_reg,
- struct i40e_asq_cmd_details *cmd_details);
int i40e_aq_send_driver_version(struct i40e_hw *hw,
struct i40e_driver_version *dv,
struct i40e_asq_cmd_details *cmd_details);
@@ -269,9 +264,6 @@ int i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
int i40e_aq_dcb_updated(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
-int i40e_aq_config_switch_comp_bw_limit(struct i40e_hw *hw,
- u16 seid, u16 credit, u8 max_bw,
- struct i40e_asq_cmd_details *cmd_details);
int i40e_aq_config_vsi_tc_bw(struct i40e_hw *hw, u16 seid,
struct i40e_aqc_configure_vsi_tc_bw_data *bw_data,
struct i40e_asq_cmd_details *cmd_details);
@@ -350,7 +342,6 @@ i40e_aq_configure_partition_bw(struct i40e_hw *hw,
int i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
int i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num,
u32 pba_num_size);
-int i40e_validate_mac_addr(u8 *mac_addr);
void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable);
/* prototype for functions used for NVM access */
int i40e_init_nvm(struct i40e_hw *hw);
@@ -425,14 +416,6 @@ i40e_virtchnl_link_speed(enum i40e_aq_link_speed link_speed)
/* prototype for functions used for SW locks */
/* i40e_common for VF drivers*/
-void i40e_vf_parse_hw_config(struct i40e_hw *hw,
- struct virtchnl_vf_resource *msg);
-int i40e_vf_reset(struct i40e_hw *hw);
-int i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
- enum virtchnl_ops v_opcode,
- int v_retval,
- u8 *msg, u16 msglen,
- struct i40e_asq_cmd_details *cmd_details);
int i40e_set_filter_control(struct i40e_hw *hw,
struct i40e_filter_control_settings *settings);
int i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index c37abbb3cd06..8a26811140b4 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -1132,7 +1132,7 @@ int i40e_ptp_alloc_pins(struct i40e_pf *pf)
if (!pf->ptp_pins) {
dev_warn(&pf->pdev->dev, "Cannot allocate memory for PTP pins structure.\n");
- return -I40E_ERR_NO_MEMORY;
+ return -ENOMEM;
}
pf->ptp_pins->sdp3_2 = off;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_status.h b/drivers/net/ethernet/intel/i40e/i40e_status.h
deleted file mode 100644
index 4d2782e76038..000000000000
--- a/drivers/net/ethernet/intel/i40e/i40e_status.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright(c) 2013 - 2018 Intel Corporation. */
-
-#ifndef _I40E_STATUS_H_
-#define _I40E_STATUS_H_
-
-/* Error Codes */
-enum i40e_status_code {
- I40E_SUCCESS = 0,
- I40E_ERR_NVM = -1,
- I40E_ERR_NVM_CHECKSUM = -2,
- I40E_ERR_CONFIG = -4,
- I40E_ERR_PARAM = -5,
- I40E_ERR_UNKNOWN_PHY = -7,
- I40E_ERR_INVALID_MAC_ADDR = -10,
- I40E_ERR_DEVICE_NOT_SUPPORTED = -11,
- I40E_ERR_RESET_FAILED = -15,
- I40E_ERR_NO_AVAILABLE_VSI = -17,
- I40E_ERR_NO_MEMORY = -18,
- I40E_ERR_BAD_PTR = -19,
- I40E_ERR_INVALID_SIZE = -26,
- I40E_ERR_QUEUE_EMPTY = -32,
- I40E_ERR_TIMEOUT = -37,
- I40E_ERR_INVALID_SD_INDEX = -45,
- I40E_ERR_INVALID_PAGE_DESC_INDEX = -46,
- I40E_ERR_INVALID_SD_TYPE = -47,
- I40E_ERR_INVALID_HMC_OBJ_INDEX = -49,
- I40E_ERR_INVALID_HMC_OBJ_COUNT = -50,
- I40E_ERR_ADMIN_QUEUE_ERROR = -53,
- I40E_ERR_ADMIN_QUEUE_TIMEOUT = -54,
- I40E_ERR_BUF_TOO_SHORT = -55,
- I40E_ERR_ADMIN_QUEUE_FULL = -56,
- I40E_ERR_ADMIN_QUEUE_NO_WORK = -57,
- I40E_ERR_NVM_BLANK_MODE = -59,
- I40E_ERR_NOT_IMPLEMENTED = -60,
- I40E_ERR_DIAG_TEST_FAILED = -62,
- I40E_ERR_NOT_READY = -63,
- I40E_NOT_SUPPORTED = -64,
- I40E_ERR_FIRMWARE_API_VERSION = -65,
- I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66,
-};
-
-#endif /* _I40E_STATUS_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 8b8bf4880faa..0b3a27f118fb 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2284,8 +2284,8 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
* If the buffer is an EOP buffer, this function exits returning false,
* otherwise return true indicating that this is in fact a non-EOP buffer.
*/
-static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
- union i40e_rx_desc *rx_desc)
+bool i40e_is_non_eop(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc)
{
/* if we are the last buffer then there is nothing else to do */
#define I40E_RXD_EOF BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 8c3d24012c54..900b0d9ede9f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -473,6 +473,8 @@ int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
bool __i40e_chk_linearize(struct sk_buff *skb);
int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
u32 flags);
+bool i40e_is_non_eop(struct i40e_ring *rx_ring,
+ union i40e_rx_desc *rx_desc);
/**
* i40e_get_head - Retrieve head from head writeback
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 388c3d36d96a..232131bedc3e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -4,7 +4,6 @@
#ifndef _I40E_TYPE_H_
#define _I40E_TYPE_H_
-#include "i40e_status.h"
#include "i40e_osdep.h"
#include "i40e_register.h"
#include "i40e_adminq.h"
@@ -1456,7 +1455,7 @@ struct i40e_ddp_version {
struct i40e_package_header {
struct i40e_ddp_version version;
u32 segment_count;
- u32 segment_offset[1];
+ u32 segment_offset[];
};
/* Generic segment header */
@@ -1487,12 +1486,12 @@ struct i40e_profile_segment {
struct i40e_ddp_version version;
char name[I40E_DDP_NAME_SIZE];
u32 device_table_count;
- struct i40e_device_id_entry device_table[1];
+ struct i40e_device_id_entry device_table[];
};
struct i40e_section_table {
u32 section_count;
- u32 section_offset[1];
+ u32 section_offset[];
};
struct i40e_profile_section_header {
@@ -1524,7 +1523,7 @@ struct i40e_profile_aq_section {
u16 flags;
u8 param[16];
u16 datalen;
- u8 data[1];
+ u8 data[];
};
struct i40e_profile_info {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index be59ba3774e1..8ea1a238dcef 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -506,6 +506,7 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
struct virtchnl_rdma_qv_info *qv_info;
u32 v_idx, i, reg_idx, reg;
u32 next_q_idx, next_q_type;
+ size_t size;
u32 msix_vf;
int ret = 0;
@@ -521,9 +522,9 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
}
kfree(vf->qvlist_info);
- vf->qvlist_info = kzalloc(struct_size(vf->qvlist_info, qv_info,
- qvlist_info->num_vectors - 1),
- GFP_KERNEL);
+ size = virtchnl_struct_size(vf->qvlist_info, qv_info,
+ qvlist_info->num_vectors);
+ vf->qvlist_info = kzalloc(size, GFP_KERNEL);
if (!vf->qvlist_info) {
ret = -ENOMEM;
goto err_out;
@@ -1346,14 +1347,14 @@ static int i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
bool alluni)
{
struct i40e_pf *pf = vf->pf;
- int aq_ret = I40E_SUCCESS;
struct i40e_vsi *vsi;
+ int aq_ret = 0;
u16 num_vlans;
s16 *vl;
vsi = i40e_find_vsi_from_id(pf, vsi_id);
if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
- return I40E_ERR_PARAM;
+ return -EINVAL;
if (vf->port_vlan_id) {
aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti,
@@ -1363,7 +1364,7 @@ static int i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
i40e_get_vlan_list_sync(vsi, &num_vlans, &vl);
if (!vl)
- return I40E_ERR_NO_MEMORY;
+ return -ENOMEM;
aq_ret = i40e_set_vsi_promisc(vf, vsi->seid, allmulti, alluni,
vl, num_vlans);
@@ -2037,7 +2038,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg)
if (VF_IS_V10(&vf->vf_ver))
info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION,
- I40E_SUCCESS, (u8 *)&info,
+ 0, (u8 *)&info,
sizeof(struct virtchnl_version_info));
}
@@ -2099,14 +2100,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
int ret;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_INIT)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
- len = struct_size(vfres, vsi_res, num_vsis);
+ len = virtchnl_struct_size(vfres, vsi_res, num_vsis);
vfres = kzalloc(len, GFP_KERNEL);
if (!vfres) {
- aq_ret = I40E_ERR_NO_MEMORY;
+ aq_ret = -ENOMEM;
len = 0;
goto err;
}
@@ -2159,7 +2160,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
dev_err(&pf->pdev->dev,
"VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
@@ -2227,7 +2228,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
@@ -2243,12 +2244,12 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
}
if (info->flags > I40E_MAX_VF_PROMISC_FLAGS) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
if (!i40e_vc_isvalid_vsi_id(vf, info->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
@@ -2315,17 +2316,17 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_isvalid_vsi_id(vf, qci->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (qci->num_queue_pairs > I40E_MAX_VF_QUEUES) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -2333,7 +2334,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
for (i = 0; i < vf->num_tc; i++)
num_qps_all += vf->ch[i].num_qps;
if (num_qps_all != qci->num_queue_pairs) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
}
@@ -2346,7 +2347,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
if (!vf->adq_enabled) {
if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
qpi->txq.queue_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -2355,14 +2356,14 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
if (qpi->txq.vsi_id != qci->vsi_id ||
qpi->rxq.vsi_id != qci->vsi_id ||
qpi->rxq.queue_id != vsi_queue_id) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
}
if (vf->adq_enabled) {
if (idx >= ARRAY_SIZE(vf->ch)) {
- aq_ret = I40E_ERR_NO_AVAILABLE_VSI;
+ aq_ret = -ENODEV;
goto error_param;
}
vsi_id = vf->ch[idx].vsi_id;
@@ -2372,7 +2373,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
&qpi->rxq) ||
i40e_config_vsi_tx_queue(vf, vsi_id, vsi_queue_id,
&qpi->txq)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -2383,7 +2384,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
*/
if (vf->adq_enabled) {
if (idx >= ARRAY_SIZE(vf->ch)) {
- aq_ret = I40E_ERR_NO_AVAILABLE_VSI;
+ aq_ret = -ENODEV;
goto error_param;
}
if (j == (vf->ch[idx].num_qps - 1)) {
@@ -2406,7 +2407,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
vsi->num_queue_pairs = vf->ch[i].num_qps;
if (i40e_update_adq_vsi_queues(vsi, i)) {
- aq_ret = I40E_ERR_CONFIG;
+ aq_ret = -EIO;
goto error_param;
}
}
@@ -2464,13 +2465,13 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
int i;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (irqmap_info->num_vectors >
vf->pf->hw.func_caps.num_msix_vectors_vf) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -2479,18 +2480,18 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
/* validate msg params */
if (!i40e_vc_isvalid_vector_id(vf, map->vector_id) ||
!i40e_vc_isvalid_vsi_id(vf, map->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
vsi_id = map->vsi_id;
if (i40e_validate_queue_map(vf, vsi_id, map->rxq_map)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (i40e_validate_queue_map(vf, vsi_id, map->txq_map)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -2579,29 +2580,29 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
int i;
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_validate_vqs_bitmaps(vqs)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
/* Use the queue bit map sent by the VF */
if (i40e_ctrl_vf_rx_rings(pf->vsi[vf->lan_vsi_idx], vqs->rx_queues,
true)) {
- aq_ret = I40E_ERR_TIMEOUT;
+ aq_ret = -EIO;
goto error_param;
}
if (i40e_ctrl_vf_tx_rings(pf->vsi[vf->lan_vsi_idx], vqs->tx_queues,
true)) {
- aq_ret = I40E_ERR_TIMEOUT;
+ aq_ret = -EIO;
goto error_param;
}
@@ -2610,7 +2611,7 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
/* zero belongs to LAN VSI */
for (i = 1; i < vf->num_tc; i++) {
if (i40e_vsi_start_rings(pf->vsi[vf->ch[i].vsi_idx]))
- aq_ret = I40E_ERR_TIMEOUT;
+ aq_ret = -EIO;
}
}
@@ -2636,29 +2637,29 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_validate_vqs_bitmaps(vqs)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
/* Use the queue bit map sent by the VF */
if (i40e_ctrl_vf_tx_rings(pf->vsi[vf->lan_vsi_idx], vqs->tx_queues,
false)) {
- aq_ret = I40E_ERR_TIMEOUT;
+ aq_ret = -EIO;
goto error_param;
}
if (i40e_ctrl_vf_rx_rings(pf->vsi[vf->lan_vsi_idx], vqs->rx_queues,
false)) {
- aq_ret = I40E_ERR_TIMEOUT;
+ aq_ret = -EIO;
goto error_param;
}
error_param:
@@ -2790,18 +2791,18 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
memset(&stats, 0, sizeof(struct i40e_eth_stats));
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
vsi = pf->vsi[vf->lan_vsi_idx];
if (!vsi) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
i40e_update_eth_stats(vsi);
@@ -2862,7 +2863,7 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
is_zero_ether_addr(addr)) {
dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n",
addr);
- return I40E_ERR_INVALID_MAC_ADDR;
+ return -EINVAL;
}
/* If the host VMM administrator has set the VF MAC address
@@ -2998,7 +2999,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
!i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
- ret = I40E_ERR_PARAM;
+ ret = -EINVAL;
goto error_param;
}
@@ -3027,7 +3028,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
dev_err(&pf->pdev->dev,
"Unable to add MAC filter %pM for VF %d\n",
al->list[i].addr, vf->vf_id);
- ret = I40E_ERR_PARAM;
+ ret = -EINVAL;
spin_unlock_bh(&vsi->mac_filter_hash_lock);
goto error_param;
}
@@ -3067,7 +3068,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
!i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
- ret = I40E_ERR_PARAM;
+ ret = -EINVAL;
goto error_param;
}
@@ -3076,7 +3077,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
is_zero_ether_addr(al->list[i].addr)) {
dev_err(&pf->pdev->dev, "Invalid MAC addr %pM for VF %d\n",
al->list[i].addr, vf->vf_id);
- ret = I40E_ERR_INVALID_MAC_ADDR;
+ ret = -EINVAL;
goto error_param;
}
if (ether_addr_equal(al->list[i].addr, vf->default_lan_addr.addr))
@@ -3088,7 +3089,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
/* delete addresses from the list */
for (i = 0; i < al->num_elements; i++)
if (i40e_del_mac_filter(vsi, al->list[i].addr)) {
- ret = I40E_ERR_INVALID_MAC_ADDR;
+ ret = -EINVAL;
spin_unlock_bh(&vsi->mac_filter_hash_lock);
goto error_param;
}
@@ -3149,13 +3150,13 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
}
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
!i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
for (i = 0; i < vfl->num_elements; i++) {
if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
dev_err(&pf->pdev->dev,
"invalid VF VLAN id %d\n", vfl->vlan_id[i]);
goto error_param;
@@ -3163,7 +3164,7 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
}
vsi = pf->vsi[vf->lan_vsi_idx];
if (vsi->info.pvid) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -3214,13 +3215,13 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
!i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
for (i = 0; i < vfl->num_elements; i++) {
if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
}
@@ -3228,7 +3229,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
vsi = pf->vsi[vf->lan_vsi_idx];
if (vsi->info.pvid) {
if (vfl->num_elements > 1 || vfl->vlan_id[0])
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -3269,7 +3270,7 @@ static int i40e_vc_rdma_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
!test_bit(I40E_VF_STATE_RDMAENA, &vf->vf_states)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
@@ -3298,13 +3299,13 @@ static int i40e_vc_rdma_qvmap_msg(struct i40e_vf *vf, u8 *msg, bool config)
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
!test_bit(I40E_VF_STATE_RDMAENA, &vf->vf_states)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto error_param;
}
if (config) {
if (i40e_config_rdma_qvlist(vf, qvlist_info))
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
} else {
i40e_release_rdma_qvlist(vf);
}
@@ -3335,7 +3336,7 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
!i40e_vc_isvalid_vsi_id(vf, vrk->vsi_id) ||
vrk->key_len != I40E_HKEY_ARRAY_SIZE) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3366,13 +3367,13 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
!i40e_vc_isvalid_vsi_id(vf, vrl->vsi_id) ||
vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
for (i = 0; i < vrl->lut_entries; i++)
if (vrl->lut[i] >= vf->num_queue_pairs) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3399,14 +3400,14 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg)
int len = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
len = sizeof(struct virtchnl_rss_hena);
vrh = kzalloc(len, GFP_KERNEL);
if (!vrh) {
- aq_ret = I40E_ERR_NO_MEMORY;
+ aq_ret = -ENOMEM;
len = 0;
goto err;
}
@@ -3435,7 +3436,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)vrh->hena);
@@ -3460,7 +3461,7 @@ static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3486,7 +3487,7 @@ static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3574,7 +3575,7 @@ static int i40e_validate_cloud_filter(struct i40e_vf *vf,
dev_err(&pf->pdev->dev,
"VF %d not trusted, make VF trusted to add advanced mode ADq cloud filters\n",
vf->vf_id);
- return I40E_ERR_CONFIG;
+ return -EIO;
}
}
@@ -3627,9 +3628,9 @@ static int i40e_validate_cloud_filter(struct i40e_vf *vf,
}
}
- return I40E_SUCCESS;
+ return 0;
err:
- return I40E_ERR_CONFIG;
+ return -EIO;
}
/**
@@ -3713,7 +3714,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
int i, ret;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3721,7 +3722,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
dev_info(&pf->pdev->dev,
"VF %d: ADq not enabled, can't apply cloud filter\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3729,7 +3730,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
dev_info(&pf->pdev->dev,
"VF %d: Invalid input, can't apply cloud filter\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3844,7 +3845,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
int i, ret;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
@@ -3852,7 +3853,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
dev_info(&pf->pdev->dev,
"VF %d: ADq is not enabled, can't apply cloud filter\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
@@ -3860,7 +3861,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
dev_info(&pf->pdev->dev,
"VF %d: Invalid input/s, can't apply cloud filter\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err_out;
}
@@ -3953,7 +3954,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
u64 speed = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3961,7 +3962,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
if (vf->spoofchk) {
dev_err(&pf->pdev->dev,
"Spoof check is ON, turn it OFF to enable ADq\n");
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3969,7 +3970,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
dev_err(&pf->pdev->dev,
"VF %d attempting to enable ADq, but hasn't properly negotiated that capability\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3978,7 +3979,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
dev_err(&pf->pdev->dev,
"VF %d trying to set %u TCs, valid range 1-%u TCs per VF\n",
vf->vf_id, tci->num_tc, I40E_MAX_VF_VSI);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -3990,7 +3991,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
"VF %d: TC %d trying to set %u queues, valid range 1-%u queues per TC\n",
vf->vf_id, i, tci->list[i].count,
I40E_DEFAULT_QUEUES_PER_VF);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -4001,7 +4002,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
dev_err(&pf->pdev->dev,
"No queues left to allocate to VF %d\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
} else {
/* we need to allocate max VF queues to enable ADq so as to
@@ -4016,7 +4017,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
if (speed == SPEED_UNKNOWN) {
dev_err(&pf->pdev->dev,
"Cannot detect link speed\n");
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -4029,7 +4030,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
"Invalid max tx rate %llu specified for VF %d.",
tci->list[i].max_tx_rate,
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
} else {
vf->ch[i].max_tx_rate =
@@ -4045,7 +4046,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
/* reset the VF in order to allocate resources */
i40e_vc_reset_vf(vf, true);
- return I40E_SUCCESS;
+ return 0;
/* send the response to the VF */
err:
@@ -4064,7 +4065,7 @@ static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
goto err;
}
@@ -4079,13 +4080,13 @@ static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
} else {
dev_info(&pf->pdev->dev, "VF %d trying to delete queue channels but ADq isn't enabled\n",
vf->vf_id);
- aq_ret = I40E_ERR_PARAM;
+ aq_ret = -EINVAL;
}
/* reset the VF in order to allocate resources */
i40e_vc_reset_vf(vf, true);
- return I40E_SUCCESS;
+ return 0;
err:
return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_CHANNELS,
@@ -4119,21 +4120,16 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
/* Check if VF is disabled. */
if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states))
- return I40E_ERR_PARAM;
+ return -EINVAL;
/* perform basic checks on the msg */
ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen);
if (ret) {
- i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM);
+ i40e_vc_send_resp_to_vf(vf, v_opcode, -EINVAL);
dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n",
local_vf_id, v_opcode, msglen);
- switch (ret) {
- case VIRTCHNL_STATUS_ERR_PARAM:
- return -EPERM;
- default:
- return -EINVAL;
- }
+ return ret;
}
switch (v_opcode) {
@@ -4226,7 +4222,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n",
v_opcode, local_vf_id);
ret = i40e_vc_send_resp_to_vf(vf, v_opcode,
- I40E_ERR_NOT_IMPLEMENTED);
+ -EOPNOTSUPP);
break;
}
@@ -4305,6 +4301,38 @@ err_out:
}
/**
+ * i40e_check_vf_init_timeout
+ * @vf: the virtual function
+ *
+ * Check that the VF's initialization was successfully done and if not
+ * wait up to 300ms for its finish.
+ *
+ * Returns true when VF is initialized, false on timeout
+ **/
+static bool i40e_check_vf_init_timeout(struct i40e_vf *vf)
+{
+ int i;
+
+ /* When the VF is resetting wait until it is done.
+ * It can take up to 200 milliseconds, but wait for
+ * up to 300 milliseconds to be safe.
+ */
+ for (i = 0; i < 15; i++) {
+ if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
+ return true;
+ msleep(20);
+ }
+
+ if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+ dev_err(&vf->pf->pdev->dev,
+ "VF %d still in reset. Try again.\n", vf->vf_id);
+ return false;
+ }
+
+ return true;
+}
+
+/**
* i40e_ndo_set_vf_mac
* @netdev: network interface device structure
* @vf_id: VF identifier
@@ -4322,7 +4350,6 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
int ret = 0;
struct hlist_node *h;
int bkt;
- u8 i;
if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
@@ -4335,21 +4362,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
goto error_param;
vf = &pf->vf[vf_id];
-
- /* When the VF is resetting wait until it is done.
- * It can take up to 200 milliseconds,
- * but wait for up to 300 milliseconds to be safe.
- * Acquire the VSI pointer only after the VF has been
- * properly initialized.
- */
- for (i = 0; i < 15; i++) {
- if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
- break;
- msleep(20);
- }
- if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
- dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
- vf_id);
+ if (!i40e_check_vf_init_timeout(vf)) {
ret = -EAGAIN;
goto error_param;
}
@@ -4451,13 +4464,11 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
}
vf = &pf->vf[vf_id];
- vsi = pf->vsi[vf->lan_vsi_idx];
- if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
- dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
- vf_id);
+ if (!i40e_check_vf_init_timeout(vf)) {
ret = -EAGAIN;
goto error_pvid;
}
+ vsi = pf->vsi[vf->lan_vsi_idx];
if (le16_to_cpu(vsi->info.pvid) == vlanprio)
/* duplicate request, so just return success */
@@ -4601,13 +4612,11 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
}
vf = &pf->vf[vf_id];
- vsi = pf->vsi[vf->lan_vsi_idx];
- if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
- dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
- vf_id);
+ if (!i40e_check_vf_init_timeout(vf)) {
ret = -EAGAIN;
goto error;
}
+ vsi = pf->vsi[vf->lan_vsi_idx];
ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
if (ret)
@@ -4774,9 +4783,7 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
}
vf = &(pf->vf[vf_id]);
- if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
- dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
- vf_id);
+ if (!i40e_check_vf_init_timeout(vf)) {
ret = -EAGAIN;
goto out;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 05ec1181471e..37f41c8a682f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -294,8 +294,14 @@ static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring,
{
unsigned int totalsize = xdp->data_end - xdp->data_meta;
unsigned int metasize = xdp->data - xdp->data_meta;
+ struct skb_shared_info *sinfo = NULL;
struct sk_buff *skb;
+ u32 nr_frags = 0;
+ if (unlikely(xdp_buff_has_frags(xdp))) {
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ nr_frags = sinfo->nr_frags;
+ }
net_prefetch(xdp->data_meta);
/* allocate a skb to store the frags */
@@ -312,6 +318,28 @@ static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring,
__skb_pull(skb, metasize);
}
+ if (likely(!xdp_buff_has_frags(xdp)))
+ goto out;
+
+ for (int i = 0; i < nr_frags; i++) {
+ struct skb_shared_info *skinfo = skb_shinfo(skb);
+ skb_frag_t *frag = &sinfo->frags[i];
+ struct page *page;
+ void *addr;
+
+ page = dev_alloc_page();
+ if (!page) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ addr = page_to_virt(page);
+
+ memcpy(addr, skb_frag_page(frag), skb_frag_size(frag));
+
+ __skb_fill_page_desc_noacc(skinfo, skinfo->nr_frags++,
+ addr, 0, skb_frag_size(frag));
+ }
+
out:
xsk_buff_free(xdp);
return skb;
@@ -322,14 +350,13 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
union i40e_rx_desc *rx_desc,
unsigned int *rx_packets,
unsigned int *rx_bytes,
- unsigned int size,
unsigned int xdp_res,
bool *failure)
{
struct sk_buff *skb;
*rx_packets = 1;
- *rx_bytes = size;
+ *rx_bytes = xdp_get_buff_len(xdp_buff);
if (likely(xdp_res == I40E_XDP_REDIR) || xdp_res == I40E_XDP_TX)
return;
@@ -363,7 +390,6 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
return;
}
- *rx_bytes = skb->len;
i40e_process_skb_fields(rx_ring, rx_desc, skb);
napi_gro_receive(&rx_ring->q_vector->napi, skb);
return;
@@ -374,6 +400,31 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
WARN_ON_ONCE(1);
}
+static int
+i40e_add_xsk_frag(struct i40e_ring *rx_ring, struct xdp_buff *first,
+ struct xdp_buff *xdp, const unsigned int size)
+{
+ struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(first);
+
+ if (!xdp_buff_has_frags(first)) {
+ sinfo->nr_frags = 0;
+ sinfo->xdp_frags_size = 0;
+ xdp_buff_set_frags_flag(first);
+ }
+
+ if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) {
+ xsk_buff_free(first);
+ return -ENOMEM;
+ }
+
+ __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++,
+ virt_to_page(xdp->data_hard_start), 0, size);
+ sinfo->xdp_frags_size += size;
+ xsk_buff_add_frag(xdp);
+
+ return 0;
+}
+
/**
* i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring
* @rx_ring: Rx ring
@@ -384,13 +435,18 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ u16 next_to_process = rx_ring->next_to_process;
u16 next_to_clean = rx_ring->next_to_clean;
u16 count_mask = rx_ring->count - 1;
unsigned int xdp_res, xdp_xmit = 0;
+ struct xdp_buff *first = NULL;
struct bpf_prog *xdp_prog;
bool failure = false;
u16 cleaned_count;
+ if (next_to_process != next_to_clean)
+ first = *i40e_rx_bi(rx_ring, next_to_clean);
+
/* NB! xdp_prog will always be !NULL, due to the fact that
* this path is enabled by setting an XDP program.
*/
@@ -404,7 +460,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
unsigned int size;
u64 qword;
- rx_desc = I40E_RX_DESC(rx_ring, next_to_clean);
+ rx_desc = I40E_RX_DESC(rx_ring, next_to_process);
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
/* This memory barrier is needed to keep us from reading
@@ -417,9 +473,9 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
i40e_clean_programming_status(rx_ring,
rx_desc->raw.qword[0],
qword);
- bi = *i40e_rx_bi(rx_ring, next_to_clean);
+ bi = *i40e_rx_bi(rx_ring, next_to_process);
xsk_buff_free(bi);
- next_to_clean = (next_to_clean + 1) & count_mask;
+ next_to_process = (next_to_process + 1) & count_mask;
continue;
}
@@ -428,22 +484,35 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
if (!size)
break;
- bi = *i40e_rx_bi(rx_ring, next_to_clean);
+ bi = *i40e_rx_bi(rx_ring, next_to_process);
xsk_buff_set_size(bi, size);
xsk_buff_dma_sync_for_cpu(bi, rx_ring->xsk_pool);
- xdp_res = i40e_run_xdp_zc(rx_ring, bi, xdp_prog);
- i40e_handle_xdp_result_zc(rx_ring, bi, rx_desc, &rx_packets,
- &rx_bytes, size, xdp_res, &failure);
+ if (!first)
+ first = bi;
+ else if (i40e_add_xsk_frag(rx_ring, first, bi, size))
+ break;
+
+ next_to_process = (next_to_process + 1) & count_mask;
+
+ if (i40e_is_non_eop(rx_ring, rx_desc))
+ continue;
+
+ xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
+ i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
+ &rx_bytes, xdp_res, &failure);
+ first->flags = 0;
+ next_to_clean = next_to_process;
if (failure)
break;
total_rx_packets += rx_packets;
total_rx_bytes += rx_bytes;
xdp_xmit |= xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR);
- next_to_clean = (next_to_clean + 1) & count_mask;
+ first = NULL;
}
rx_ring->next_to_clean = next_to_clean;
+ rx_ring->next_to_process = next_to_process;
cleaned_count = (next_to_clean - rx_ring->next_to_use - 1) & count_mask;
if (cleaned_count >= I40E_RX_BUFFER_WRITE)
@@ -466,6 +535,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
static void i40e_xmit_pkt(struct i40e_ring *xdp_ring, struct xdp_desc *desc,
unsigned int *total_bytes)
{
+ u32 cmd = I40E_TX_DESC_CMD_ICRC | xsk_is_eop_desc(desc);
struct i40e_tx_desc *tx_desc;
dma_addr_t dma;
@@ -474,8 +544,7 @@ static void i40e_xmit_pkt(struct i40e_ring *xdp_ring, struct xdp_desc *desc,
tx_desc = I40E_TX_DESC(xdp_ring, xdp_ring->next_to_use++);
tx_desc->buffer_addr = cpu_to_le64(dma);
- tx_desc->cmd_type_offset_bsz = build_ctob(I40E_TX_DESC_CMD_ICRC | I40E_TX_DESC_CMD_EOP,
- 0, desc->len, 0);
+ tx_desc->cmd_type_offset_bsz = build_ctob(cmd, 0, desc->len, 0);
*total_bytes += desc->len;
}
@@ -489,14 +558,14 @@ static void i40e_xmit_pkt_batch(struct i40e_ring *xdp_ring, struct xdp_desc *des
u32 i;
loop_unrolled_for(i = 0; i < PKTS_PER_BATCH; i++) {
+ u32 cmd = I40E_TX_DESC_CMD_ICRC | xsk_is_eop_desc(&desc[i]);
+
dma = xsk_buff_raw_get_dma(xdp_ring->xsk_pool, desc[i].addr);
xsk_buff_raw_dma_sync_for_device(xdp_ring->xsk_pool, dma, desc[i].len);
tx_desc = I40E_TX_DESC(xdp_ring, ntu++);
tx_desc->buffer_addr = cpu_to_le64(dma);
- tx_desc->cmd_type_offset_bsz = build_ctob(I40E_TX_DESC_CMD_ICRC |
- I40E_TX_DESC_CMD_EOP,
- 0, desc[i].len, 0);
+ tx_desc->cmd_type_offset_bsz = build_ctob(cmd, 0, desc[i].len, 0);
*total_bytes += desc[i].len;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 8cbdebc5b698..85fba85fbb23 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -92,9 +92,9 @@ struct iavf_vsi {
#define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */
#define IAVF_MBPS_QUANTA 50
-#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE (sizeof(struct virtchnl_vf_resource) + \
- (IAVF_MAX_VF_VSI * \
- sizeof(struct virtchnl_vsi_resource)))
+#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE \
+ virtchnl_struct_size((struct virtchnl_vf_resource *)NULL, \
+ vsi_res, IAVF_MAX_VF_VSI)
/* MAX_MSIX_Q_VECTORS of these are allocated,
* but we only use one per queue-specific vector.
diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.c b/drivers/net/ethernet/intel/iavf/iavf_client.c
index 93c903c02c64..e6051b6355aa 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_client.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.c
@@ -469,8 +469,8 @@ static int iavf_client_setup_qvlist(struct iavf_info *ldev,
}
v_qvlist_info = (struct virtchnl_rdma_qvlist_info *)qvlist_info;
- msg_size = struct_size(v_qvlist_info, qv_info,
- v_qvlist_info->num_vectors - 1);
+ msg_size = virtchnl_struct_size(v_qvlist_info, qv_info,
+ v_qvlist_info->num_vectors);
adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP);
err = iavf_aq_send_msg_to_pf(&adapter->hw,
diff --git a/drivers/net/ethernet/intel/iavf/iavf_client.h b/drivers/net/ethernet/intel/iavf/iavf_client.h
index c5d51d7dc7cc..500269bc0f5b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_client.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_client.h
@@ -53,7 +53,7 @@ struct iavf_qv_info {
struct iavf_qvlist_info {
u32 num_vectors;
- struct iavf_qv_info qv_info[1];
+ struct iavf_qv_info qv_info[];
};
#define IAVF_CLIENT_MSIX_ALL 0xFFFFFFFF
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 9610ca770349..7b300c86ceda 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -3744,15 +3744,15 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
struct virtchnl_filter *vf = &filter->f;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
- dev_err(&adapter->pdev->dev, "Unsupported key used: 0x%x\n",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
+ dev_err(&adapter->pdev->dev, "Unsupported key used: 0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index be3c007ce90a..f9727e9c3d63 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -215,8 +215,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter)
u16 len;
int err;
- len = sizeof(struct virtchnl_vf_resource) +
- IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
+ len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE;
event.buf_len = len;
event.msg_buf = kzalloc(len, GFP_KERNEL);
if (!event.msg_buf)
@@ -284,7 +283,7 @@ void iavf_configure_queues(struct iavf_adapter *adapter)
return;
}
adapter->current_op = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
- len = struct_size(vqci, qpair, pairs);
+ len = virtchnl_struct_size(vqci, qpair, pairs);
vqci = kzalloc(len, GFP_KERNEL);
if (!vqci)
return;
@@ -397,7 +396,7 @@ void iavf_map_queues(struct iavf_adapter *adapter)
q_vectors = adapter->num_msix_vectors - NONQ_VECS;
- len = struct_size(vimi, vecmap, adapter->num_msix_vectors);
+ len = virtchnl_struct_size(vimi, vecmap, adapter->num_msix_vectors);
vimi = kzalloc(len, GFP_KERNEL);
if (!vimi)
return;
@@ -476,13 +475,11 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
}
adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR;
- len = struct_size(veal, list, count);
+ len = virtchnl_struct_size(veal, list, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add MAC changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE -
- sizeof(struct virtchnl_ether_addr_list)) /
- sizeof(struct virtchnl_ether_addr);
- len = struct_size(veal, list, count);
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(veal, list, --count);
more = true;
}
@@ -547,13 +544,11 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter)
}
adapter->current_op = VIRTCHNL_OP_DEL_ETH_ADDR;
- len = struct_size(veal, list, count);
+ len = virtchnl_struct_size(veal, list, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete MAC changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE -
- sizeof(struct virtchnl_ether_addr_list)) /
- sizeof(struct virtchnl_ether_addr);
- len = struct_size(veal, list, count);
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(veal, list, --count);
more = true;
}
veal = kzalloc(len, GFP_ATOMIC);
@@ -687,12 +682,12 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
- len = sizeof(*vvfl) + (count * sizeof(u16));
+ len = virtchnl_struct_size(vvfl, vlan_id, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
- sizeof(u16);
- len = sizeof(*vvfl) + (count * sizeof(u16));
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(vvfl, vlan_id,
+ --count);
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
@@ -732,15 +727,12 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
more = true;
}
- len = sizeof(*vvfl_v2) + ((count - 1) *
- sizeof(struct virtchnl_vlan_filter));
+ len = virtchnl_struct_size(vvfl_v2, filters, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl_v2)) /
- sizeof(struct virtchnl_vlan_filter);
- len = sizeof(*vvfl_v2) +
- ((count - 1) *
- sizeof(struct virtchnl_vlan_filter));
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(vvfl_v2, filters,
+ --count);
more = true;
}
@@ -838,12 +830,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
- len = sizeof(*vvfl) + (count * sizeof(u16));
+ len = virtchnl_struct_size(vvfl, vlan_id, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
- sizeof(u16);
- len = sizeof(*vvfl) + (count * sizeof(u16));
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(vvfl, vlan_id,
+ --count);
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
@@ -884,16 +876,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
adapter->current_op = VIRTCHNL_OP_DEL_VLAN_V2;
- len = sizeof(*vvfl_v2) +
- ((count - 1) * sizeof(struct virtchnl_vlan_filter));
+ len = virtchnl_struct_size(vvfl_v2, filters, count);
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
- count = (IAVF_MAX_AQ_BUF_SIZE -
- sizeof(*vvfl_v2)) /
- sizeof(struct virtchnl_vlan_filter);
- len = sizeof(*vvfl_v2) +
- ((count - 1) *
- sizeof(struct virtchnl_vlan_filter));
+ while (len > IAVF_MAX_AQ_BUF_SIZE)
+ len = virtchnl_struct_size(vvfl_v2, filters,
+ --count);
more = true;
}
@@ -1085,8 +1073,7 @@ void iavf_set_rss_key(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
- len = sizeof(struct virtchnl_rss_key) +
- (adapter->rss_key_size * sizeof(u8)) - 1;
+ len = virtchnl_struct_size(vrk, key, adapter->rss_key_size);
vrk = kzalloc(len, GFP_KERNEL);
if (!vrk)
return;
@@ -1117,8 +1104,7 @@ void iavf_set_rss_lut(struct iavf_adapter *adapter)
adapter->current_op);
return;
}
- len = sizeof(struct virtchnl_rss_lut) +
- (adapter->rss_lut_size * sizeof(u8)) - 1;
+ len = virtchnl_struct_size(vrl, lut, adapter->rss_lut_size);
vrl = kzalloc(len, GFP_KERNEL);
if (!vrl)
return;
@@ -1499,7 +1485,7 @@ void iavf_enable_channels(struct iavf_adapter *adapter)
return;
}
- len = struct_size(vti, list, adapter->num_tc - 1);
+ len = virtchnl_struct_size(vti, list, adapter->num_tc);
vti = kzalloc(len, GFP_KERNEL);
if (!vti)
return;
@@ -2175,9 +2161,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
}
break;
case VIRTCHNL_OP_GET_VF_RESOURCES: {
- u16 len = sizeof(struct virtchnl_vf_resource) +
- IAVF_MAX_VF_VSI *
- sizeof(struct virtchnl_vsi_resource);
+ u16 len = IAVF_VIRTCHNL_VF_RESOURCE_SIZE;
+
memcpy(adapter->vf_res, msg, min(msglen, len));
iavf_validate_num_queues(adapter);
iavf_vf_parse_hw_config(&adapter->hw, adapter->vf_res);
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 817977e3039d..960277d78e09 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -47,5 +47,5 @@ ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
-ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o
+ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o ice_eswitch_br.o
ice-$(CONFIG_GNSS) += ice_gnss.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 4ba3d99439a0..5022b036ca4f 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -200,6 +200,8 @@ enum ice_feature {
ICE_F_PTP_EXTTS,
ICE_F_SMA_CTRL,
ICE_F_GNSS,
+ ICE_F_ROCE_LAG,
+ ICE_F_SRIOV_LAG,
ICE_F_MAX
};
@@ -370,6 +372,7 @@ struct ice_vsi {
u16 rx_buf_len;
struct ice_aqc_vsi_props info; /* VSI properties */
+ struct ice_vsi_vlan_info vlan_info; /* vlan config to be restored */
/* VSI stats */
struct rtnl_link_stats64 net_stats;
@@ -517,6 +520,7 @@ enum ice_misc_thread_tasks {
struct ice_switchdev_info {
struct ice_vsi *control_vsi;
struct ice_vsi *uplink_vsi;
+ struct ice_esw_br_offloads *br_offloads;
bool is_running;
};
@@ -567,6 +571,7 @@ struct ice_pf {
struct mutex sw_mutex; /* lock for protecting VSI alloc flow */
struct mutex tc_mutex; /* lock to protect TC changes */
struct mutex adev_mutex; /* lock to protect aux device access */
+ struct mutex lag_mutex; /* protect ice_lag struct in PF */
u32 msg_enable;
struct ice_ptp ptp;
struct gnss_serial *gnss_serial;
@@ -626,6 +631,7 @@ struct ice_pf {
struct ice_lag *lag; /* Link Aggregation information */
struct ice_switchdev_info switchdev;
+ struct ice_esw_br_port *br_port;
#define ICE_INVALID_AGG_NODE_ID 0
#define ICE_PF_AGG_NODE_ID_START 1
@@ -636,6 +642,8 @@ struct ice_pf {
struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
};
+extern struct workqueue_struct *ice_lag_wq;
+
struct ice_netdev_priv {
struct ice_vsi *vsi;
struct ice_repr *repr;
@@ -853,7 +861,7 @@ static inline bool ice_is_adq_active(struct ice_pf *pf)
return false;
}
-bool netif_is_ice(struct net_device *dev);
+bool netif_is_ice(const struct net_device *dev);
int ice_vsi_setup_tx_rings(struct ice_vsi *vsi);
int ice_vsi_setup_rx_rings(struct ice_vsi *vsi);
int ice_vsi_open_ctrl(struct ice_vsi *vsi);
@@ -909,8 +917,25 @@ void ice_fdir_release_flows(struct ice_hw *hw);
void ice_fdir_replay_flows(struct ice_hw *hw);
void ice_fdir_replay_fltrs(struct ice_pf *pf);
int ice_fdir_create_dflt_rules(struct ice_pf *pf);
-int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
- struct ice_rq_event_info *event);
+
+enum ice_aq_task_state {
+ ICE_AQ_TASK_NOT_PREPARED,
+ ICE_AQ_TASK_WAITING,
+ ICE_AQ_TASK_COMPLETE,
+ ICE_AQ_TASK_CANCELED,
+};
+
+struct ice_aq_task {
+ struct hlist_node entry;
+ struct ice_rq_event_info event;
+ enum ice_aq_task_state state;
+ u16 opcode;
+};
+
+void ice_aq_prep_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode);
+int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ unsigned long timeout);
int ice_open(struct net_device *netdev);
int ice_open_internal(struct net_device *netdev);
int ice_stop(struct net_device *netdev);
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 63d3e1dcbba5..29f7a9852aec 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -120,6 +120,9 @@ struct ice_aqc_list_caps_elem {
#define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076
#define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077
#define ICE_AQC_CAPS_NVM_MGMT 0x0080
+#define ICE_AQC_CAPS_FW_LAG_SUPPORT 0x0092
+#define ICE_AQC_BIT_ROCEV2_LAG 0x01
+#define ICE_AQC_BIT_SRIOV_LAG 0x02
u8 major_ver;
u8 minor_ver;
@@ -232,6 +235,8 @@ struct ice_aqc_set_port_params {
#define ICE_AQC_SET_P_PARAMS_DOUBLE_VLAN_ENA BIT(2)
__le16 bad_frame_vsi;
__le16 swid;
+#define ICE_AQC_PORT_SWID_VALID BIT(15)
+#define ICE_AQC_PORT_SWID_M 0xFF
u8 reserved[10];
};
@@ -241,10 +246,12 @@ struct ice_aqc_set_port_params {
* Allocate Resources command (indirect 0x0208)
* Free Resources command (indirect 0x0209)
* Get Allocated Resource Descriptors Command (indirect 0x020A)
+ * Share Resource command (indirect 0x020B)
*/
#define ICE_AQC_RES_TYPE_VSI_LIST_REP 0x03
#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04
#define ICE_AQC_RES_TYPE_RECIPE 0x05
+#define ICE_AQC_RES_TYPE_SWID 0x07
#define ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK 0x21
#define ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES 0x22
#define ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES 0x23
@@ -264,6 +271,7 @@ struct ice_aqc_set_port_params {
/* Allocate Resources command (indirect 0x0208)
* Free Resources command (indirect 0x0209)
+ * Share Resource command (indirect 0x020B)
*/
struct ice_aqc_alloc_free_res_cmd {
__le16 num_entries; /* Number of Resource entries */
@@ -818,7 +826,11 @@ struct ice_aqc_txsched_move_grp_info_hdr {
__le32 src_parent_teid;
__le32 dest_parent_teid;
__le16 num_elems;
- __le16 reserved;
+ u8 mode;
+#define ICE_AQC_MOVE_ELEM_MODE_SAME_PF 0x0
+#define ICE_AQC_MOVE_ELEM_MODE_GIVE_OWN 0x1
+#define ICE_AQC_MOVE_ELEM_MODE_KEEP_OWN 0x2
+ u8 reserved;
};
struct ice_aqc_move_elem {
@@ -1392,6 +1404,7 @@ struct ice_aqc_get_link_topo {
struct ice_aqc_link_topo_addr addr;
u8 node_part_num;
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21
+#define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31
u8 rsvd[9];
};
@@ -1781,11 +1794,10 @@ struct ice_aqc_lldp_filter_ctrl {
u8 reserved2[12];
};
+#define ICE_AQC_RSS_VSI_VALID BIT(15)
+
/* Get/Set RSS key (indirect 0x0B04/0x0B02) */
struct ice_aqc_get_set_rss_key {
-#define ICE_AQC_GSET_RSS_KEY_VSI_VALID BIT(15)
-#define ICE_AQC_GSET_RSS_KEY_VSI_ID_S 0
-#define ICE_AQC_GSET_RSS_KEY_VSI_ID_M (0x3FF << ICE_AQC_GSET_RSS_KEY_VSI_ID_S)
__le16 vsi_id;
u8 reserved[6];
__le32 addr_high;
@@ -1803,35 +1815,33 @@ struct ice_aqc_get_set_rss_keys {
u8 extended_hash_key[ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE];
};
-/* Get/Set RSS LUT (indirect 0x0B05/0x0B03) */
-struct ice_aqc_get_set_rss_lut {
-#define ICE_AQC_GSET_RSS_LUT_VSI_VALID BIT(15)
-#define ICE_AQC_GSET_RSS_LUT_VSI_ID_S 0
-#define ICE_AQC_GSET_RSS_LUT_VSI_ID_M (0x3FF << ICE_AQC_GSET_RSS_LUT_VSI_ID_S)
- __le16 vsi_id;
-#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S 0
-#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M \
- (0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S)
-
-#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI 0
-#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF 1
-#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL 2
+enum ice_lut_type {
+ ICE_LUT_VSI = 0,
+ ICE_LUT_PF = 1,
+ ICE_LUT_GLOBAL = 2,
+};
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S 2
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M \
- (0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S)
+enum ice_lut_size {
+ ICE_LUT_VSI_SIZE = 64,
+ ICE_LUT_GLOBAL_SIZE = 512,
+ ICE_LUT_PF_SIZE = 2048,
+};
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128 128
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG 0
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512 512
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG 1
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K 2048
-#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG 2
+/* enum ice_aqc_lut_flags combines constants used to fill
+ * &ice_aqc_get_set_rss_lut ::flags, which is an amalgamation of global LUT ID,
+ * LUT size and LUT type, last of which does not need neither shift nor mask.
+ */
+enum ice_aqc_lut_flags {
+ ICE_AQC_LUT_SIZE_SMALL = 0, /* size = 64 or 128 */
+ ICE_AQC_LUT_SIZE_512 = BIT(2),
+ ICE_AQC_LUT_SIZE_2K = BIT(3),
-#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S 4
-#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M \
- (0xF << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S)
+ ICE_AQC_LUT_GLOBAL_IDX = GENMASK(7, 4),
+};
+/* Get/Set RSS LUT (indirect 0x0B05/0x0B03) */
+struct ice_aqc_get_set_rss_lut {
+ __le16 vsi_id;
__le16 flags;
__le32 reserved;
__le32 addr_high;
@@ -1923,6 +1933,42 @@ struct ice_aqc_dis_txq_item {
__le16 q_id[];
} __packed;
+/* Move/Reconfigure Tx queue (indirect 0x0C32) */
+struct ice_aqc_cfg_txqs {
+ u8 cmd_type;
+#define ICE_AQC_Q_CFG_MOVE_NODE 0x1
+#define ICE_AQC_Q_CFG_TC_CHNG 0x2
+#define ICE_AQC_Q_CFG_MOVE_TC_CHNG 0x3
+#define ICE_AQC_Q_CFG_SUBSEQ_CALL BIT(2)
+#define ICE_AQC_Q_CFG_FLUSH BIT(3)
+ u8 num_qs;
+ u8 port_num_chng;
+#define ICE_AQC_Q_CFG_SRC_PRT_M 0x7
+#define ICE_AQC_Q_CFG_DST_PRT_S 3
+#define ICE_AQC_Q_CFG_DST_PRT_M (0x7 << ICE_AQC_Q_CFG_DST_PRT_S)
+ u8 time_out;
+#define ICE_AQC_Q_CFG_TIMEOUT_S 2
+#define ICE_AQC_Q_CFG_TIMEOUT_M (0x1F << ICE_AQC_Q_CFG_TIMEOUT_S)
+ __le32 blocked_cgds;
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+/* Per Q struct for Move/Reconfigure Tx LAN Queues (indirect 0x0C32) */
+struct ice_aqc_cfg_txq_perq {
+ __le16 q_handle;
+ u8 tc;
+ u8 rsvd;
+ __le32 q_teid;
+};
+
+/* The buffer for Move/Reconfigure Tx LAN Queues (indirect 0x0C32) */
+struct ice_aqc_cfg_txqs_buf {
+ __le32 src_parent_teid;
+ __le32 dst_parent_teid;
+ struct ice_aqc_cfg_txq_perq queue_info[];
+};
+
/* Add Tx RDMA Queue Set (indirect 0x0C33) */
struct ice_aqc_add_rdma_qset {
u8 num_qset_grps;
@@ -2181,6 +2227,7 @@ struct ice_aq_desc {
struct ice_aqc_neigh_dev_req neigh_dev;
struct ice_aqc_add_txqs add_txqs;
struct ice_aqc_dis_txqs dis_txqs;
+ struct ice_aqc_cfg_txqs cfg_txqs;
struct ice_aqc_add_rdma_qset add_rdma_qset;
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
@@ -2263,6 +2310,7 @@ enum ice_adminq_opc {
/* Alloc/Free/Get Resources */
ice_aqc_opc_alloc_res = 0x0208,
ice_aqc_opc_free_res = 0x0209,
+ ice_aqc_opc_share_res = 0x020B,
ice_aqc_opc_set_vlan_mode_parameters = 0x020C,
ice_aqc_opc_get_vlan_mode_parameters = 0x020D,
@@ -2356,6 +2404,7 @@ enum ice_adminq_opc {
/* Tx queue handling commands/events */
ice_aqc_opc_add_txqs = 0x0C30,
ice_aqc_opc_dis_txqs = 0x0C31,
+ ice_aqc_opc_cfg_txqs = 0x0C32,
ice_aqc_opc_add_rdma_qset = 0x0C33,
/* package commands */
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index b678bdf96f3a..7fa43827a3f0 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -408,7 +408,6 @@ static unsigned int ice_rx_offset(struct ice_rx_ring *rx_ring)
*/
static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
{
- int chain_len = ICE_MAX_CHAINED_RX_BUFS;
struct ice_vsi *vsi = ring->vsi;
u32 rxdid = ICE_RXDID_FLEX_NIC;
struct ice_rlan_ctx rlan_ctx;
@@ -435,7 +434,8 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
/* Receive Packet Data Buffer Size.
* The Packet Data Buffer Size is defined in 128 byte units.
*/
- rlan_ctx.dbuf = ring->rx_buf_len >> ICE_RLAN_CTX_DBUF_S;
+ rlan_ctx.dbuf = DIV_ROUND_UP(ring->rx_buf_len,
+ BIT_ULL(ICE_RLAN_CTX_DBUF_S));
/* use 32 byte descriptors */
rlan_ctx.dsize = 1;
@@ -472,17 +472,11 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
*/
rlan_ctx.showiv = 0;
- /* For AF_XDP ZC, we disallow packets to span on
- * multiple buffers, thus letting us skip that
- * handling in the fast-path.
- */
- if (ring->xsk_pool)
- chain_len = 1;
/* Max packet size for this queue - must not be set to a larger value
* than 5 x DBUF
*/
rlan_ctx.rxmax = min_t(u32, vsi->max_frame,
- chain_len * ring->rx_buf_len);
+ ICE_MAX_CHAINED_RX_BUFS * ring->rx_buf_len);
/* Rx queue threshold in units of 64 */
rlan_ctx.lrxqthresh = 1;
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index e16d4c83ed5f..80deca45ab59 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -5,6 +5,7 @@
#include "ice_sched.h"
#include "ice_adminq_cmd.h"
#include "ice_flow.h"
+#include "ice_ptp_hw.h"
#define ICE_PF_RESET_WAIT_COUNT 300
@@ -1999,37 +2000,31 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
/**
* ice_aq_alloc_free_res - command to allocate/free resources
* @hw: pointer to the HW struct
- * @num_entries: number of resource entries in buffer
* @buf: Indirect buffer to hold data parameters and response
* @buf_size: size of buffer for indirect commands
* @opc: pass in the command opcode
- * @cd: pointer to command details structure or NULL
*
* Helper function to allocate/free resources using the admin queue commands
*/
-int
-ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
- struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
- enum ice_adminq_opc opc, struct ice_sq_cd *cd)
+int ice_aq_alloc_free_res(struct ice_hw *hw,
+ struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
+ enum ice_adminq_opc opc)
{
struct ice_aqc_alloc_free_res_cmd *cmd;
struct ice_aq_desc desc;
cmd = &desc.params.sw_res_ctrl;
- if (!buf)
- return -EINVAL;
-
- if (buf_size < flex_array_size(buf, elem, num_entries))
+ if (!buf || buf_size < flex_array_size(buf, elem, 1))
return -EINVAL;
ice_fill_dflt_direct_cmd_desc(&desc, opc);
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
- cmd->num_entries = cpu_to_le16(num_entries);
+ cmd->num_entries = cpu_to_le16(1);
- return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
+ return ice_aq_send_cmd(hw, &desc, buf, buf_size, NULL);
}
/**
@@ -2059,8 +2054,7 @@ ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)
if (btm)
buf->res_type |= cpu_to_le16(ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM);
- status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
- ice_aqc_opc_alloc_res, NULL);
+ status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
if (status)
goto ice_alloc_res_exit;
@@ -2094,8 +2088,7 @@ int ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res)
buf->res_type = cpu_to_le16(type);
memcpy(buf->elem, res, sizeof(*buf->elem) * num);
- status = ice_aq_alloc_free_res(hw, num, buf, buf_len,
- ice_aqc_opc_free_res, NULL);
+ status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
if (status)
ice_debug(hw, ICE_DBG_SW, "CQ CMD Buffer:\n");
@@ -2241,6 +2234,14 @@ ice_parse_common_caps(struct ice_hw *hw, struct ice_hw_common_caps *caps,
"%s: reset_restrict_support = %d\n", prefix,
caps->reset_restrict_support);
break;
+ case ICE_AQC_CAPS_FW_LAG_SUPPORT:
+ caps->roce_lag = !!(number & ICE_AQC_BIT_ROCEV2_LAG);
+ ice_debug(hw, ICE_DBG_INIT, "%s: roce_lag = %u\n",
+ prefix, caps->roce_lag);
+ caps->sriov_lag = !!(number & ICE_AQC_BIT_SRIOV_LAG);
+ ice_debug(hw, ICE_DBG_INIT, "%s: sriov_lag = %u\n",
+ prefix, caps->sriov_lag);
+ break;
default:
/* Not one of the recognized common capabilities */
found = false;
@@ -2654,6 +2655,67 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
}
/**
+ * ice_aq_get_netlist_node
+ * @hw: pointer to the hw struct
+ * @cmd: get_link_topo AQ structure
+ * @node_part_number: output node part number if node found
+ * @node_handle: output node handle parameter if node found
+ */
+static int
+ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd,
+ u8 *node_part_number, u16 *node_handle)
+{
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
+ desc.params.get_link_topo = *cmd;
+
+ if (ice_aq_send_cmd(hw, &desc, NULL, 0, NULL))
+ return -EIO;
+
+ if (node_handle)
+ *node_handle = le16_to_cpu(desc.params.get_link_topo.addr.handle);
+ if (node_part_number)
+ *node_part_number = desc.params.get_link_topo.node_part_num;
+
+ return 0;
+}
+
+/**
+ * ice_is_pf_c827 - check if pf contains c827 phy
+ * @hw: pointer to the hw struct
+ */
+bool ice_is_pf_c827(struct ice_hw *hw)
+{
+ struct ice_aqc_get_link_topo cmd = {};
+ u8 node_part_number;
+ u16 node_handle;
+ int status;
+
+ if (hw->mac_type != ICE_MAC_E810)
+ return false;
+
+ if (hw->device_id != ICE_DEV_ID_E810C_QSFP)
+ return true;
+
+ cmd.addr.topo_params.node_type_ctx =
+ FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY) |
+ FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ICE_AQC_LINK_TOPO_NODE_CTX_PORT);
+ cmd.addr.topo_params.index = 0;
+
+ status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number,
+ &node_handle);
+
+ if (status || node_part_number != ICE_AQC_GET_LINK_TOPO_NODE_NR_C827)
+ return false;
+
+ if (node_handle == E810C_QSFP_C827_0_HANDLE || node_handle == E810C_QSFP_C827_1_HANDLE)
+ return true;
+
+ return false;
+}
+
+/**
* ice_aq_list_caps - query function/device capabilities
* @hw: pointer to the HW struct
* @buf: a buffer to hold the capabilities
@@ -3869,6 +3931,34 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
return status;
}
+static enum ice_lut_size ice_lut_type_to_size(enum ice_lut_type type)
+{
+ switch (type) {
+ case ICE_LUT_VSI:
+ return ICE_LUT_VSI_SIZE;
+ case ICE_LUT_GLOBAL:
+ return ICE_LUT_GLOBAL_SIZE;
+ case ICE_LUT_PF:
+ return ICE_LUT_PF_SIZE;
+ }
+ WARN_ONCE(1, "incorrect type passed");
+ return ICE_LUT_VSI_SIZE;
+}
+
+static enum ice_aqc_lut_flags ice_lut_size_to_flag(enum ice_lut_size size)
+{
+ switch (size) {
+ case ICE_LUT_VSI_SIZE:
+ return ICE_AQC_LUT_SIZE_SMALL;
+ case ICE_LUT_GLOBAL_SIZE:
+ return ICE_AQC_LUT_SIZE_512;
+ case ICE_LUT_PF_SIZE:
+ return ICE_AQC_LUT_SIZE_2K;
+ }
+ WARN_ONCE(1, "incorrect size passed");
+ return 0;
+}
+
/**
* __ice_aq_get_set_rss_lut
* @hw: pointer to the hardware structure
@@ -3878,95 +3968,44 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
* Internal function to get (0x0B05) or set (0x0B03) RSS look up table
*/
static int
-__ice_aq_get_set_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *params, bool set)
-{
- u16 flags = 0, vsi_id, lut_type, lut_size, glob_lut_idx, vsi_handle;
- struct ice_aqc_get_set_rss_lut *cmd_resp;
+__ice_aq_get_set_rss_lut(struct ice_hw *hw,
+ struct ice_aq_get_set_rss_lut_params *params, bool set)
+{
+ u16 opcode, vsi_id, vsi_handle = params->vsi_handle, glob_lut_idx = 0;
+ enum ice_lut_type lut_type = params->lut_type;
+ struct ice_aqc_get_set_rss_lut *desc_params;
+ enum ice_aqc_lut_flags flags;
+ enum ice_lut_size lut_size;
struct ice_aq_desc desc;
- int status;
- u8 *lut;
+ u8 *lut = params->lut;
- if (!params)
- return -EINVAL;
-
- vsi_handle = params->vsi_handle;
- lut = params->lut;
- if (!ice_is_vsi_valid(hw, vsi_handle) || !lut)
+ if (!lut || !ice_is_vsi_valid(hw, vsi_handle))
return -EINVAL;
- lut_size = params->lut_size;
- lut_type = params->lut_type;
- glob_lut_idx = params->global_lut_id;
- vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
-
- cmd_resp = &desc.params.get_set_rss_lut;
+ lut_size = ice_lut_type_to_size(lut_type);
+ if (lut_size > params->lut_size)
+ return -EINVAL;
+ else if (set && lut_size != params->lut_size)
+ return -EINVAL;
- if (set) {
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_lut);
+ opcode = set ? ice_aqc_opc_set_rss_lut : ice_aqc_opc_get_rss_lut;
+ ice_fill_dflt_direct_cmd_desc(&desc, opcode);
+ if (set)
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
- } else {
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_lut);
- }
-
- cmd_resp->vsi_id = cpu_to_le16(((vsi_id <<
- ICE_AQC_GSET_RSS_LUT_VSI_ID_S) &
- ICE_AQC_GSET_RSS_LUT_VSI_ID_M) |
- ICE_AQC_GSET_RSS_LUT_VSI_VALID);
-
- switch (lut_type) {
- case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI:
- case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF:
- case ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL:
- flags |= ((lut_type << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S) &
- ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M);
- break;
- default:
- status = -EINVAL;
- goto ice_aq_get_set_rss_lut_exit;
- }
-
- if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL) {
- flags |= ((glob_lut_idx << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S) &
- ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M);
- if (!set)
- goto ice_aq_get_set_rss_lut_send;
- } else if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF) {
- if (!set)
- goto ice_aq_get_set_rss_lut_send;
- } else {
- goto ice_aq_get_set_rss_lut_send;
- }
+ desc_params = &desc.params.get_set_rss_lut;
+ vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
+ desc_params->vsi_id = cpu_to_le16(vsi_id | ICE_AQC_RSS_VSI_VALID);
- /* LUT size is only valid for Global and PF table types */
- switch (lut_size) {
- case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128:
- break;
- case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512:
- flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG <<
- ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &
- ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;
- break;
- case ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K:
- if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF) {
- flags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG <<
- ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &
- ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;
- break;
- }
- fallthrough;
- default:
- status = -EINVAL;
- goto ice_aq_get_set_rss_lut_exit;
- }
+ if (lut_type == ICE_LUT_GLOBAL)
+ glob_lut_idx = FIELD_PREP(ICE_AQC_LUT_GLOBAL_IDX,
+ params->global_lut_id);
-ice_aq_get_set_rss_lut_send:
- cmd_resp->flags = cpu_to_le16(flags);
- status = ice_aq_send_cmd(hw, &desc, lut, lut_size, NULL);
+ flags = lut_type | glob_lut_idx | ice_lut_size_to_flag(lut_size);
+ desc_params->flags = cpu_to_le16(flags);
-ice_aq_get_set_rss_lut_exit:
- return status;
+ return ice_aq_send_cmd(hw, &desc, lut, lut_size, NULL);
}
/**
@@ -4008,12 +4047,10 @@ static int
__ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id,
struct ice_aqc_get_set_rss_keys *key, bool set)
{
- struct ice_aqc_get_set_rss_key *cmd_resp;
+ struct ice_aqc_get_set_rss_key *desc_params;
u16 key_size = sizeof(*key);
struct ice_aq_desc desc;
- cmd_resp = &desc.params.get_set_rss_key;
-
if (set) {
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_key);
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
@@ -4021,10 +4058,8 @@ __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id,
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_key);
}
- cmd_resp->vsi_id = cpu_to_le16(((vsi_id <<
- ICE_AQC_GSET_RSS_KEY_VSI_ID_S) &
- ICE_AQC_GSET_RSS_KEY_VSI_ID_M) |
- ICE_AQC_GSET_RSS_KEY_VSI_VALID);
+ desc_params = &desc.params.get_set_rss_key;
+ desc_params->vsi_id = cpu_to_le16(vsi_id | ICE_AQC_RSS_VSI_VALID);
return ice_aq_send_cmd(hw, &desc, key, key_size, NULL);
}
@@ -4222,6 +4257,53 @@ do_aq:
}
/**
+ * ice_aq_cfg_lan_txq
+ * @hw: pointer to the hardware structure
+ * @buf: buffer for command
+ * @buf_size: size of buffer in bytes
+ * @num_qs: number of queues being configured
+ * @oldport: origination lport
+ * @newport: destination lport
+ * @cd: pointer to command details structure or NULL
+ *
+ * Move/Configure LAN Tx queue (0x0C32)
+ *
+ * There is a better AQ command to use for moving nodes, so only coding
+ * this one for configuring the node.
+ */
+int
+ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf,
+ u16 buf_size, u16 num_qs, u8 oldport, u8 newport,
+ struct ice_sq_cd *cd)
+{
+ struct ice_aqc_cfg_txqs *cmd;
+ struct ice_aq_desc desc;
+ int status;
+
+ cmd = &desc.params.cfg_txqs;
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_cfg_txqs);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ if (!buf)
+ return -EINVAL;
+
+ cmd->cmd_type = ICE_AQC_Q_CFG_TC_CHNG;
+ cmd->num_qs = num_qs;
+ cmd->port_num_chng = (oldport & ICE_AQC_Q_CFG_SRC_PRT_M);
+ cmd->port_num_chng |= (newport << ICE_AQC_Q_CFG_DST_PRT_S) &
+ ICE_AQC_Q_CFG_DST_PRT_M;
+ cmd->time_out = (5 << ICE_AQC_Q_CFG_TIMEOUT_S) &
+ ICE_AQC_Q_CFG_TIMEOUT_M;
+ cmd->blocked_cgds = 0;
+
+ status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
+ if (status)
+ ice_debug(hw, ICE_DBG_SCHED, "Failed to reconfigure nodes %d\n",
+ hw->adminq.sq_last_status);
+ return status;
+}
+
+/**
* ice_aq_add_rdma_qsets
* @hw: pointer to the hardware structure
* @num_qset_grps: Number of RDMA Qset groups
@@ -4700,6 +4782,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
break;
ice_free_sched_node(pi, node);
q_ctx->q_handle = ICE_INVAL_Q_HANDLE;
+ q_ctx->q_teid = ICE_INVAL_TEID;
}
mutex_unlock(&pi->sched_lock);
kfree(qg_list);
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 81961a7d6598..226b81f97a92 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -38,10 +38,9 @@ int
ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res);
int
ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res);
-int
-ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
- struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
- enum ice_adminq_opc opc, struct ice_sq_cd *cd);
+int ice_aq_alloc_free_res(struct ice_hw *hw,
+ struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
+ enum ice_adminq_opc opc);
bool ice_is_sbq_supported(struct ice_hw *hw);
struct ice_ctl_q_info *ice_get_sbq(struct ice_hw *hw);
int
@@ -93,6 +92,7 @@ int
ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
struct ice_aqc_get_phy_caps_data *caps,
struct ice_sq_cd *cd);
+bool ice_is_pf_c827(struct ice_hw *hw);
int
ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count,
enum ice_adminq_opc opc, struct ice_sq_cd *cd);
@@ -186,6 +186,10 @@ int
ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle,
u8 num_qgrps, struct ice_aqc_add_tx_qgrp *buf, u16 buf_size,
struct ice_sq_cd *cd);
+int
+ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf,
+ u16 buf_size, u16 num_qs, u8 oldport, u8 newport,
+ struct ice_sq_cd *cd);
int ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle);
void ice_replay_post(struct ice_hw *hw);
void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf);
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
index 3eb01731e496..e1fbc6de452d 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
@@ -70,6 +70,11 @@ static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets)
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return -EINVAL;
+ }
+
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
mutex_lock(&pf->tc_mutex);
@@ -170,6 +175,11 @@ static u8 ice_dcbnl_setdcbx(struct net_device *netdev, u8 mode)
if (mode == pf->dcbx_cap)
return ICE_DCB_NO_HW_CHG;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return ICE_DCB_NO_HW_CHG;
+ }
+
qos_cfg = &pf->hw.port_info->qos_cfg;
/* DSCP configuration is not DCBx negotiated */
@@ -261,6 +271,11 @@ static int ice_dcbnl_setpfc(struct net_device *netdev, struct ieee_pfc *pfc)
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return -EINVAL;
+ }
+
mutex_lock(&pf->tc_mutex);
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
@@ -323,6 +338,11 @@ static void ice_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, u8 set)
if (prio >= ICE_MAX_USER_PRIORITY)
return;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return;
+ }
+
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
new_cfg->pfc.pfccap = pf->hw.func_caps.common_cap.maxtc;
@@ -379,6 +399,11 @@ static u8 ice_dcbnl_setstate(struct net_device *netdev, u8 state)
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return ICE_DCB_NO_HW_CHG;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return ICE_DCB_NO_HW_CHG;
+ }
+
/* Nothing to do */
if (!!state == test_bit(ICE_FLAG_DCB_ENA, pf->flags))
return ICE_DCB_NO_HW_CHG;
@@ -451,6 +476,11 @@ ice_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
if (tc >= ICE_MAX_TRAFFIC_CLASS)
return;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return;
+ }
+
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
/* prio_type, bwg_id and bw_pct per UP are not supported */
@@ -505,6 +535,11 @@ ice_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 bw_pct)
if (pgid >= ICE_MAX_TRAFFIC_CLASS)
return;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return;
+ }
+
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
new_cfg->etscfg.tcbwtable[pgid] = bw_pct;
@@ -725,6 +760,11 @@ static int ice_dcbnl_setapp(struct net_device *netdev, struct dcb_app *app)
return -EINVAL;
}
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return -EINVAL;
+ }
+
max_tc = pf->hw.func_caps.common_cap.maxtc;
if (app->priority >= max_tc) {
netdev_err(netdev, "TC %d out of range, max TC %d\n",
@@ -836,6 +876,11 @@ static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app)
return -EINVAL;
}
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return -EINVAL;
+ }
+
mutex_lock(&pf->tc_mutex);
old_cfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
@@ -937,6 +982,11 @@ static u8 ice_dcbnl_cee_set_all(struct net_device *netdev)
!(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return ICE_DCB_NO_HW_CHG;
+ if (pf->lag && pf->lag->bonded) {
+ netdev_err(netdev, "DCB changes not allowed when in a bond\n");
+ return ICE_DCB_NO_HW_CHG;
+ }
+
new_cfg = &pf->hw.port_info->qos_cfg.desired_dcbx_cfg;
mutex_lock(&pf->tc_mutex);
diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c
index d71ed210f9c4..b27ec93638b6 100644
--- a/drivers/net/ethernet/intel/ice/ice_ddp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ddp.c
@@ -30,7 +30,7 @@ static const struct ice_tunnel_type_scan tnls[] = {
* Verifies various attributes of the package file, including length, format
* version, and the requirement of at least one segment.
*/
-enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
+static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
{
u32 seg_count;
u32 i;
@@ -118,7 +118,7 @@ static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
*
* This helper function validates a buffer's header.
*/
-struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
+static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf)
{
struct ice_buf_hdr *hdr;
u16 section_count;
@@ -1153,6 +1153,54 @@ static void ice_release_global_cfg_lock(struct ice_hw *hw)
}
/**
+ * ice_aq_download_pkg
+ * @hw: pointer to the hardware structure
+ * @pkg_buf: the package buffer to transfer
+ * @buf_size: the size of the package buffer
+ * @last_buf: last buffer indicator
+ * @error_offset: returns error offset
+ * @error_info: returns error information
+ * @cd: pointer to command details structure or NULL
+ *
+ * Download Package (0x0C40)
+ */
+static int
+ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
+ u16 buf_size, bool last_buf, u32 *error_offset,
+ u32 *error_info, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_download_pkg *cmd;
+ struct ice_aq_desc desc;
+ int status;
+
+ if (error_offset)
+ *error_offset = 0;
+ if (error_info)
+ *error_info = 0;
+
+ cmd = &desc.params.download_pkg;
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ if (last_buf)
+ cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
+
+ status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
+ if (status == -EIO) {
+ /* Read error from buffer only when the FW returned an error */
+ struct ice_aqc_download_pkg_resp *resp;
+
+ resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
+ if (error_offset)
+ *error_offset = le32_to_cpu(resp->error_offset);
+ if (error_info)
+ *error_info = le32_to_cpu(resp->error_info);
+ }
+
+ return status;
+}
+
+/**
* ice_dwnld_cfg_bufs
* @hw: pointer to the hardware structure
* @bufs: pointer to an array of buffers
@@ -1294,20 +1342,20 @@ static enum ice_ddp_state ice_download_pkg(struct ice_hw *hw,
}
/**
- * ice_aq_download_pkg
+ * ice_aq_update_pkg
* @hw: pointer to the hardware structure
- * @pkg_buf: the package buffer to transfer
- * @buf_size: the size of the package buffer
+ * @pkg_buf: the package cmd buffer
+ * @buf_size: the size of the package cmd buffer
* @last_buf: last buffer indicator
* @error_offset: returns error offset
* @error_info: returns error information
* @cd: pointer to command details structure or NULL
*
- * Download Package (0x0C40)
+ * Update Package (0x0C42)
*/
-int ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
- u16 buf_size, bool last_buf, u32 *error_offset,
- u32 *error_info, struct ice_sq_cd *cd)
+static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
+ u16 buf_size, bool last_buf, u32 *error_offset,
+ u32 *error_info, struct ice_sq_cd *cd)
{
struct ice_aqc_download_pkg *cmd;
struct ice_aq_desc desc;
@@ -1319,7 +1367,7 @@ int ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
*error_info = 0;
cmd = &desc.params.download_pkg;
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_download_pkg);
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
if (last_buf)
@@ -1361,53 +1409,6 @@ int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
}
/**
- * ice_aq_update_pkg
- * @hw: pointer to the hardware structure
- * @pkg_buf: the package cmd buffer
- * @buf_size: the size of the package cmd buffer
- * @last_buf: last buffer indicator
- * @error_offset: returns error offset
- * @error_info: returns error information
- * @cd: pointer to command details structure or NULL
- *
- * Update Package (0x0C42)
- */
-static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
- u16 buf_size, bool last_buf, u32 *error_offset,
- u32 *error_info, struct ice_sq_cd *cd)
-{
- struct ice_aqc_download_pkg *cmd;
- struct ice_aq_desc desc;
- int status;
-
- if (error_offset)
- *error_offset = 0;
- if (error_info)
- *error_info = 0;
-
- cmd = &desc.params.download_pkg;
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_update_pkg);
- desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
-
- if (last_buf)
- cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF;
-
- status = ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
- if (status == -EIO) {
- /* Read error from buffer only when the FW returned an error */
- struct ice_aqc_download_pkg_resp *resp;
-
- resp = (struct ice_aqc_download_pkg_resp *)pkg_buf;
- if (error_offset)
- *error_offset = le32_to_cpu(resp->error_offset);
- if (error_info)
- *error_info = le32_to_cpu(resp->error_info);
- }
-
- return status;
-}
-
-/**
* ice_update_pkg_no_lock
* @hw: pointer to the hardware structure
* @bufs: pointer to an array of buffers
@@ -1470,8 +1471,9 @@ int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
* success it returns a pointer to the segment header, otherwise it will
* return NULL.
*/
-struct ice_generic_seg_hdr *ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
- struct ice_pkg_hdr *pkg_hdr)
+static struct ice_generic_seg_hdr *
+ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
+ struct ice_pkg_hdr *pkg_hdr)
{
u32 i;
diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.h b/drivers/net/ethernet/intel/ice/ice_ddp.h
index 41acfe26df1c..abb5f32f2ef4 100644
--- a/drivers/net/ethernet/intel/ice/ice_ddp.h
+++ b/drivers/net/ethernet/intel/ice/ice_ddp.h
@@ -416,21 +416,13 @@ struct ice_pkg_enum {
void *(*handler)(u32 sect_type, void *section, u32 index, u32 *offset);
};
-int ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
- u16 buf_size, bool last_buf, u32 *error_offset,
- u32 *error_info, struct ice_sq_cd *cd);
int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
u16 buf_size, struct ice_sq_cd *cd);
void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size);
-enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len);
-
struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw);
-struct ice_generic_seg_hdr *ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
- struct ice_pkg_hdr *pkg_hdr);
-
int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count);
int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count);
@@ -439,6 +431,4 @@ u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld);
void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
u32 sect_type);
-struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf);
-
#endif
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index 8f232c41a89e..a655d499abfa 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -4,6 +4,7 @@
#include "ice.h"
#include "ice_lib.h"
#include "ice_eswitch.h"
+#include "ice_eswitch_br.h"
#include "ice_fltr.h"
#include "ice_repr.h"
#include "ice_devlink.h"
@@ -83,10 +84,6 @@ static int ice_eswitch_setup_env(struct ice_pf *pf)
struct ice_vsi_vlan_ops *vlan_ops;
bool rule_added = false;
- vlan_ops = ice_get_compat_vsi_vlan_ops(ctrl_vsi);
- if (vlan_ops->dis_stripping(ctrl_vsi))
- return -ENODEV;
-
ice_remove_vsi_fltr(&pf->hw, uplink_vsi->idx);
netif_addr_lock_bh(uplink_netdev);
@@ -103,17 +100,28 @@ static int ice_eswitch_setup_env(struct ice_pf *pf)
rule_added = true;
}
+ vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi);
+ if (vlan_ops->dis_rx_filtering(uplink_vsi))
+ goto err_dis_rx;
+
if (ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_set_allow_override))
goto err_override_uplink;
if (ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_set_allow_override))
goto err_override_control;
+ if (ice_vsi_update_local_lb(uplink_vsi, true))
+ goto err_override_local_lb;
+
return 0;
+err_override_local_lb:
+ ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_clear_allow_override);
err_override_control:
ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_clear_allow_override);
err_override_uplink:
+ vlan_ops->ena_rx_filtering(uplink_vsi);
+err_dis_rx:
if (rule_added)
ice_clear_dflt_vsi(uplink_vsi);
err_def_rx:
@@ -306,6 +314,9 @@ void ice_eswitch_update_repr(struct ice_vsi *vsi)
repr->src_vsi = vsi;
repr->dst->u.port_info.port_id = vsi->vsi_num;
+ if (repr->br_port)
+ repr->br_port->vsi = vsi;
+
ret = ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof);
if (ret) {
ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI);
@@ -331,6 +342,9 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev)
np = netdev_priv(netdev);
vsi = np->vsi;
+ if (!vsi || !ice_is_switchdev_running(vsi->back))
+ return NETDEV_TX_BUSY;
+
if (ice_is_reset_in_progress(vsi->back->state) ||
test_bit(ICE_VF_DIS, vsi->back->state))
return NETDEV_TX_BUSY;
@@ -378,9 +392,14 @@ static void ice_eswitch_release_env(struct ice_pf *pf)
{
struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi;
struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
+ struct ice_vsi_vlan_ops *vlan_ops;
+ vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi);
+
+ ice_vsi_update_local_lb(uplink_vsi, false);
ice_vsi_update_security(ctrl_vsi, ice_vsi_ctx_clear_allow_override);
ice_vsi_update_security(uplink_vsi, ice_vsi_ctx_clear_allow_override);
+ vlan_ops->ena_rx_filtering(uplink_vsi);
ice_clear_dflt_vsi(uplink_vsi);
ice_fltr_add_mac_and_broadcast(uplink_vsi,
uplink_vsi->port_info->mac.perm_addr,
@@ -455,16 +474,24 @@ static void ice_eswitch_napi_disable(struct ice_pf *pf)
*/
static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
{
- struct ice_vsi *ctrl_vsi;
+ struct ice_vsi *ctrl_vsi, *uplink_vsi;
+
+ uplink_vsi = ice_get_main_vsi(pf);
+ if (!uplink_vsi)
+ return -ENODEV;
+
+ if (netif_is_any_bridge_port(uplink_vsi->netdev)) {
+ dev_err(ice_pf_to_dev(pf),
+ "Uplink port cannot be a bridge port\n");
+ return -EINVAL;
+ }
pf->switchdev.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info);
if (!pf->switchdev.control_vsi)
return -ENODEV;
ctrl_vsi = pf->switchdev.control_vsi;
- pf->switchdev.uplink_vsi = ice_get_main_vsi(pf);
- if (!pf->switchdev.uplink_vsi)
- goto err_vsi;
+ pf->switchdev.uplink_vsi = uplink_vsi;
if (ice_eswitch_setup_env(pf))
goto err_vsi;
@@ -480,10 +507,15 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
if (ice_vsi_open(ctrl_vsi))
goto err_setup_reprs;
+ if (ice_eswitch_br_offloads_init(pf))
+ goto err_br_offloads;
+
ice_eswitch_napi_enable(pf);
return 0;
+err_br_offloads:
+ ice_vsi_close(ctrl_vsi);
err_setup_reprs:
ice_repr_rem_from_all_vfs(pf);
err_repr_add:
@@ -502,8 +534,8 @@ static void ice_eswitch_disable_switchdev(struct ice_pf *pf)
struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
ice_eswitch_napi_disable(pf);
+ ice_eswitch_br_offloads_deinit(pf);
ice_eswitch_release_env(pf);
- ice_rem_adv_rule_for_vsi(&pf->hw, ctrl_vsi->idx);
ice_eswitch_release_reprs(pf, ctrl_vsi);
ice_vsi_release(ctrl_vsi);
ice_repr_rem_from_all_vfs(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
new file mode 100644
index 000000000000..67bfd1f61cdd
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
@@ -0,0 +1,1346 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_eswitch_br.h"
+#include "ice_repr.h"
+#include "ice_switch.h"
+#include "ice_vlan.h"
+#include "ice_vf_vsi_vlan_ops.h"
+#include "ice_trace.h"
+
+#define ICE_ESW_BRIDGE_UPDATE_INTERVAL msecs_to_jiffies(1000)
+
+static const struct rhashtable_params ice_fdb_ht_params = {
+ .key_offset = offsetof(struct ice_esw_br_fdb_entry, data),
+ .key_len = sizeof(struct ice_esw_br_fdb_data),
+ .head_offset = offsetof(struct ice_esw_br_fdb_entry, ht_node),
+ .automatic_shrinking = true,
+};
+
+static bool ice_eswitch_br_is_dev_valid(const struct net_device *dev)
+{
+ /* Accept only PF netdev, PRs and LAG */
+ return ice_is_port_repr_netdev(dev) || netif_is_ice(dev) ||
+ netif_is_lag_master(dev);
+}
+
+static struct net_device *
+ice_eswitch_br_get_uplink_from_lag(struct net_device *lag_dev)
+{
+ struct net_device *lower;
+ struct list_head *iter;
+
+ netdev_for_each_lower_dev(lag_dev, lower, iter) {
+ if (netif_is_ice(lower))
+ return lower;
+ }
+
+ return NULL;
+}
+
+static struct ice_esw_br_port *
+ice_eswitch_br_netdev_to_port(struct net_device *dev)
+{
+ if (ice_is_port_repr_netdev(dev)) {
+ struct ice_repr *repr = ice_netdev_to_repr(dev);
+
+ return repr->br_port;
+ } else if (netif_is_ice(dev) || netif_is_lag_master(dev)) {
+ struct net_device *ice_dev;
+ struct ice_pf *pf;
+
+ if (netif_is_lag_master(dev))
+ ice_dev = ice_eswitch_br_get_uplink_from_lag(dev);
+ else
+ ice_dev = dev;
+
+ if (!ice_dev)
+ return NULL;
+
+ pf = ice_netdev_to_pf(ice_dev);
+
+ return pf->br_port;
+ }
+
+ return NULL;
+}
+
+static void
+ice_eswitch_br_ingress_rule_setup(struct ice_adv_rule_info *rule_info,
+ u8 pf_id, u16 vf_vsi_idx)
+{
+ rule_info->sw_act.vsi_handle = vf_vsi_idx;
+ rule_info->sw_act.flag |= ICE_FLTR_RX;
+ rule_info->sw_act.src = pf_id;
+ rule_info->priority = 5;
+}
+
+static void
+ice_eswitch_br_egress_rule_setup(struct ice_adv_rule_info *rule_info,
+ u16 pf_vsi_idx)
+{
+ rule_info->sw_act.vsi_handle = pf_vsi_idx;
+ rule_info->sw_act.flag |= ICE_FLTR_TX;
+ rule_info->flags_info.act = ICE_SINGLE_ACT_LAN_ENABLE;
+ rule_info->flags_info.act_valid = true;
+ rule_info->priority = 5;
+}
+
+static int
+ice_eswitch_br_rule_delete(struct ice_hw *hw, struct ice_rule_query_data *rule)
+{
+ int err;
+
+ if (!rule)
+ return -EINVAL;
+
+ err = ice_rem_adv_rule_by_id(hw, rule);
+ kfree(rule);
+
+ return err;
+}
+
+static u16
+ice_eswitch_br_get_lkups_cnt(u16 vid)
+{
+ return ice_eswitch_br_is_vid_valid(vid) ? 2 : 1;
+}
+
+static void
+ice_eswitch_br_add_vlan_lkup(struct ice_adv_lkup_elem *list, u16 vid)
+{
+ if (ice_eswitch_br_is_vid_valid(vid)) {
+ list[1].type = ICE_VLAN_OFOS;
+ list[1].h_u.vlan_hdr.vlan = cpu_to_be16(vid & VLAN_VID_MASK);
+ list[1].m_u.vlan_hdr.vlan = cpu_to_be16(0xFFFF);
+ }
+}
+
+static struct ice_rule_query_data *
+ice_eswitch_br_fwd_rule_create(struct ice_hw *hw, int vsi_idx, int port_type,
+ const unsigned char *mac, u16 vid)
+{
+ struct ice_adv_rule_info rule_info = { 0 };
+ struct ice_rule_query_data *rule;
+ struct ice_adv_lkup_elem *list;
+ u16 lkups_cnt;
+ int err;
+
+ lkups_cnt = ice_eswitch_br_get_lkups_cnt(vid);
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule)
+ return ERR_PTR(-ENOMEM);
+
+ list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ if (!list) {
+ err = -ENOMEM;
+ goto err_list_alloc;
+ }
+
+ switch (port_type) {
+ case ICE_ESWITCH_BR_UPLINK_PORT:
+ ice_eswitch_br_egress_rule_setup(&rule_info, vsi_idx);
+ break;
+ case ICE_ESWITCH_BR_VF_REPR_PORT:
+ ice_eswitch_br_ingress_rule_setup(&rule_info, hw->pf_id,
+ vsi_idx);
+ break;
+ default:
+ err = -EINVAL;
+ goto err_add_rule;
+ }
+
+ list[0].type = ICE_MAC_OFOS;
+ ether_addr_copy(list[0].h_u.eth_hdr.dst_addr, mac);
+ eth_broadcast_addr(list[0].m_u.eth_hdr.dst_addr);
+
+ ice_eswitch_br_add_vlan_lkup(list, vid);
+
+ rule_info.need_pass_l2 = true;
+
+ rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI;
+
+ err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, rule);
+ if (err)
+ goto err_add_rule;
+
+ kfree(list);
+
+ return rule;
+
+err_add_rule:
+ kfree(list);
+err_list_alloc:
+ kfree(rule);
+
+ return ERR_PTR(err);
+}
+
+static struct ice_rule_query_data *
+ice_eswitch_br_guard_rule_create(struct ice_hw *hw, u16 vsi_idx,
+ const unsigned char *mac, u16 vid)
+{
+ struct ice_adv_rule_info rule_info = { 0 };
+ struct ice_rule_query_data *rule;
+ struct ice_adv_lkup_elem *list;
+ int err = -ENOMEM;
+ u16 lkups_cnt;
+
+ lkups_cnt = ice_eswitch_br_get_lkups_cnt(vid);
+
+ rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+ if (!rule)
+ goto err_exit;
+
+ list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
+ if (!list)
+ goto err_list_alloc;
+
+ list[0].type = ICE_MAC_OFOS;
+ ether_addr_copy(list[0].h_u.eth_hdr.src_addr, mac);
+ eth_broadcast_addr(list[0].m_u.eth_hdr.src_addr);
+
+ ice_eswitch_br_add_vlan_lkup(list, vid);
+
+ rule_info.allow_pass_l2 = true;
+ rule_info.sw_act.vsi_handle = vsi_idx;
+ rule_info.sw_act.fltr_act = ICE_NOP;
+ rule_info.priority = 5;
+
+ err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, rule);
+ if (err)
+ goto err_add_rule;
+
+ kfree(list);
+
+ return rule;
+
+err_add_rule:
+ kfree(list);
+err_list_alloc:
+ kfree(rule);
+err_exit:
+ return ERR_PTR(err);
+}
+
+static struct ice_esw_br_flow *
+ice_eswitch_br_flow_create(struct device *dev, struct ice_hw *hw, int vsi_idx,
+ int port_type, const unsigned char *mac, u16 vid)
+{
+ struct ice_rule_query_data *fwd_rule, *guard_rule;
+ struct ice_esw_br_flow *flow;
+ int err;
+
+ flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+ if (!flow)
+ return ERR_PTR(-ENOMEM);
+
+ fwd_rule = ice_eswitch_br_fwd_rule_create(hw, vsi_idx, port_type, mac,
+ vid);
+ err = PTR_ERR_OR_ZERO(fwd_rule);
+ if (err) {
+ dev_err(dev, "Failed to create eswitch bridge %sgress forward rule, err: %d\n",
+ port_type == ICE_ESWITCH_BR_UPLINK_PORT ? "e" : "in",
+ err);
+ goto err_fwd_rule;
+ }
+
+ guard_rule = ice_eswitch_br_guard_rule_create(hw, vsi_idx, mac, vid);
+ err = PTR_ERR_OR_ZERO(guard_rule);
+ if (err) {
+ dev_err(dev, "Failed to create eswitch bridge %sgress guard rule, err: %d\n",
+ port_type == ICE_ESWITCH_BR_UPLINK_PORT ? "e" : "in",
+ err);
+ goto err_guard_rule;
+ }
+
+ flow->fwd_rule = fwd_rule;
+ flow->guard_rule = guard_rule;
+
+ return flow;
+
+err_guard_rule:
+ ice_eswitch_br_rule_delete(hw, fwd_rule);
+err_fwd_rule:
+ kfree(flow);
+
+ return ERR_PTR(err);
+}
+
+static struct ice_esw_br_fdb_entry *
+ice_eswitch_br_fdb_find(struct ice_esw_br *bridge, const unsigned char *mac,
+ u16 vid)
+{
+ struct ice_esw_br_fdb_data data = {
+ .vid = vid,
+ };
+
+ ether_addr_copy(data.addr, mac);
+ return rhashtable_lookup_fast(&bridge->fdb_ht, &data,
+ ice_fdb_ht_params);
+}
+
+static void
+ice_eswitch_br_flow_delete(struct ice_pf *pf, struct ice_esw_br_flow *flow)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ int err;
+
+ err = ice_eswitch_br_rule_delete(&pf->hw, flow->fwd_rule);
+ if (err)
+ dev_err(dev, "Failed to delete FDB forward rule, err: %d\n",
+ err);
+
+ err = ice_eswitch_br_rule_delete(&pf->hw, flow->guard_rule);
+ if (err)
+ dev_err(dev, "Failed to delete FDB guard rule, err: %d\n",
+ err);
+
+ kfree(flow);
+}
+
+static struct ice_esw_br_vlan *
+ice_esw_br_port_vlan_lookup(struct ice_esw_br *bridge, u16 vsi_idx, u16 vid)
+{
+ struct ice_pf *pf = bridge->br_offloads->pf;
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_esw_br_port *port;
+ struct ice_esw_br_vlan *vlan;
+
+ port = xa_load(&bridge->ports, vsi_idx);
+ if (!port) {
+ dev_info(dev, "Bridge port lookup failed (vsi=%u)\n", vsi_idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ vlan = xa_load(&port->vlans, vid);
+ if (!vlan) {
+ dev_info(dev, "Bridge port vlan metadata lookup failed (vsi=%u)\n",
+ vsi_idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return vlan;
+}
+
+static void
+ice_eswitch_br_fdb_entry_delete(struct ice_esw_br *bridge,
+ struct ice_esw_br_fdb_entry *fdb_entry)
+{
+ struct ice_pf *pf = bridge->br_offloads->pf;
+
+ rhashtable_remove_fast(&bridge->fdb_ht, &fdb_entry->ht_node,
+ ice_fdb_ht_params);
+ list_del(&fdb_entry->list);
+
+ ice_eswitch_br_flow_delete(pf, fdb_entry->flow);
+
+ kfree(fdb_entry);
+}
+
+static void
+ice_eswitch_br_fdb_offload_notify(struct net_device *dev,
+ const unsigned char *mac, u16 vid,
+ unsigned long val)
+{
+ struct switchdev_notifier_fdb_info fdb_info = {
+ .addr = mac,
+ .vid = vid,
+ .offloaded = true,
+ };
+
+ call_switchdev_notifiers(val, dev, &fdb_info.info, NULL);
+}
+
+static void
+ice_eswitch_br_fdb_entry_notify_and_cleanup(struct ice_esw_br *bridge,
+ struct ice_esw_br_fdb_entry *entry)
+{
+ if (!(entry->flags & ICE_ESWITCH_BR_FDB_ADDED_BY_USER))
+ ice_eswitch_br_fdb_offload_notify(entry->dev, entry->data.addr,
+ entry->data.vid,
+ SWITCHDEV_FDB_DEL_TO_BRIDGE);
+ ice_eswitch_br_fdb_entry_delete(bridge, entry);
+}
+
+static void
+ice_eswitch_br_fdb_entry_find_and_delete(struct ice_esw_br *bridge,
+ const unsigned char *mac, u16 vid)
+{
+ struct ice_pf *pf = bridge->br_offloads->pf;
+ struct ice_esw_br_fdb_entry *fdb_entry;
+ struct device *dev = ice_pf_to_dev(pf);
+
+ fdb_entry = ice_eswitch_br_fdb_find(bridge, mac, vid);
+ if (!fdb_entry) {
+ dev_err(dev, "FDB entry with mac: %pM and vid: %u not found\n",
+ mac, vid);
+ return;
+ }
+
+ trace_ice_eswitch_br_fdb_entry_find_and_delete(fdb_entry);
+ ice_eswitch_br_fdb_entry_notify_and_cleanup(bridge, fdb_entry);
+}
+
+static void
+ice_eswitch_br_fdb_entry_create(struct net_device *netdev,
+ struct ice_esw_br_port *br_port,
+ bool added_by_user,
+ const unsigned char *mac, u16 vid)
+{
+ struct ice_esw_br *bridge = br_port->bridge;
+ struct ice_pf *pf = bridge->br_offloads->pf;
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_esw_br_fdb_entry *fdb_entry;
+ struct ice_esw_br_flow *flow;
+ struct ice_esw_br_vlan *vlan;
+ struct ice_hw *hw = &pf->hw;
+ unsigned long event;
+ int err;
+
+ /* untagged filtering is not yet supported */
+ if (!(bridge->flags & ICE_ESWITCH_BR_VLAN_FILTERING) && vid)
+ return;
+
+ if ((bridge->flags & ICE_ESWITCH_BR_VLAN_FILTERING)) {
+ vlan = ice_esw_br_port_vlan_lookup(bridge, br_port->vsi_idx,
+ vid);
+ if (IS_ERR(vlan)) {
+ dev_err(dev, "Failed to find vlan lookup, err: %ld\n",
+ PTR_ERR(vlan));
+ return;
+ }
+ }
+
+ fdb_entry = ice_eswitch_br_fdb_find(bridge, mac, vid);
+ if (fdb_entry)
+ ice_eswitch_br_fdb_entry_notify_and_cleanup(bridge, fdb_entry);
+
+ fdb_entry = kzalloc(sizeof(*fdb_entry), GFP_KERNEL);
+ if (!fdb_entry) {
+ err = -ENOMEM;
+ goto err_exit;
+ }
+
+ flow = ice_eswitch_br_flow_create(dev, hw, br_port->vsi_idx,
+ br_port->type, mac, vid);
+ if (IS_ERR(flow)) {
+ err = PTR_ERR(flow);
+ goto err_add_flow;
+ }
+
+ ether_addr_copy(fdb_entry->data.addr, mac);
+ fdb_entry->data.vid = vid;
+ fdb_entry->br_port = br_port;
+ fdb_entry->flow = flow;
+ fdb_entry->dev = netdev;
+ fdb_entry->last_use = jiffies;
+ event = SWITCHDEV_FDB_ADD_TO_BRIDGE;
+
+ if (added_by_user) {
+ fdb_entry->flags |= ICE_ESWITCH_BR_FDB_ADDED_BY_USER;
+ event = SWITCHDEV_FDB_OFFLOADED;
+ }
+
+ err = rhashtable_insert_fast(&bridge->fdb_ht, &fdb_entry->ht_node,
+ ice_fdb_ht_params);
+ if (err)
+ goto err_fdb_insert;
+
+ list_add(&fdb_entry->list, &bridge->fdb_list);
+ trace_ice_eswitch_br_fdb_entry_create(fdb_entry);
+
+ ice_eswitch_br_fdb_offload_notify(netdev, mac, vid, event);
+
+ return;
+
+err_fdb_insert:
+ ice_eswitch_br_flow_delete(pf, flow);
+err_add_flow:
+ kfree(fdb_entry);
+err_exit:
+ dev_err(dev, "Failed to create fdb entry, err: %d\n", err);
+}
+
+static void
+ice_eswitch_br_fdb_work_dealloc(struct ice_esw_br_fdb_work *fdb_work)
+{
+ kfree(fdb_work->fdb_info.addr);
+ kfree(fdb_work);
+}
+
+static void
+ice_eswitch_br_fdb_event_work(struct work_struct *work)
+{
+ struct ice_esw_br_fdb_work *fdb_work = ice_work_to_fdb_work(work);
+ bool added_by_user = fdb_work->fdb_info.added_by_user;
+ const unsigned char *mac = fdb_work->fdb_info.addr;
+ u16 vid = fdb_work->fdb_info.vid;
+ struct ice_esw_br_port *br_port;
+
+ rtnl_lock();
+
+ br_port = ice_eswitch_br_netdev_to_port(fdb_work->dev);
+ if (!br_port)
+ goto err_exit;
+
+ switch (fdb_work->event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ ice_eswitch_br_fdb_entry_create(fdb_work->dev, br_port,
+ added_by_user, mac, vid);
+ break;
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ ice_eswitch_br_fdb_entry_find_and_delete(br_port->bridge,
+ mac, vid);
+ break;
+ default:
+ goto err_exit;
+ }
+
+err_exit:
+ rtnl_unlock();
+ dev_put(fdb_work->dev);
+ ice_eswitch_br_fdb_work_dealloc(fdb_work);
+}
+
+static struct ice_esw_br_fdb_work *
+ice_eswitch_br_fdb_work_alloc(struct switchdev_notifier_fdb_info *fdb_info,
+ struct net_device *dev,
+ unsigned long event)
+{
+ struct ice_esw_br_fdb_work *work;
+ unsigned char *mac;
+
+ work = kzalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_WORK(&work->work, ice_eswitch_br_fdb_event_work);
+ memcpy(&work->fdb_info, fdb_info, sizeof(work->fdb_info));
+
+ mac = kzalloc(ETH_ALEN, GFP_ATOMIC);
+ if (!mac) {
+ kfree(work);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ether_addr_copy(mac, fdb_info->addr);
+ work->fdb_info.addr = mac;
+ work->event = event;
+ work->dev = dev;
+
+ return work;
+}
+
+static int
+ice_eswitch_br_switchdev_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct switchdev_notifier_info *info = ptr;
+ struct ice_esw_br_offloads *br_offloads;
+ struct ice_esw_br_fdb_work *work;
+ struct netlink_ext_ack *extack;
+ struct net_device *upper;
+
+ br_offloads = ice_nb_to_br_offloads(nb, switchdev_nb);
+ extack = switchdev_notifier_info_to_extack(ptr);
+
+ upper = netdev_master_upper_dev_get_rcu(dev);
+ if (!upper)
+ return NOTIFY_DONE;
+
+ if (!netif_is_bridge_master(upper))
+ return NOTIFY_DONE;
+
+ if (!ice_eswitch_br_is_dev_valid(dev))
+ return NOTIFY_DONE;
+
+ if (!ice_eswitch_br_netdev_to_port(dev))
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ fdb_info = container_of(info, typeof(*fdb_info), info);
+
+ work = ice_eswitch_br_fdb_work_alloc(fdb_info, dev, event);
+ if (IS_ERR(work)) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to init switchdev fdb work");
+ return notifier_from_errno(PTR_ERR(work));
+ }
+ dev_hold(dev);
+
+ queue_work(br_offloads->wq, &work->work);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void ice_eswitch_br_fdb_flush(struct ice_esw_br *bridge)
+{
+ struct ice_esw_br_fdb_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list)
+ ice_eswitch_br_fdb_entry_notify_and_cleanup(bridge, entry);
+}
+
+static void
+ice_eswitch_br_vlan_filtering_set(struct ice_esw_br *bridge, bool enable)
+{
+ if (enable == !!(bridge->flags & ICE_ESWITCH_BR_VLAN_FILTERING))
+ return;
+
+ ice_eswitch_br_fdb_flush(bridge);
+ if (enable)
+ bridge->flags |= ICE_ESWITCH_BR_VLAN_FILTERING;
+ else
+ bridge->flags &= ~ICE_ESWITCH_BR_VLAN_FILTERING;
+}
+
+static void
+ice_eswitch_br_clear_pvid(struct ice_esw_br_port *port)
+{
+ struct ice_vlan port_vlan = ICE_VLAN(ETH_P_8021Q, port->pvid, 0);
+ struct ice_vsi_vlan_ops *vlan_ops;
+
+ vlan_ops = ice_get_compat_vsi_vlan_ops(port->vsi);
+
+ vlan_ops->del_vlan(port->vsi, &port_vlan);
+ vlan_ops->clear_port_vlan(port->vsi);
+
+ ice_vf_vsi_disable_port_vlan(port->vsi);
+
+ port->pvid = 0;
+}
+
+static void
+ice_eswitch_br_vlan_cleanup(struct ice_esw_br_port *port,
+ struct ice_esw_br_vlan *vlan)
+{
+ struct ice_esw_br_fdb_entry *fdb_entry, *tmp;
+ struct ice_esw_br *bridge = port->bridge;
+
+ trace_ice_eswitch_br_vlan_cleanup(vlan);
+
+ list_for_each_entry_safe(fdb_entry, tmp, &bridge->fdb_list, list) {
+ if (vlan->vid == fdb_entry->data.vid)
+ ice_eswitch_br_fdb_entry_delete(bridge, fdb_entry);
+ }
+
+ xa_erase(&port->vlans, vlan->vid);
+ if (port->pvid == vlan->vid)
+ ice_eswitch_br_clear_pvid(port);
+ kfree(vlan);
+}
+
+static void ice_eswitch_br_port_vlans_flush(struct ice_esw_br_port *port)
+{
+ struct ice_esw_br_vlan *vlan;
+ unsigned long index;
+
+ xa_for_each(&port->vlans, index, vlan)
+ ice_eswitch_br_vlan_cleanup(port, vlan);
+}
+
+static int
+ice_eswitch_br_set_pvid(struct ice_esw_br_port *port,
+ struct ice_esw_br_vlan *vlan)
+{
+ struct ice_vlan port_vlan = ICE_VLAN(ETH_P_8021Q, vlan->vid, 0);
+ struct device *dev = ice_pf_to_dev(port->vsi->back);
+ struct ice_vsi_vlan_ops *vlan_ops;
+ int err;
+
+ if (port->pvid == vlan->vid || vlan->vid == 1)
+ return 0;
+
+ /* Setting port vlan on uplink isn't supported by hw */
+ if (port->type == ICE_ESWITCH_BR_UPLINK_PORT)
+ return -EOPNOTSUPP;
+
+ if (port->pvid) {
+ dev_info(dev,
+ "Port VLAN (vsi=%u, vid=%u) already exists on the port, remove it before adding new one\n",
+ port->vsi_idx, port->pvid);
+ return -EEXIST;
+ }
+
+ ice_vf_vsi_enable_port_vlan(port->vsi);
+
+ vlan_ops = ice_get_compat_vsi_vlan_ops(port->vsi);
+ err = vlan_ops->set_port_vlan(port->vsi, &port_vlan);
+ if (err)
+ return err;
+
+ err = vlan_ops->add_vlan(port->vsi, &port_vlan);
+ if (err)
+ return err;
+
+ ice_eswitch_br_port_vlans_flush(port);
+ port->pvid = vlan->vid;
+
+ return 0;
+}
+
+static struct ice_esw_br_vlan *
+ice_eswitch_br_vlan_create(u16 vid, u16 flags, struct ice_esw_br_port *port)
+{
+ struct device *dev = ice_pf_to_dev(port->vsi->back);
+ struct ice_esw_br_vlan *vlan;
+ int err;
+
+ vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
+ if (!vlan)
+ return ERR_PTR(-ENOMEM);
+
+ vlan->vid = vid;
+ vlan->flags = flags;
+ if ((flags & BRIDGE_VLAN_INFO_PVID) &&
+ (flags & BRIDGE_VLAN_INFO_UNTAGGED)) {
+ err = ice_eswitch_br_set_pvid(port, vlan);
+ if (err)
+ goto err_set_pvid;
+ } else if ((flags & BRIDGE_VLAN_INFO_PVID) ||
+ (flags & BRIDGE_VLAN_INFO_UNTAGGED)) {
+ dev_info(dev, "VLAN push and pop are supported only simultaneously\n");
+ err = -EOPNOTSUPP;
+ goto err_set_pvid;
+ }
+
+ err = xa_insert(&port->vlans, vlan->vid, vlan, GFP_KERNEL);
+ if (err)
+ goto err_insert;
+
+ trace_ice_eswitch_br_vlan_create(vlan);
+
+ return vlan;
+
+err_insert:
+ if (port->pvid)
+ ice_eswitch_br_clear_pvid(port);
+err_set_pvid:
+ kfree(vlan);
+ return ERR_PTR(err);
+}
+
+static int
+ice_eswitch_br_port_vlan_add(struct ice_esw_br *bridge, u16 vsi_idx, u16 vid,
+ u16 flags, struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br_port *port;
+ struct ice_esw_br_vlan *vlan;
+
+ port = xa_load(&bridge->ports, vsi_idx);
+ if (!port)
+ return -EINVAL;
+
+ if (port->pvid) {
+ dev_info(ice_pf_to_dev(port->vsi->back),
+ "Port VLAN (vsi=%u, vid=%d) exists on the port, remove it to add trunk VLANs\n",
+ port->vsi_idx, port->pvid);
+ return -EEXIST;
+ }
+
+ vlan = xa_load(&port->vlans, vid);
+ if (vlan) {
+ if (vlan->flags == flags)
+ return 0;
+
+ ice_eswitch_br_vlan_cleanup(port, vlan);
+ }
+
+ vlan = ice_eswitch_br_vlan_create(vid, flags, port);
+ if (IS_ERR(vlan)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Failed to create VLAN entry, vid: %u, vsi: %u",
+ vid, vsi_idx);
+ return PTR_ERR(vlan);
+ }
+
+ return 0;
+}
+
+static void
+ice_eswitch_br_port_vlan_del(struct ice_esw_br *bridge, u16 vsi_idx, u16 vid)
+{
+ struct ice_esw_br_port *port;
+ struct ice_esw_br_vlan *vlan;
+
+ port = xa_load(&bridge->ports, vsi_idx);
+ if (!port)
+ return;
+
+ vlan = xa_load(&port->vlans, vid);
+ if (!vlan)
+ return;
+
+ ice_eswitch_br_vlan_cleanup(port, vlan);
+}
+
+static int
+ice_eswitch_br_port_obj_add(struct net_device *netdev, const void *ctx,
+ const struct switchdev_obj *obj,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br_port *br_port = ice_eswitch_br_netdev_to_port(netdev);
+ struct switchdev_obj_port_vlan *vlan;
+ int err;
+
+ if (!br_port)
+ return -EINVAL;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+ err = ice_eswitch_br_port_vlan_add(br_port->bridge,
+ br_port->vsi_idx, vlan->vid,
+ vlan->flags, extack);
+ return err;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ice_eswitch_br_port_obj_del(struct net_device *netdev, const void *ctx,
+ const struct switchdev_obj *obj)
+{
+ struct ice_esw_br_port *br_port = ice_eswitch_br_netdev_to_port(netdev);
+ struct switchdev_obj_port_vlan *vlan;
+
+ if (!br_port)
+ return -EINVAL;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+ ice_eswitch_br_port_vlan_del(br_port->bridge, br_port->vsi_idx,
+ vlan->vid);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ice_eswitch_br_port_obj_attr_set(struct net_device *netdev, const void *ctx,
+ const struct switchdev_attr *attr,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br_port *br_port = ice_eswitch_br_netdev_to_port(netdev);
+
+ if (!br_port)
+ return -EINVAL;
+
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+ ice_eswitch_br_vlan_filtering_set(br_port->bridge,
+ attr->u.vlan_filtering);
+ return 0;
+ case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+ br_port->bridge->ageing_time =
+ clock_t_to_jiffies(attr->u.ageing_time);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ice_eswitch_br_event_blocking(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ int err;
+
+ switch (event) {
+ case SWITCHDEV_PORT_OBJ_ADD:
+ err = switchdev_handle_port_obj_add(dev, ptr,
+ ice_eswitch_br_is_dev_valid,
+ ice_eswitch_br_port_obj_add);
+ break;
+ case SWITCHDEV_PORT_OBJ_DEL:
+ err = switchdev_handle_port_obj_del(dev, ptr,
+ ice_eswitch_br_is_dev_valid,
+ ice_eswitch_br_port_obj_del);
+ break;
+ case SWITCHDEV_PORT_ATTR_SET:
+ err = switchdev_handle_port_attr_set(dev, ptr,
+ ice_eswitch_br_is_dev_valid,
+ ice_eswitch_br_port_obj_attr_set);
+ break;
+ default:
+ err = 0;
+ }
+
+ return notifier_from_errno(err);
+}
+
+static void
+ice_eswitch_br_port_deinit(struct ice_esw_br *bridge,
+ struct ice_esw_br_port *br_port)
+{
+ struct ice_esw_br_fdb_entry *fdb_entry, *tmp;
+ struct ice_vsi *vsi = br_port->vsi;
+
+ list_for_each_entry_safe(fdb_entry, tmp, &bridge->fdb_list, list) {
+ if (br_port == fdb_entry->br_port)
+ ice_eswitch_br_fdb_entry_delete(bridge, fdb_entry);
+ }
+
+ if (br_port->type == ICE_ESWITCH_BR_UPLINK_PORT && vsi->back)
+ vsi->back->br_port = NULL;
+ else if (vsi->vf && vsi->vf->repr)
+ vsi->vf->repr->br_port = NULL;
+
+ xa_erase(&bridge->ports, br_port->vsi_idx);
+ ice_eswitch_br_port_vlans_flush(br_port);
+ kfree(br_port);
+}
+
+static struct ice_esw_br_port *
+ice_eswitch_br_port_init(struct ice_esw_br *bridge)
+{
+ struct ice_esw_br_port *br_port;
+
+ br_port = kzalloc(sizeof(*br_port), GFP_KERNEL);
+ if (!br_port)
+ return ERR_PTR(-ENOMEM);
+
+ xa_init(&br_port->vlans);
+
+ br_port->bridge = bridge;
+
+ return br_port;
+}
+
+static int
+ice_eswitch_br_vf_repr_port_init(struct ice_esw_br *bridge,
+ struct ice_repr *repr)
+{
+ struct ice_esw_br_port *br_port;
+ int err;
+
+ br_port = ice_eswitch_br_port_init(bridge);
+ if (IS_ERR(br_port))
+ return PTR_ERR(br_port);
+
+ br_port->vsi = repr->src_vsi;
+ br_port->vsi_idx = br_port->vsi->idx;
+ br_port->type = ICE_ESWITCH_BR_VF_REPR_PORT;
+ repr->br_port = br_port;
+
+ err = xa_insert(&bridge->ports, br_port->vsi_idx, br_port, GFP_KERNEL);
+ if (err) {
+ ice_eswitch_br_port_deinit(bridge, br_port);
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+ice_eswitch_br_uplink_port_init(struct ice_esw_br *bridge, struct ice_pf *pf)
+{
+ struct ice_vsi *vsi = pf->switchdev.uplink_vsi;
+ struct ice_esw_br_port *br_port;
+ int err;
+
+ br_port = ice_eswitch_br_port_init(bridge);
+ if (IS_ERR(br_port))
+ return PTR_ERR(br_port);
+
+ br_port->vsi = vsi;
+ br_port->vsi_idx = br_port->vsi->idx;
+ br_port->type = ICE_ESWITCH_BR_UPLINK_PORT;
+ pf->br_port = br_port;
+
+ err = xa_insert(&bridge->ports, br_port->vsi_idx, br_port, GFP_KERNEL);
+ if (err) {
+ ice_eswitch_br_port_deinit(bridge, br_port);
+ return err;
+ }
+
+ return 0;
+}
+
+static void
+ice_eswitch_br_ports_flush(struct ice_esw_br *bridge)
+{
+ struct ice_esw_br_port *port;
+ unsigned long i;
+
+ xa_for_each(&bridge->ports, i, port)
+ ice_eswitch_br_port_deinit(bridge, port);
+}
+
+static void
+ice_eswitch_br_deinit(struct ice_esw_br_offloads *br_offloads,
+ struct ice_esw_br *bridge)
+{
+ if (!bridge)
+ return;
+
+ /* Cleanup all the ports that were added asynchronously
+ * through NETDEV_CHANGEUPPER event.
+ */
+ ice_eswitch_br_ports_flush(bridge);
+ WARN_ON(!xa_empty(&bridge->ports));
+ xa_destroy(&bridge->ports);
+ rhashtable_destroy(&bridge->fdb_ht);
+
+ br_offloads->bridge = NULL;
+ kfree(bridge);
+}
+
+static struct ice_esw_br *
+ice_eswitch_br_init(struct ice_esw_br_offloads *br_offloads, int ifindex)
+{
+ struct ice_esw_br *bridge;
+ int err;
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return ERR_PTR(-ENOMEM);
+
+ err = rhashtable_init(&bridge->fdb_ht, &ice_fdb_ht_params);
+ if (err) {
+ kfree(bridge);
+ return ERR_PTR(err);
+ }
+
+ INIT_LIST_HEAD(&bridge->fdb_list);
+ bridge->br_offloads = br_offloads;
+ bridge->ifindex = ifindex;
+ bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME);
+ xa_init(&bridge->ports);
+ br_offloads->bridge = bridge;
+
+ return bridge;
+}
+
+static struct ice_esw_br *
+ice_eswitch_br_get(struct ice_esw_br_offloads *br_offloads, int ifindex,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br *bridge = br_offloads->bridge;
+
+ if (bridge) {
+ if (bridge->ifindex != ifindex) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only one bridge is supported per eswitch");
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ return bridge;
+ }
+
+ /* Create the bridge if it doesn't exist yet */
+ bridge = ice_eswitch_br_init(br_offloads, ifindex);
+ if (IS_ERR(bridge))
+ NL_SET_ERR_MSG_MOD(extack, "Failed to init the bridge");
+
+ return bridge;
+}
+
+static void
+ice_eswitch_br_verify_deinit(struct ice_esw_br_offloads *br_offloads,
+ struct ice_esw_br *bridge)
+{
+ /* Remove the bridge if it exists and there are no ports left */
+ if (!bridge || !xa_empty(&bridge->ports))
+ return;
+
+ ice_eswitch_br_deinit(br_offloads, bridge);
+}
+
+static int
+ice_eswitch_br_port_unlink(struct ice_esw_br_offloads *br_offloads,
+ struct net_device *dev, int ifindex,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br_port *br_port = ice_eswitch_br_netdev_to_port(dev);
+ struct ice_esw_br *bridge;
+
+ if (!br_port) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Port representor is not attached to any bridge");
+ return -EINVAL;
+ }
+
+ if (br_port->bridge->ifindex != ifindex) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Port representor is attached to another bridge");
+ return -EINVAL;
+ }
+
+ bridge = br_port->bridge;
+
+ trace_ice_eswitch_br_port_unlink(br_port);
+ ice_eswitch_br_port_deinit(br_port->bridge, br_port);
+ ice_eswitch_br_verify_deinit(br_offloads, bridge);
+
+ return 0;
+}
+
+static int
+ice_eswitch_br_port_link(struct ice_esw_br_offloads *br_offloads,
+ struct net_device *dev, int ifindex,
+ struct netlink_ext_ack *extack)
+{
+ struct ice_esw_br *bridge;
+ int err;
+
+ if (ice_eswitch_br_netdev_to_port(dev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Port is already attached to the bridge");
+ return -EINVAL;
+ }
+
+ bridge = ice_eswitch_br_get(br_offloads, ifindex, extack);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
+
+ if (ice_is_port_repr_netdev(dev)) {
+ struct ice_repr *repr = ice_netdev_to_repr(dev);
+
+ err = ice_eswitch_br_vf_repr_port_init(bridge, repr);
+ trace_ice_eswitch_br_port_link(repr->br_port);
+ } else {
+ struct net_device *ice_dev;
+ struct ice_pf *pf;
+
+ if (netif_is_lag_master(dev))
+ ice_dev = ice_eswitch_br_get_uplink_from_lag(dev);
+ else
+ ice_dev = dev;
+
+ if (!ice_dev)
+ return 0;
+
+ pf = ice_netdev_to_pf(ice_dev);
+
+ err = ice_eswitch_br_uplink_port_init(bridge, pf);
+ trace_ice_eswitch_br_port_link(pf->br_port);
+ }
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to init bridge port");
+ goto err_port_init;
+ }
+
+ return 0;
+
+err_port_init:
+ ice_eswitch_br_verify_deinit(br_offloads, bridge);
+ return err;
+}
+
+static int
+ice_eswitch_br_port_changeupper(struct notifier_block *nb, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct ice_esw_br_offloads *br_offloads;
+ struct netlink_ext_ack *extack;
+ struct net_device *upper;
+
+ br_offloads = ice_nb_to_br_offloads(nb, netdev_nb);
+
+ if (!ice_eswitch_br_is_dev_valid(dev))
+ return 0;
+
+ upper = info->upper_dev;
+ if (!netif_is_bridge_master(upper))
+ return 0;
+
+ extack = netdev_notifier_info_to_extack(&info->info);
+
+ if (info->linking)
+ return ice_eswitch_br_port_link(br_offloads, dev,
+ upper->ifindex, extack);
+ else
+ return ice_eswitch_br_port_unlink(br_offloads, dev,
+ upper->ifindex, extack);
+}
+
+static int
+ice_eswitch_br_port_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ int err = 0;
+
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ err = ice_eswitch_br_port_changeupper(nb, ptr);
+ break;
+ }
+
+ return notifier_from_errno(err);
+}
+
+static void
+ice_eswitch_br_offloads_dealloc(struct ice_pf *pf)
+{
+ struct ice_esw_br_offloads *br_offloads = pf->switchdev.br_offloads;
+
+ ASSERT_RTNL();
+
+ if (!br_offloads)
+ return;
+
+ ice_eswitch_br_deinit(br_offloads, br_offloads->bridge);
+
+ pf->switchdev.br_offloads = NULL;
+ kfree(br_offloads);
+}
+
+static struct ice_esw_br_offloads *
+ice_eswitch_br_offloads_alloc(struct ice_pf *pf)
+{
+ struct ice_esw_br_offloads *br_offloads;
+
+ ASSERT_RTNL();
+
+ if (pf->switchdev.br_offloads)
+ return ERR_PTR(-EEXIST);
+
+ br_offloads = kzalloc(sizeof(*br_offloads), GFP_KERNEL);
+ if (!br_offloads)
+ return ERR_PTR(-ENOMEM);
+
+ pf->switchdev.br_offloads = br_offloads;
+ br_offloads->pf = pf;
+
+ return br_offloads;
+}
+
+void
+ice_eswitch_br_offloads_deinit(struct ice_pf *pf)
+{
+ struct ice_esw_br_offloads *br_offloads;
+
+ br_offloads = pf->switchdev.br_offloads;
+ if (!br_offloads)
+ return;
+
+ cancel_delayed_work_sync(&br_offloads->update_work);
+ unregister_netdevice_notifier(&br_offloads->netdev_nb);
+ unregister_switchdev_blocking_notifier(&br_offloads->switchdev_blk);
+ unregister_switchdev_notifier(&br_offloads->switchdev_nb);
+ destroy_workqueue(br_offloads->wq);
+ /* Although notifier block is unregistered just before,
+ * so we don't get any new events, some events might be
+ * already in progress. Hold the rtnl lock and wait for
+ * them to finished.
+ */
+ rtnl_lock();
+ ice_eswitch_br_offloads_dealloc(pf);
+ rtnl_unlock();
+}
+
+static void ice_eswitch_br_update(struct ice_esw_br_offloads *br_offloads)
+{
+ struct ice_esw_br *bridge = br_offloads->bridge;
+ struct ice_esw_br_fdb_entry *entry, *tmp;
+
+ if (!bridge)
+ return;
+
+ rtnl_lock();
+ list_for_each_entry_safe(entry, tmp, &bridge->fdb_list, list) {
+ if (entry->flags & ICE_ESWITCH_BR_FDB_ADDED_BY_USER)
+ continue;
+
+ if (time_is_after_eq_jiffies(entry->last_use +
+ bridge->ageing_time))
+ continue;
+
+ ice_eswitch_br_fdb_entry_notify_and_cleanup(bridge, entry);
+ }
+ rtnl_unlock();
+}
+
+static void ice_eswitch_br_update_work(struct work_struct *work)
+{
+ struct ice_esw_br_offloads *br_offloads;
+
+ br_offloads = ice_work_to_br_offloads(work);
+
+ ice_eswitch_br_update(br_offloads);
+
+ queue_delayed_work(br_offloads->wq, &br_offloads->update_work,
+ ICE_ESW_BRIDGE_UPDATE_INTERVAL);
+}
+
+int
+ice_eswitch_br_offloads_init(struct ice_pf *pf)
+{
+ struct ice_esw_br_offloads *br_offloads;
+ struct device *dev = ice_pf_to_dev(pf);
+ int err;
+
+ rtnl_lock();
+ br_offloads = ice_eswitch_br_offloads_alloc(pf);
+ rtnl_unlock();
+ if (IS_ERR(br_offloads)) {
+ dev_err(dev, "Failed to init eswitch bridge\n");
+ return PTR_ERR(br_offloads);
+ }
+
+ br_offloads->wq = alloc_ordered_workqueue("ice_bridge_wq", 0);
+ if (!br_offloads->wq) {
+ err = -ENOMEM;
+ dev_err(dev, "Failed to allocate bridge workqueue\n");
+ goto err_alloc_wq;
+ }
+
+ br_offloads->switchdev_nb.notifier_call =
+ ice_eswitch_br_switchdev_event;
+ err = register_switchdev_notifier(&br_offloads->switchdev_nb);
+ if (err) {
+ dev_err(dev,
+ "Failed to register switchdev notifier\n");
+ goto err_reg_switchdev_nb;
+ }
+
+ br_offloads->switchdev_blk.notifier_call =
+ ice_eswitch_br_event_blocking;
+ err = register_switchdev_blocking_notifier(&br_offloads->switchdev_blk);
+ if (err) {
+ dev_err(dev,
+ "Failed to register bridge blocking switchdev notifier\n");
+ goto err_reg_switchdev_blk;
+ }
+
+ br_offloads->netdev_nb.notifier_call = ice_eswitch_br_port_event;
+ err = register_netdevice_notifier(&br_offloads->netdev_nb);
+ if (err) {
+ dev_err(dev,
+ "Failed to register bridge port event notifier\n");
+ goto err_reg_netdev_nb;
+ }
+
+ INIT_DELAYED_WORK(&br_offloads->update_work,
+ ice_eswitch_br_update_work);
+ queue_delayed_work(br_offloads->wq, &br_offloads->update_work,
+ ICE_ESW_BRIDGE_UPDATE_INTERVAL);
+
+ return 0;
+
+err_reg_netdev_nb:
+ unregister_switchdev_blocking_notifier(&br_offloads->switchdev_blk);
+err_reg_switchdev_blk:
+ unregister_switchdev_notifier(&br_offloads->switchdev_nb);
+err_reg_switchdev_nb:
+ destroy_workqueue(br_offloads->wq);
+err_alloc_wq:
+ rtnl_lock();
+ ice_eswitch_br_offloads_dealloc(pf);
+ rtnl_unlock();
+
+ return err;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.h b/drivers/net/ethernet/intel/ice/ice_eswitch_br.h
new file mode 100644
index 000000000000..85a8fadb2928
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2023, Intel Corporation. */
+
+#ifndef _ICE_ESWITCH_BR_H_
+#define _ICE_ESWITCH_BR_H_
+
+#include <linux/rhashtable.h>
+#include <linux/workqueue.h>
+
+struct ice_esw_br_fdb_data {
+ unsigned char addr[ETH_ALEN];
+ u16 vid;
+};
+
+struct ice_esw_br_flow {
+ struct ice_rule_query_data *fwd_rule;
+ struct ice_rule_query_data *guard_rule;
+};
+
+enum {
+ ICE_ESWITCH_BR_FDB_ADDED_BY_USER = BIT(0),
+};
+
+struct ice_esw_br_fdb_entry {
+ struct ice_esw_br_fdb_data data;
+ struct rhash_head ht_node;
+ struct list_head list;
+
+ int flags;
+
+ struct net_device *dev;
+ struct ice_esw_br_port *br_port;
+ struct ice_esw_br_flow *flow;
+
+ unsigned long last_use;
+};
+
+enum ice_esw_br_port_type {
+ ICE_ESWITCH_BR_UPLINK_PORT = 0,
+ ICE_ESWITCH_BR_VF_REPR_PORT = 1,
+};
+
+struct ice_esw_br_port {
+ struct ice_esw_br *bridge;
+ struct ice_vsi *vsi;
+ enum ice_esw_br_port_type type;
+ u16 vsi_idx;
+ u16 pvid;
+ struct xarray vlans;
+};
+
+enum {
+ ICE_ESWITCH_BR_VLAN_FILTERING = BIT(0),
+};
+
+struct ice_esw_br {
+ struct ice_esw_br_offloads *br_offloads;
+ struct xarray ports;
+
+ struct rhashtable fdb_ht;
+ struct list_head fdb_list;
+
+ int ifindex;
+ u32 flags;
+ unsigned long ageing_time;
+};
+
+struct ice_esw_br_offloads {
+ struct ice_pf *pf;
+ struct ice_esw_br *bridge;
+ struct notifier_block netdev_nb;
+ struct notifier_block switchdev_blk;
+ struct notifier_block switchdev_nb;
+
+ struct workqueue_struct *wq;
+ struct delayed_work update_work;
+};
+
+struct ice_esw_br_fdb_work {
+ struct work_struct work;
+ struct switchdev_notifier_fdb_info fdb_info;
+ struct net_device *dev;
+ unsigned long event;
+};
+
+struct ice_esw_br_vlan {
+ u16 vid;
+ u16 flags;
+};
+
+#define ice_nb_to_br_offloads(nb, nb_name) \
+ container_of(nb, \
+ struct ice_esw_br_offloads, \
+ nb_name)
+
+#define ice_work_to_br_offloads(w) \
+ container_of(w, \
+ struct ice_esw_br_offloads, \
+ update_work.work)
+
+#define ice_work_to_fdb_work(w) \
+ container_of(w, \
+ struct ice_esw_br_fdb_work, \
+ work)
+
+static inline bool ice_eswitch_br_is_vid_valid(u16 vid)
+{
+ /* In trunk VLAN mode, for untagged traffic the bridge sends requests
+ * to offload VLAN 1 with pvid and untagged flags set. Since these
+ * flags are not supported, add a MAC filter instead.
+ */
+ return vid > 1;
+}
+
+void
+ice_eswitch_br_offloads_deinit(struct ice_pf *pf);
+int
+ice_eswitch_br_offloads_init(struct ice_pf *pf);
+
+#endif /* _ICE_ESWITCH_BR_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_fw_update.c b/drivers/net/ethernet/intel/ice/ice_fw_update.c
index 3dc5662d62a6..319a2d6fe26c 100644
--- a/drivers/net/ethernet/intel/ice/ice_fw_update.c
+++ b/drivers/net/ethernet/intel/ice/ice_fw_update.c
@@ -293,16 +293,17 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
{
u16 completion_module, completion_retval;
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
+ struct ice_aq_desc *desc;
u32 completion_offset;
int err;
- memset(&event, 0, sizeof(event));
-
dev_dbg(dev, "Writing block of %u bytes for module 0x%02x at offset %u\n",
block_size, module, offset);
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_write);
+
err = ice_aq_update_nvm(hw, module, offset, block_size, block,
last_cmd, 0, NULL);
if (err) {
@@ -319,7 +320,7 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
* is conservative and is intended to prevent failure to update when
* firmware is slow to respond.
*/
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write, 15 * HZ, &event);
+ err = ice_aq_wait_for_event(pf, &task, 15 * HZ);
if (err) {
dev_err(dev, "Timed out while trying to flash module 0x%02x with block of size %u at offset %u, err %d\n",
module, block_size, offset, err);
@@ -327,11 +328,12 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
return -EIO;
}
- completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid);
- completion_retval = le16_to_cpu(event.desc.retval);
+ desc = &task.event.desc;
+ completion_module = le16_to_cpu(desc->params.nvm.module_typeid);
+ completion_retval = le16_to_cpu(desc->retval);
- completion_offset = le16_to_cpu(event.desc.params.nvm.offset_low);
- completion_offset |= event.desc.params.nvm.offset_high << 16;
+ completion_offset = le16_to_cpu(desc->params.nvm.offset_low);
+ completion_offset |= desc->params.nvm.offset_high << 16;
if (completion_module != module) {
dev_err(dev, "Unexpected module_typeid in write completion: got 0x%x, expected 0x%x\n",
@@ -363,8 +365,8 @@ ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset,
*/
if (reset_level && last_cmd && module == ICE_SR_1ST_NVM_BANK_PTR) {
if (hw->dev_caps.common_cap.pcie_reset_avoidance) {
- *reset_level = (event.desc.params.nvm.cmd_flags &
- ICE_AQC_NVM_RESET_LVL_M);
+ *reset_level = desc->params.nvm.cmd_flags &
+ ICE_AQC_NVM_RESET_LVL_M;
dev_dbg(dev, "Firmware reported required reset level as %u\n",
*reset_level);
} else {
@@ -479,19 +481,20 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
{
u16 completion_module, completion_retval;
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
+ struct ice_aq_desc *desc;
struct devlink *devlink;
int err;
dev_dbg(dev, "Beginning erase of flash component '%s', module 0x%02x\n", component, module);
- memset(&event, 0, sizeof(event));
-
devlink = priv_to_devlink(pf);
devlink_flash_update_timeout_notify(devlink, "Erasing", component, ICE_FW_ERASE_TIMEOUT);
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_erase);
+
err = ice_aq_erase_nvm(hw, module, NULL);
if (err) {
dev_err(dev, "Failed to erase %s (module 0x%02x), err %d aq_err %s\n",
@@ -502,7 +505,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ, &event);
+ err = ice_aq_wait_for_event(pf, &task, ICE_FW_ERASE_TIMEOUT * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to respond with erase completion for %s (module 0x%02x), err %d\n",
component, module, err);
@@ -510,8 +513,9 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
- completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid);
- completion_retval = le16_to_cpu(event.desc.retval);
+ desc = &task.event.desc;
+ completion_module = le16_to_cpu(desc->params.nvm.module_typeid);
+ completion_retval = le16_to_cpu(desc->retval);
if (completion_module != module) {
dev_err(dev, "Unexpected module_typeid in erase completion for %s: got 0x%x, expected 0x%x\n",
@@ -560,13 +564,13 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
u8 *emp_reset_available, struct netlink_ext_ack *extack)
{
struct device *dev = ice_pf_to_dev(pf);
- struct ice_rq_event_info event;
+ struct ice_aq_task task = {};
struct ice_hw *hw = &pf->hw;
u16 completion_retval;
u8 response_flags;
int err;
- memset(&event, 0, sizeof(event));
+ ice_aq_prep_for_event(pf, &task, ice_aqc_opc_nvm_write_activate);
err = ice_nvm_write_activate(hw, activate_flags, &response_flags);
if (err) {
@@ -592,8 +596,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
}
}
- err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ,
- &event);
+ err = ice_aq_wait_for_event(pf, &task, 30 * HZ);
if (err) {
dev_err(dev, "Timed out waiting for firmware to switch active flash banks, err %d\n",
err);
@@ -601,7 +604,7 @@ ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags,
return err;
}
- completion_retval = le16_to_cpu(event.desc.retval);
+ completion_retval = le16_to_cpu(task.event.desc.retval);
if (completion_retval) {
dev_err(dev, "Firmware failed to switch active flash banks aq_err %s\n",
ice_aq_str((enum ice_aq_err)completion_retval));
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index a92dc9a16035..531cc2194741 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -335,6 +335,8 @@
#define VP_MDET_TX_TCLAN_VALID_M BIT(0)
#define VP_MDET_TX_TDPU(_VF) (0x00040000 + ((_VF) * 4))
#define VP_MDET_TX_TDPU_VALID_M BIT(0)
+#define GL_MNG_FWSM 0x000B6134
+#define GL_MNG_FWSM_FW_LOADING_M BIT(30)
#define GLNVM_FLA 0x000B6108
#define GLNVM_FLA_LOCKED_M BIT(6)
#define GLNVM_GENS 0x000B6100
@@ -489,7 +491,6 @@
#define VSIQF_FD_CNT_FD_BCNT_M ICE_M(0x3FFF, 16)
#define VSIQF_FD_SIZE(_VSI) (0x00462000 + ((_VSI) * 4))
#define VSIQF_HKEY_MAX_INDEX 12
-#define VSIQF_HLUT_MAX_INDEX 15
#define PFPM_APM 0x000B8080
#define PFPM_APM_APME_M BIT(0)
#define PFPM_WUFC 0x0009DC00
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index 5a7753bda324..4f39863b5537 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -4,8 +4,24 @@
/* Link Aggregation code */
#include "ice.h"
+#include "ice_lib.h"
#include "ice_lag.h"
+#define ICE_LAG_RES_SHARED BIT(14)
+#define ICE_LAG_RES_VALID BIT(15)
+
+#define LACP_TRAIN_PKT_LEN 16
+static const u8 lacp_train_pkt[LACP_TRAIN_PKT_LEN] = { 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0x88, 0x09, 0, 0 };
+
+#define ICE_RECIPE_LEN 64
+static const u8 ice_dflt_vsi_rcp[ICE_RECIPE_LEN] = {
+ 0x05, 0, 0, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x85, 0, 0x01, 0, 0, 0, 0xff, 0xff, 0x08, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
/**
* ice_lag_set_primary - set PF LAG state as Primary
* @lag: LAG info struct
@@ -47,16 +63,219 @@ static void ice_lag_set_backup(struct ice_lag *lag)
}
/**
+ * netif_is_same_ice - determine if netdev is on the same ice NIC as local PF
+ * @pf: local PF struct
+ * @netdev: netdev we are evaluating
+ */
+static bool netif_is_same_ice(struct ice_pf *pf, struct net_device *netdev)
+{
+ struct ice_netdev_priv *np;
+ struct ice_pf *test_pf;
+ struct ice_vsi *vsi;
+
+ if (!netif_is_ice(netdev))
+ return false;
+
+ np = netdev_priv(netdev);
+ if (!np)
+ return false;
+
+ vsi = np->vsi;
+ if (!vsi)
+ return false;
+
+ test_pf = vsi->back;
+ if (!test_pf)
+ return false;
+
+ if (pf->pdev->bus != test_pf->pdev->bus ||
+ pf->pdev->slot != test_pf->pdev->slot)
+ return false;
+
+ return true;
+}
+
+/**
+ * ice_netdev_to_lag - return pointer to associated lag struct from netdev
+ * @netdev: pointer to net_device struct to query
+ */
+static struct ice_lag *ice_netdev_to_lag(struct net_device *netdev)
+{
+ struct ice_netdev_priv *np;
+ struct ice_vsi *vsi;
+
+ if (!netif_is_ice(netdev))
+ return NULL;
+
+ np = netdev_priv(netdev);
+ if (!np)
+ return NULL;
+
+ vsi = np->vsi;
+ if (!vsi)
+ return NULL;
+
+ return vsi->back->lag;
+}
+
+/**
+ * ice_lag_find_hw_by_lport - return an hw struct from bond members lport
+ * @lag: lag struct
+ * @lport: lport value to search for
+ */
+static struct ice_hw *
+ice_lag_find_hw_by_lport(struct ice_lag *lag, u8 lport)
+{
+ struct ice_lag_netdev_list *entry;
+ struct net_device *tmp_netdev;
+ struct ice_netdev_priv *np;
+ struct ice_hw *hw;
+
+ list_for_each_entry(entry, lag->netdev_head, node) {
+ tmp_netdev = entry->netdev;
+ if (!tmp_netdev || !netif_is_ice(tmp_netdev))
+ continue;
+
+ np = netdev_priv(tmp_netdev);
+ if (!np || !np->vsi)
+ continue;
+
+ hw = &np->vsi->back->hw;
+ if (hw->port_info->lport == lport)
+ return hw;
+ }
+
+ return NULL;
+}
+
+/**
+ * ice_lag_find_primary - returns pointer to primary interfaces lag struct
+ * @lag: local interfaces lag struct
+ */
+static struct ice_lag *ice_lag_find_primary(struct ice_lag *lag)
+{
+ struct ice_lag *primary_lag = NULL;
+ struct list_head *tmp;
+
+ list_for_each(tmp, lag->netdev_head) {
+ struct ice_lag_netdev_list *entry;
+ struct ice_lag *tmp_lag;
+
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ tmp_lag = ice_netdev_to_lag(entry->netdev);
+ if (tmp_lag && tmp_lag->primary) {
+ primary_lag = tmp_lag;
+ break;
+ }
+ }
+
+ return primary_lag;
+}
+
+/**
+ * ice_lag_cfg_dflt_fltr - Add/Remove default VSI rule for LAG
+ * @lag: lag struct for local interface
+ * @add: boolean on whether we are adding filters
+ */
+static int
+ice_lag_cfg_dflt_fltr(struct ice_lag *lag, bool add)
+{
+ struct ice_sw_rule_lkup_rx_tx *s_rule;
+ u16 s_rule_sz, vsi_num;
+ struct ice_hw *hw;
+ u32 act, opc;
+ u8 *eth_hdr;
+ int err;
+
+ hw = &lag->pf->hw;
+ vsi_num = ice_get_hw_vsi_num(hw, 0);
+
+ s_rule_sz = ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s_rule);
+ s_rule = kzalloc(s_rule_sz, GFP_KERNEL);
+ if (!s_rule) {
+ dev_err(ice_pf_to_dev(lag->pf), "error allocating rule for LAG default VSI\n");
+ return -ENOMEM;
+ }
+
+ if (add) {
+ eth_hdr = s_rule->hdr_data;
+ ice_fill_eth_hdr(eth_hdr);
+
+ act = (vsi_num << ICE_SINGLE_ACT_VSI_ID_S) &
+ ICE_SINGLE_ACT_VSI_ID_M;
+ act |= ICE_SINGLE_ACT_VSI_FORWARDING |
+ ICE_SINGLE_ACT_VALID_BIT | ICE_SINGLE_ACT_LAN_ENABLE;
+
+ s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
+ s_rule->recipe_id = cpu_to_le16(lag->pf_recipe);
+ s_rule->src = cpu_to_le16(hw->port_info->lport);
+ s_rule->act = cpu_to_le32(act);
+ s_rule->hdr_len = cpu_to_le16(DUMMY_ETH_HDR_LEN);
+ opc = ice_aqc_opc_add_sw_rules;
+ } else {
+ s_rule->index = cpu_to_le16(lag->pf_rule_id);
+ opc = ice_aqc_opc_remove_sw_rules;
+ }
+
+ err = ice_aq_sw_rules(&lag->pf->hw, s_rule, s_rule_sz, 1, opc, NULL);
+ if (err)
+ goto dflt_fltr_free;
+
+ if (add)
+ lag->pf_rule_id = le16_to_cpu(s_rule->index);
+ else
+ lag->pf_rule_id = 0;
+
+dflt_fltr_free:
+ kfree(s_rule);
+ return err;
+}
+
+/**
+ * ice_lag_cfg_pf_fltrs - set filters up for new active port
+ * @lag: local interfaces lag struct
+ * @ptr: opaque data containing notifier event
+ */
+static void
+ice_lag_cfg_pf_fltrs(struct ice_lag *lag, void *ptr)
+{
+ struct netdev_notifier_bonding_info *info;
+ struct netdev_bonding_info *bonding_info;
+ struct net_device *event_netdev;
+ struct device *dev;
+
+ event_netdev = netdev_notifier_info_to_dev(ptr);
+ /* not for this netdev */
+ if (event_netdev != lag->netdev)
+ return;
+
+ info = (struct netdev_notifier_bonding_info *)ptr;
+ bonding_info = &info->bonding_info;
+ dev = ice_pf_to_dev(lag->pf);
+
+ /* interface not active - remove old default VSI rule */
+ if (bonding_info->slave.state && lag->pf_rule_id) {
+ if (ice_lag_cfg_dflt_fltr(lag, false))
+ dev_err(dev, "Error removing old default VSI filter\n");
+ return;
+ }
+
+ /* interface becoming active - add new default VSI rule */
+ if (!bonding_info->slave.state && !lag->pf_rule_id)
+ if (ice_lag_cfg_dflt_fltr(lag, true))
+ dev_err(dev, "Error adding new default VSI filter\n");
+}
+
+/**
* ice_display_lag_info - print LAG info
* @lag: LAG info struct
*/
static void ice_display_lag_info(struct ice_lag *lag)
{
- const char *name, *peer, *upper, *role, *bonded, *primary;
+ const char *name, *upper, *role, *bonded, *primary;
struct device *dev = &lag->pf->pdev->dev;
name = lag->netdev ? netdev_name(lag->netdev) : "unset";
- peer = lag->peer_netdev ? netdev_name(lag->peer_netdev) : "unset";
upper = lag->upper_netdev ? netdev_name(lag->upper_netdev) : "unset";
primary = lag->primary ? "TRUE" : "FALSE";
bonded = lag->bonded ? "BONDED" : "UNBONDED";
@@ -78,8 +297,410 @@ static void ice_display_lag_info(struct ice_lag *lag)
role = "ERROR";
}
- dev_dbg(dev, "%s %s, peer:%s, upper:%s, role:%s, primary:%s\n", name,
- bonded, peer, upper, role, primary);
+ dev_dbg(dev, "%s %s, upper:%s, role:%s, primary:%s\n", name, bonded,
+ upper, role, primary);
+}
+
+/**
+ * ice_lag_qbuf_recfg - generate a buffer of queues for a reconfigure command
+ * @hw: HW struct that contains the queue contexts
+ * @qbuf: pointer to buffer to populate
+ * @vsi_num: index of the VSI in PF space
+ * @numq: number of queues to search for
+ * @tc: traffic class that contains the queues
+ *
+ * function returns the number of valid queues in buffer
+ */
+static u16
+ice_lag_qbuf_recfg(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *qbuf,
+ u16 vsi_num, u16 numq, u8 tc)
+{
+ struct ice_q_ctx *q_ctx;
+ u16 qid, count = 0;
+ struct ice_pf *pf;
+ int i;
+
+ pf = hw->back;
+ for (i = 0; i < numq; i++) {
+ q_ctx = ice_get_lan_q_ctx(hw, vsi_num, tc, i);
+ if (!q_ctx) {
+ dev_dbg(ice_hw_to_dev(hw), "%s queue %d NO Q CONTEXT\n",
+ __func__, i);
+ continue;
+ }
+ if (q_ctx->q_teid == ICE_INVAL_TEID) {
+ dev_dbg(ice_hw_to_dev(hw), "%s queue %d INVAL TEID\n",
+ __func__, i);
+ continue;
+ }
+ if (q_ctx->q_handle == ICE_INVAL_Q_HANDLE) {
+ dev_dbg(ice_hw_to_dev(hw), "%s queue %d INVAL Q HANDLE\n",
+ __func__, i);
+ continue;
+ }
+
+ qid = pf->vsi[vsi_num]->txq_map[q_ctx->q_handle];
+ qbuf->queue_info[count].q_handle = cpu_to_le16(qid);
+ qbuf->queue_info[count].tc = tc;
+ qbuf->queue_info[count].q_teid = cpu_to_le32(q_ctx->q_teid);
+ count++;
+ }
+
+ return count;
+}
+
+/**
+ * ice_lag_get_sched_parent - locate or create a sched node parent
+ * @hw: HW struct for getting parent in
+ * @tc: traffic class on parent/node
+ */
+static struct ice_sched_node *
+ice_lag_get_sched_parent(struct ice_hw *hw, u8 tc)
+{
+ struct ice_sched_node *tc_node, *aggnode, *parent = NULL;
+ u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
+ struct ice_port_info *pi = hw->port_info;
+ struct device *dev;
+ u8 aggl, vsil;
+ int n;
+
+ dev = ice_hw_to_dev(hw);
+
+ tc_node = ice_sched_get_tc_node(pi, tc);
+ if (!tc_node) {
+ dev_warn(dev, "Failure to find TC node for LAG move\n");
+ return parent;
+ }
+
+ aggnode = ice_sched_get_agg_node(pi, tc_node, ICE_DFLT_AGG_ID);
+ if (!aggnode) {
+ dev_warn(dev, "Failure to find aggregate node for LAG move\n");
+ return parent;
+ }
+
+ aggl = ice_sched_get_agg_layer(hw);
+ vsil = ice_sched_get_vsi_layer(hw);
+
+ for (n = aggl + 1; n < vsil; n++)
+ num_nodes[n] = 1;
+
+ for (n = 0; n < aggnode->num_children; n++) {
+ parent = ice_sched_get_free_vsi_parent(hw, aggnode->children[n],
+ num_nodes);
+ if (parent)
+ return parent;
+ }
+
+ /* if free parent not found - add one */
+ parent = aggnode;
+ for (n = aggl + 1; n < vsil; n++) {
+ u16 num_nodes_added;
+ u32 first_teid;
+ int err;
+
+ err = ice_sched_add_nodes_to_layer(pi, tc_node, parent, n,
+ num_nodes[n], &first_teid,
+ &num_nodes_added);
+ if (err || num_nodes[n] != num_nodes_added)
+ return NULL;
+
+ if (num_nodes_added)
+ parent = ice_sched_find_node_by_teid(tc_node,
+ first_teid);
+ else
+ parent = parent->children[0];
+ if (!parent) {
+ dev_warn(dev, "Failure to add new parent for LAG move\n");
+ return parent;
+ }
+ }
+
+ return parent;
+}
+
+/**
+ * ice_lag_move_vf_node_tc - move scheduling nodes for one VF on one TC
+ * @lag: lag info struct
+ * @oldport: lport of previous nodes location
+ * @newport: lport of destination nodes location
+ * @vsi_num: array index of VSI in PF space
+ * @tc: traffic class to move
+ */
+static void
+ice_lag_move_vf_node_tc(struct ice_lag *lag, u8 oldport, u8 newport,
+ u16 vsi_num, u8 tc)
+{
+ u16 numq, valq, buf_size, num_moved, qbuf_size;
+ struct device *dev = ice_pf_to_dev(lag->pf);
+ struct ice_aqc_cfg_txqs_buf *qbuf;
+ struct ice_aqc_move_elem *buf;
+ struct ice_sched_node *n_prt;
+ struct ice_hw *new_hw = NULL;
+ __le32 teid, parent_teid;
+ struct ice_vsi_ctx *ctx;
+ u32 tmp_teid;
+
+ ctx = ice_get_vsi_ctx(&lag->pf->hw, vsi_num);
+ if (!ctx) {
+ dev_warn(dev, "Unable to locate VSI context for LAG failover\n");
+ return;
+ }
+
+ /* check to see if this VF is enabled on this TC */
+ if (!ctx->sched.vsi_node[tc])
+ return;
+
+ /* locate HW struct for destination port */
+ new_hw = ice_lag_find_hw_by_lport(lag, newport);
+ if (!new_hw) {
+ dev_warn(dev, "Unable to locate HW struct for LAG node destination\n");
+ return;
+ }
+
+ numq = ctx->num_lan_q_entries[tc];
+ teid = ctx->sched.vsi_node[tc]->info.node_teid;
+ tmp_teid = le32_to_cpu(teid);
+ parent_teid = ctx->sched.vsi_node[tc]->info.parent_teid;
+ /* if no teid assigned or numq == 0, then this TC is not active */
+ if (!tmp_teid || !numq)
+ return;
+
+ /* suspend VSI subtree for Traffic Class "tc" on
+ * this VF's VSI
+ */
+ if (ice_sched_suspend_resume_elems(&lag->pf->hw, 1, &tmp_teid, true))
+ dev_dbg(dev, "Problem suspending traffic for LAG node move\n");
+
+ /* reconfigure all VF's queues on this Traffic Class
+ * to new port
+ */
+ qbuf_size = struct_size(qbuf, queue_info, numq);
+ qbuf = kzalloc(qbuf_size, GFP_KERNEL);
+ if (!qbuf) {
+ dev_warn(dev, "Failure allocating memory for VF queue recfg buffer\n");
+ goto resume_traffic;
+ }
+
+ /* add the per queue info for the reconfigure command buffer */
+ valq = ice_lag_qbuf_recfg(&lag->pf->hw, qbuf, vsi_num, numq, tc);
+ if (!valq) {
+ dev_dbg(dev, "No valid queues found for LAG failover\n");
+ goto qbuf_none;
+ }
+
+ if (ice_aq_cfg_lan_txq(&lag->pf->hw, qbuf, qbuf_size, valq, oldport,
+ newport, NULL)) {
+ dev_warn(dev, "Failure to configure queues for LAG failover\n");
+ goto qbuf_err;
+ }
+
+qbuf_none:
+ kfree(qbuf);
+
+ /* find new parent in destination port's tree for VF VSI node on this
+ * Traffic Class
+ */
+ n_prt = ice_lag_get_sched_parent(new_hw, tc);
+ if (!n_prt)
+ goto resume_traffic;
+
+ /* Move Vf's VSI node for this TC to newport's scheduler tree */
+ buf_size = struct_size(buf, teid, 1);
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf) {
+ dev_warn(dev, "Failure to alloc memory for VF node failover\n");
+ goto resume_traffic;
+ }
+
+ buf->hdr.src_parent_teid = parent_teid;
+ buf->hdr.dest_parent_teid = n_prt->info.node_teid;
+ buf->hdr.num_elems = cpu_to_le16(1);
+ buf->hdr.mode = ICE_AQC_MOVE_ELEM_MODE_KEEP_OWN;
+ buf->teid[0] = teid;
+
+ if (ice_aq_move_sched_elems(&lag->pf->hw, 1, buf, buf_size, &num_moved,
+ NULL))
+ dev_warn(dev, "Failure to move VF nodes for failover\n");
+ else
+ ice_sched_update_parent(n_prt, ctx->sched.vsi_node[tc]);
+
+ kfree(buf);
+ goto resume_traffic;
+
+qbuf_err:
+ kfree(qbuf);
+
+resume_traffic:
+ /* restart traffic for VSI node */
+ if (ice_sched_suspend_resume_elems(&lag->pf->hw, 1, &tmp_teid, false))
+ dev_dbg(dev, "Problem restarting traffic for LAG node move\n");
+}
+
+/**
+ * ice_lag_move_single_vf_nodes - Move Tx scheduling nodes for single VF
+ * @lag: primary interface LAG struct
+ * @oldport: lport of previous interface
+ * @newport: lport of destination interface
+ * @vsi_num: SW index of VF's VSI
+ */
+static void
+ice_lag_move_single_vf_nodes(struct ice_lag *lag, u8 oldport, u8 newport,
+ u16 vsi_num)
+{
+ u8 tc;
+
+ ice_for_each_traffic_class(tc)
+ ice_lag_move_vf_node_tc(lag, oldport, newport, vsi_num, tc);
+}
+
+/**
+ * ice_lag_move_new_vf_nodes - Move Tx scheduling nodes for a VF if required
+ * @vf: the VF to move Tx nodes for
+ *
+ * Called just after configuring new VF queues. Check whether the VF Tx
+ * scheduling nodes need to be updated to fail over to the active port. If so,
+ * move them now.
+ */
+void ice_lag_move_new_vf_nodes(struct ice_vf *vf)
+{
+ struct ice_lag_netdev_list ndlist;
+ struct list_head *tmp, *n;
+ u8 pri_port, act_port;
+ struct ice_lag *lag;
+ struct ice_vsi *vsi;
+ struct ice_pf *pf;
+
+ vsi = ice_get_vf_vsi(vf);
+
+ if (WARN_ON(!vsi))
+ return;
+
+ if (WARN_ON(vsi->type != ICE_VSI_VF))
+ return;
+
+ pf = vf->pf;
+ lag = pf->lag;
+
+ mutex_lock(&pf->lag_mutex);
+ if (!lag->bonded)
+ goto new_vf_unlock;
+
+ pri_port = pf->hw.port_info->lport;
+ act_port = lag->active_port;
+
+ if (lag->upper_netdev) {
+ struct ice_lag_netdev_list *nl;
+ struct net_device *tmp_nd;
+
+ INIT_LIST_HEAD(&ndlist.node);
+ rcu_read_lock();
+ for_each_netdev_in_bond_rcu(lag->upper_netdev, tmp_nd) {
+ nl = kzalloc(sizeof(*nl), GFP_KERNEL);
+ if (!nl)
+ break;
+
+ nl->netdev = tmp_nd;
+ list_add(&nl->node, &ndlist.node);
+ }
+ rcu_read_unlock();
+ }
+
+ lag->netdev_head = &ndlist.node;
+
+ if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG) &&
+ lag->bonded && lag->primary && pri_port != act_port &&
+ !list_empty(lag->netdev_head))
+ ice_lag_move_single_vf_nodes(lag, pri_port, act_port, vsi->idx);
+
+ list_for_each_safe(tmp, n, &ndlist.node) {
+ struct ice_lag_netdev_list *entry;
+
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ lag->netdev_head = NULL;
+
+new_vf_unlock:
+ mutex_unlock(&pf->lag_mutex);
+}
+
+/**
+ * ice_lag_move_vf_nodes - move Tx scheduling nodes for all VFs to new port
+ * @lag: lag info struct
+ * @oldport: lport of previous interface
+ * @newport: lport of destination interface
+ */
+static void ice_lag_move_vf_nodes(struct ice_lag *lag, u8 oldport, u8 newport)
+{
+ struct ice_pf *pf;
+ int i;
+
+ if (!lag->primary)
+ return;
+
+ pf = lag->pf;
+ ice_for_each_vsi(pf, i)
+ if (pf->vsi[i] && (pf->vsi[i]->type == ICE_VSI_VF ||
+ pf->vsi[i]->type == ICE_VSI_SWITCHDEV_CTRL))
+ ice_lag_move_single_vf_nodes(lag, oldport, newport, i);
+}
+
+#define ICE_LAG_SRIOV_CP_RECIPE 10
+#define ICE_LAG_SRIOV_TRAIN_PKT_LEN 16
+
+/**
+ * ice_lag_cfg_cp_fltr - configure filter for control packets
+ * @lag: local interface's lag struct
+ * @add: add or remove rule
+ */
+static void
+ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add)
+{
+ struct ice_sw_rule_lkup_rx_tx *s_rule = NULL;
+ struct ice_vsi *vsi;
+ u16 buf_len, opc;
+
+ vsi = lag->pf->vsi[0];
+
+ buf_len = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule,
+ ICE_LAG_SRIOV_TRAIN_PKT_LEN);
+ s_rule = kzalloc(buf_len, GFP_KERNEL);
+ if (!s_rule) {
+ netdev_warn(lag->netdev, "-ENOMEM error configuring CP filter\n");
+ return;
+ }
+
+ if (add) {
+ s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
+ s_rule->recipe_id = cpu_to_le16(ICE_LAG_SRIOV_CP_RECIPE);
+ s_rule->src = cpu_to_le16(vsi->port_info->lport);
+ s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI |
+ ICE_SINGLE_ACT_LAN_ENABLE |
+ ICE_SINGLE_ACT_VALID_BIT |
+ ((vsi->vsi_num <<
+ ICE_SINGLE_ACT_VSI_ID_S) &
+ ICE_SINGLE_ACT_VSI_ID_M));
+ s_rule->hdr_len = cpu_to_le16(ICE_LAG_SRIOV_TRAIN_PKT_LEN);
+ memcpy(s_rule->hdr_data, lacp_train_pkt, LACP_TRAIN_PKT_LEN);
+ opc = ice_aqc_opc_add_sw_rules;
+ } else {
+ opc = ice_aqc_opc_remove_sw_rules;
+ s_rule->index = cpu_to_le16(lag->cp_rule_idx);
+ }
+ if (ice_aq_sw_rules(&lag->pf->hw, s_rule, buf_len, 1, opc, NULL)) {
+ netdev_warn(lag->netdev, "Error %s CP rule for fail-over\n",
+ add ? "ADDING" : "REMOVING");
+ goto cp_free;
+ }
+
+ if (add)
+ lag->cp_rule_idx = le16_to_cpu(s_rule->index);
+ else
+ lag->cp_rule_idx = 0;
+
+cp_free:
+ kfree(s_rule);
}
/**
@@ -124,117 +745,430 @@ lag_out:
}
/**
+ * ice_lag_reclaim_vf_tc - move scheduling nodes back to primary interface
+ * @lag: primary interface lag struct
+ * @src_hw: HW struct current node location
+ * @vsi_num: VSI index in PF space
+ * @tc: traffic class to move
+ */
+static void
+ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num,
+ u8 tc)
+{
+ u16 numq, valq, buf_size, num_moved, qbuf_size;
+ struct device *dev = ice_pf_to_dev(lag->pf);
+ struct ice_aqc_cfg_txqs_buf *qbuf;
+ struct ice_aqc_move_elem *buf;
+ struct ice_sched_node *n_prt;
+ __le32 teid, parent_teid;
+ struct ice_vsi_ctx *ctx;
+ struct ice_hw *hw;
+ u32 tmp_teid;
+
+ hw = &lag->pf->hw;
+ ctx = ice_get_vsi_ctx(hw, vsi_num);
+ if (!ctx) {
+ dev_warn(dev, "Unable to locate VSI context for LAG reclaim\n");
+ return;
+ }
+
+ /* check to see if this VF is enabled on this TC */
+ if (!ctx->sched.vsi_node[tc])
+ return;
+
+ numq = ctx->num_lan_q_entries[tc];
+ teid = ctx->sched.vsi_node[tc]->info.node_teid;
+ tmp_teid = le32_to_cpu(teid);
+ parent_teid = ctx->sched.vsi_node[tc]->info.parent_teid;
+
+ /* if !teid or !numq, then this TC is not active */
+ if (!tmp_teid || !numq)
+ return;
+
+ /* suspend traffic */
+ if (ice_sched_suspend_resume_elems(hw, 1, &tmp_teid, true))
+ dev_dbg(dev, "Problem suspending traffic for LAG node move\n");
+
+ /* reconfig queues for new port */
+ qbuf_size = struct_size(qbuf, queue_info, numq);
+ qbuf = kzalloc(qbuf_size, GFP_KERNEL);
+ if (!qbuf) {
+ dev_warn(dev, "Failure allocating memory for VF queue recfg buffer\n");
+ goto resume_reclaim;
+ }
+
+ /* add the per queue info for the reconfigure command buffer */
+ valq = ice_lag_qbuf_recfg(hw, qbuf, vsi_num, numq, tc);
+ if (!valq) {
+ dev_dbg(dev, "No valid queues found for LAG reclaim\n");
+ goto reclaim_none;
+ }
+
+ if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq,
+ src_hw->port_info->lport, hw->port_info->lport,
+ NULL)) {
+ dev_warn(dev, "Failure to configure queues for LAG failover\n");
+ goto reclaim_qerr;
+ }
+
+reclaim_none:
+ kfree(qbuf);
+
+ /* find parent in primary tree */
+ n_prt = ice_lag_get_sched_parent(hw, tc);
+ if (!n_prt)
+ goto resume_reclaim;
+
+ /* Move node to new parent */
+ buf_size = struct_size(buf, teid, 1);
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf) {
+ dev_warn(dev, "Failure to alloc memory for VF node failover\n");
+ goto resume_reclaim;
+ }
+
+ buf->hdr.src_parent_teid = parent_teid;
+ buf->hdr.dest_parent_teid = n_prt->info.node_teid;
+ buf->hdr.num_elems = cpu_to_le16(1);
+ buf->hdr.mode = ICE_AQC_MOVE_ELEM_MODE_KEEP_OWN;
+ buf->teid[0] = teid;
+
+ if (ice_aq_move_sched_elems(&lag->pf->hw, 1, buf, buf_size, &num_moved,
+ NULL))
+ dev_warn(dev, "Failure to move VF nodes for LAG reclaim\n");
+ else
+ ice_sched_update_parent(n_prt, ctx->sched.vsi_node[tc]);
+
+ kfree(buf);
+ goto resume_reclaim;
+
+reclaim_qerr:
+ kfree(qbuf);
+
+resume_reclaim:
+ /* restart traffic */
+ if (ice_sched_suspend_resume_elems(hw, 1, &tmp_teid, false))
+ dev_warn(dev, "Problem restarting traffic for LAG node reclaim\n");
+}
+
+/**
+ * ice_lag_reclaim_vf_nodes - When interface leaving bond primary reclaims nodes
+ * @lag: primary interface lag struct
+ * @src_hw: HW struct for current node location
+ */
+static void
+ice_lag_reclaim_vf_nodes(struct ice_lag *lag, struct ice_hw *src_hw)
+{
+ struct ice_pf *pf;
+ int i, tc;
+
+ if (!lag->primary || !src_hw)
+ return;
+
+ pf = lag->pf;
+ ice_for_each_vsi(pf, i)
+ if (pf->vsi[i] && (pf->vsi[i]->type == ICE_VSI_VF ||
+ pf->vsi[i]->type == ICE_VSI_SWITCHDEV_CTRL))
+ ice_for_each_traffic_class(tc)
+ ice_lag_reclaim_vf_tc(lag, src_hw, i, tc);
+}
+
+/**
* ice_lag_link - handle LAG link event
* @lag: LAG info struct
- * @info: info from the netdev notifier
*/
-static void
-ice_lag_link(struct ice_lag *lag, struct netdev_notifier_changeupper_info *info)
+static void ice_lag_link(struct ice_lag *lag)
{
- struct net_device *netdev_tmp, *upper = info->upper_dev;
struct ice_pf *pf = lag->pf;
- int peers = 0;
if (lag->bonded)
dev_warn(ice_pf_to_dev(pf), "%s Already part of a bond\n",
netdev_name(lag->netdev));
- rcu_read_lock();
- for_each_netdev_in_bond_rcu(upper, netdev_tmp)
- peers++;
- rcu_read_unlock();
-
- if (lag->upper_netdev != upper) {
- dev_hold(upper);
- lag->upper_netdev = upper;
- }
-
- ice_clear_rdma_cap(pf);
-
lag->bonded = true;
lag->role = ICE_LAG_UNSET;
-
- /* if this is the first element in an LAG mark as primary */
- lag->primary = !!(peers == 1);
+ netdev_info(lag->netdev, "Shared SR-IOV resources in bond are active\n");
}
/**
* ice_lag_unlink - handle unlink event
* @lag: LAG info struct
- * @info: info from netdev notification
*/
-static void
-ice_lag_unlink(struct ice_lag *lag,
- struct netdev_notifier_changeupper_info *info)
+static void ice_lag_unlink(struct ice_lag *lag)
{
- struct net_device *netdev_tmp, *upper = info->upper_dev;
+ u8 pri_port, act_port, loc_port;
struct ice_pf *pf = lag->pf;
- bool found = false;
if (!lag->bonded) {
netdev_dbg(lag->netdev, "bonding unlink event on non-LAG netdev\n");
return;
}
- /* determine if we are in the new LAG config or not */
- rcu_read_lock();
- for_each_netdev_in_bond_rcu(upper, netdev_tmp) {
- if (netdev_tmp == lag->netdev) {
- found = true;
- break;
+ if (lag->primary) {
+ act_port = lag->active_port;
+ pri_port = lag->pf->hw.port_info->lport;
+ if (act_port != pri_port && act_port != ICE_LAG_INVALID_PORT)
+ ice_lag_move_vf_nodes(lag, act_port, pri_port);
+ lag->primary = false;
+ lag->active_port = ICE_LAG_INVALID_PORT;
+ } else {
+ struct ice_lag *primary_lag;
+
+ primary_lag = ice_lag_find_primary(lag);
+ if (primary_lag) {
+ act_port = primary_lag->active_port;
+ pri_port = primary_lag->pf->hw.port_info->lport;
+ loc_port = pf->hw.port_info->lport;
+ if (act_port == loc_port &&
+ act_port != ICE_LAG_INVALID_PORT) {
+ ice_lag_reclaim_vf_nodes(primary_lag,
+ &lag->pf->hw);
+ primary_lag->active_port = ICE_LAG_INVALID_PORT;
+ }
}
}
- rcu_read_unlock();
- if (found)
+ lag->bonded = false;
+ lag->role = ICE_LAG_NONE;
+ lag->upper_netdev = NULL;
+}
+
+/**
+ * ice_lag_link_unlink - helper function to call lag_link/unlink
+ * @lag: lag info struct
+ * @ptr: opaque pointer data
+ */
+static void ice_lag_link_unlink(struct ice_lag *lag, void *ptr)
+{
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+
+ if (netdev != lag->netdev)
return;
- if (lag->upper_netdev) {
- dev_put(lag->upper_netdev);
- lag->upper_netdev = NULL;
+ if (info->linking)
+ ice_lag_link(lag);
+ else
+ ice_lag_unlink(lag);
+}
+
+/**
+ * ice_lag_set_swid - set the SWID on secondary interface
+ * @primary_swid: primary interface's SWID
+ * @local_lag: local interfaces LAG struct
+ * @link: Is this a linking activity
+ *
+ * If link is false, then primary_swid should be expected to not be valid
+ * This function should never be called in interrupt context.
+ */
+static void
+ice_lag_set_swid(u16 primary_swid, struct ice_lag *local_lag,
+ bool link)
+{
+ struct ice_aqc_alloc_free_res_elem *buf;
+ struct ice_aqc_set_port_params *cmd;
+ struct ice_aq_desc desc;
+ u16 buf_len, swid;
+ int status, i;
+
+ buf_len = struct_size(buf, elem, 1);
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf) {
+ dev_err(ice_pf_to_dev(local_lag->pf), "-ENOMEM error setting SWID\n");
+ return;
}
- lag->peer_netdev = NULL;
- ice_set_rdma_cap(pf);
- lag->bonded = false;
- lag->role = ICE_LAG_NONE;
+ buf->num_elems = cpu_to_le16(1);
+ buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_SWID);
+ /* if unlinnking need to free the shared resource */
+ if (!link && local_lag->bond_swid) {
+ buf->elem[0].e.sw_resp = cpu_to_le16(local_lag->bond_swid);
+ status = ice_aq_alloc_free_res(&local_lag->pf->hw, buf,
+ buf_len, ice_aqc_opc_free_res);
+ if (status)
+ dev_err(ice_pf_to_dev(local_lag->pf), "Error freeing SWID during LAG unlink\n");
+ local_lag->bond_swid = 0;
+ }
+
+ if (link) {
+ buf->res_type |= cpu_to_le16(ICE_LAG_RES_SHARED |
+ ICE_LAG_RES_VALID);
+ /* store the primary's SWID in case it leaves bond first */
+ local_lag->bond_swid = primary_swid;
+ buf->elem[0].e.sw_resp = cpu_to_le16(local_lag->bond_swid);
+ } else {
+ buf->elem[0].e.sw_resp =
+ cpu_to_le16(local_lag->pf->hw.port_info->sw_id);
+ }
+
+ status = ice_aq_alloc_free_res(&local_lag->pf->hw, buf, buf_len,
+ ice_aqc_opc_alloc_res);
+ if (status)
+ dev_err(ice_pf_to_dev(local_lag->pf), "Error subscribing to SWID 0x%04X\n",
+ local_lag->bond_swid);
+
+ kfree(buf);
+
+ /* Configure port param SWID to correct value */
+ if (link)
+ swid = primary_swid;
+ else
+ swid = local_lag->pf->hw.port_info->sw_id;
+
+ cmd = &desc.params.set_port_params;
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_params);
+
+ cmd->swid = cpu_to_le16(ICE_AQC_PORT_SWID_VALID | swid);
+ /* If this is happening in reset context, it is possible that the
+ * primary interface has not finished setting its SWID to SHARED
+ * yet. Allow retries to account for this timing issue between
+ * interfaces.
+ */
+ for (i = 0; i < ICE_LAG_RESET_RETRIES; i++) {
+ status = ice_aq_send_cmd(&local_lag->pf->hw, &desc, NULL, 0,
+ NULL);
+ if (!status)
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (status)
+ dev_err(ice_pf_to_dev(local_lag->pf), "Error setting SWID in port params %d\n",
+ status);
}
/**
- * ice_lag_unregister - handle netdev unregister events
- * @lag: LAG info struct
- * @netdev: netdev reporting the event
+ * ice_lag_primary_swid - set/clear the SHARED attrib of primary's SWID
+ * @lag: primary interface's lag struct
+ * @link: is this a linking activity
+ *
+ * Implement setting primary SWID as shared using 0x020B
*/
-static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
+static void ice_lag_primary_swid(struct ice_lag *lag, bool link)
{
- struct ice_pf *pf = lag->pf;
+ struct ice_hw *hw;
+ u16 swid;
- /* check to see if this event is for this netdev
- * check that we are in an aggregate
- */
- if (netdev != lag->netdev || !lag->bonded)
+ hw = &lag->pf->hw;
+ swid = hw->port_info->sw_id;
+
+ if (ice_share_res(hw, ICE_AQC_RES_TYPE_SWID, link, swid))
+ dev_warn(ice_pf_to_dev(lag->pf), "Failure to set primary interface shared status\n");
+}
+
+/**
+ * ice_lag_add_prune_list - Adds event_pf's VSI to primary's prune list
+ * @lag: lag info struct
+ * @event_pf: PF struct for VSI we are adding to primary's prune list
+ */
+static void ice_lag_add_prune_list(struct ice_lag *lag, struct ice_pf *event_pf)
+{
+ u16 num_vsi, rule_buf_sz, vsi_list_id, event_vsi_num, prim_vsi_idx;
+ struct ice_sw_rule_vsi_list *s_rule = NULL;
+ struct device *dev;
+
+ num_vsi = 1;
+
+ dev = ice_pf_to_dev(lag->pf);
+ event_vsi_num = event_pf->vsi[0]->vsi_num;
+ prim_vsi_idx = lag->pf->vsi[0]->idx;
+
+ if (!ice_find_vsi_list_entry(&lag->pf->hw, ICE_SW_LKUP_VLAN,
+ prim_vsi_idx, &vsi_list_id)) {
+ dev_warn(dev, "Could not locate prune list when setting up SRIOV LAG\n");
return;
+ }
- if (lag->upper_netdev) {
- dev_put(lag->upper_netdev);
- lag->upper_netdev = NULL;
- ice_set_rdma_cap(pf);
+ rule_buf_sz = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi);
+ s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
+ if (!s_rule) {
+ dev_warn(dev, "Error allocating space for prune list when configuring SRIOV LAG\n");
+ return;
}
- /* perform some cleanup in case we come back */
- lag->bonded = false;
- lag->role = ICE_LAG_NONE;
+
+ s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_PRUNE_LIST_SET);
+ s_rule->index = cpu_to_le16(vsi_list_id);
+ s_rule->number_vsi = cpu_to_le16(num_vsi);
+ s_rule->vsi[0] = cpu_to_le16(event_vsi_num);
+
+ if (ice_aq_sw_rules(&event_pf->hw, s_rule, rule_buf_sz, 1,
+ ice_aqc_opc_update_sw_rules, NULL))
+ dev_warn(dev, "Error adding VSI prune list\n");
+ kfree(s_rule);
+}
+
+/**
+ * ice_lag_del_prune_list - Remove secondary's vsi from primary's prune list
+ * @lag: primary interface's ice_lag struct
+ * @event_pf: PF struct for unlinking interface
+ */
+static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf)
+{
+ u16 num_vsi, vsi_num, vsi_idx, rule_buf_sz, vsi_list_id;
+ struct ice_sw_rule_vsi_list *s_rule = NULL;
+ struct device *dev;
+
+ num_vsi = 1;
+
+ dev = ice_pf_to_dev(lag->pf);
+ vsi_num = event_pf->vsi[0]->vsi_num;
+ vsi_idx = lag->pf->vsi[0]->idx;
+
+ if (!ice_find_vsi_list_entry(&lag->pf->hw, ICE_SW_LKUP_VLAN,
+ vsi_idx, &vsi_list_id)) {
+ dev_warn(dev, "Could not locate prune list when unwinding SRIOV LAG\n");
+ return;
+ }
+
+ rule_buf_sz = (u16)ICE_SW_RULE_VSI_LIST_SIZE(s_rule, num_vsi);
+ s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
+ if (!s_rule) {
+ dev_warn(dev, "Error allocating prune list when unwinding SRIOV LAG\n");
+ return;
+ }
+
+ s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_PRUNE_LIST_CLEAR);
+ s_rule->index = cpu_to_le16(vsi_list_id);
+ s_rule->number_vsi = cpu_to_le16(num_vsi);
+ s_rule->vsi[0] = cpu_to_le16(vsi_num);
+
+ if (ice_aq_sw_rules(&event_pf->hw, (struct ice_aqc_sw_rules *)s_rule,
+ rule_buf_sz, 1, ice_aqc_opc_update_sw_rules, NULL))
+ dev_warn(dev, "Error clearing VSI prune list\n");
+
+ kfree(s_rule);
+}
+
+/**
+ * ice_lag_init_feature_support_flag - Check for NVM support for LAG
+ * @pf: PF struct
+ */
+static void ice_lag_init_feature_support_flag(struct ice_pf *pf)
+{
+ struct ice_hw_common_caps *caps;
+
+ caps = &pf->hw.dev_caps.common_cap;
+ if (caps->roce_lag)
+ ice_set_feature_support(pf, ICE_F_ROCE_LAG);
+ else
+ ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
+
+ if (caps->sriov_lag)
+ ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
+ else
+ ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
}
/**
* ice_lag_changeupper_event - handle LAG changeupper event
* @lag: LAG info struct
* @ptr: opaque pointer data
- *
- * ptr is to be cast into netdev_notifier_changeupper_info
*/
static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr)
{
struct netdev_notifier_changeupper_info *info;
+ struct ice_lag *primary_lag;
struct net_device *netdev;
info = ptr;
@@ -244,44 +1178,442 @@ static void ice_lag_changeupper_event(struct ice_lag *lag, void *ptr)
if (netdev != lag->netdev)
return;
- if (!info->upper_dev) {
- netdev_dbg(netdev, "changeupper rcvd, but no upper defined\n");
+ primary_lag = ice_lag_find_primary(lag);
+ if (info->linking) {
+ lag->upper_netdev = info->upper_dev;
+ /* If there is not already a primary interface in the LAG,
+ * then mark this one as primary.
+ */
+ if (!primary_lag) {
+ lag->primary = true;
+ /* Configure primary's SWID to be shared */
+ ice_lag_primary_swid(lag, true);
+ primary_lag = lag;
+ } else {
+ u16 swid;
+
+ swid = primary_lag->pf->hw.port_info->sw_id;
+ ice_lag_set_swid(swid, lag, true);
+ ice_lag_add_prune_list(primary_lag, lag->pf);
+ }
+ /* add filter for primary control packets */
+ ice_lag_cfg_cp_fltr(lag, true);
+ } else {
+ if (!primary_lag && lag->primary)
+ primary_lag = lag;
+
+ if (!lag->primary) {
+ ice_lag_set_swid(0, lag, false);
+ } else {
+ if (primary_lag && lag->primary) {
+ ice_lag_primary_swid(lag, false);
+ ice_lag_del_prune_list(primary_lag, lag->pf);
+ }
+ }
+ /* remove filter for control packets */
+ ice_lag_cfg_cp_fltr(lag, false);
+ }
+}
+
+/**
+ * ice_lag_monitor_link - monitor interfaces entering/leaving the aggregate
+ * @lag: lag info struct
+ * @ptr: opaque data containing notifier event
+ *
+ * This function only operates after a primary has been set.
+ */
+static void ice_lag_monitor_link(struct ice_lag *lag, void *ptr)
+{
+ struct netdev_notifier_changeupper_info *info;
+ struct ice_hw *prim_hw, *active_hw;
+ struct net_device *event_netdev;
+ struct ice_pf *pf;
+ u8 prim_port;
+
+ if (!lag->primary)
+ return;
+
+ event_netdev = netdev_notifier_info_to_dev(ptr);
+ if (!netif_is_same_ice(lag->pf, event_netdev))
+ return;
+
+ pf = lag->pf;
+ prim_hw = &pf->hw;
+ prim_port = prim_hw->port_info->lport;
+
+ info = (struct netdev_notifier_changeupper_info *)ptr;
+ if (info->upper_dev != lag->upper_netdev)
return;
+
+ if (!info->linking) {
+ /* Since there are only two interfaces allowed in SRIOV+LAG, if
+ * one port is leaving, then nodes need to be on primary
+ * interface.
+ */
+ if (prim_port != lag->active_port &&
+ lag->active_port != ICE_LAG_INVALID_PORT) {
+ active_hw = ice_lag_find_hw_by_lport(lag,
+ lag->active_port);
+ ice_lag_reclaim_vf_nodes(lag, active_hw);
+ lag->active_port = ICE_LAG_INVALID_PORT;
+ }
}
+}
+
+/**
+ * ice_lag_monitor_active - main PF keep track of which port is active
+ * @lag: lag info struct
+ * @ptr: opaque data containing notifier event
+ *
+ * This function is for the primary PF to monitor changes in which port is
+ * active and handle changes for SRIOV VF functionality
+ */
+static void ice_lag_monitor_active(struct ice_lag *lag, void *ptr)
+{
+ struct net_device *event_netdev, *event_upper;
+ struct netdev_notifier_bonding_info *info;
+ struct netdev_bonding_info *bonding_info;
+ struct ice_netdev_priv *event_np;
+ struct ice_pf *pf, *event_pf;
+ u8 prim_port, event_port;
+
+ if (!lag->primary)
+ return;
- netdev_dbg(netdev, "bonding %s\n", info->linking ? "LINK" : "UNLINK");
+ pf = lag->pf;
+ if (!pf)
+ return;
- if (!netif_is_lag_master(info->upper_dev)) {
- netdev_dbg(netdev, "changeupper rcvd, but not primary. bail\n");
+ event_netdev = netdev_notifier_info_to_dev(ptr);
+ rcu_read_lock();
+ event_upper = netdev_master_upper_dev_get_rcu(event_netdev);
+ rcu_read_unlock();
+ if (!netif_is_ice(event_netdev) || event_upper != lag->upper_netdev)
return;
+
+ event_np = netdev_priv(event_netdev);
+ event_pf = event_np->vsi->back;
+ event_port = event_pf->hw.port_info->lport;
+ prim_port = pf->hw.port_info->lport;
+
+ info = (struct netdev_notifier_bonding_info *)ptr;
+ bonding_info = &info->bonding_info;
+
+ if (!bonding_info->slave.state) {
+ /* if no port is currently active, then nodes and filters exist
+ * on primary port, check if we need to move them
+ */
+ if (lag->active_port == ICE_LAG_INVALID_PORT) {
+ if (event_port != prim_port)
+ ice_lag_move_vf_nodes(lag, prim_port,
+ event_port);
+ lag->active_port = event_port;
+ return;
+ }
+
+ /* active port is already set and is current event port */
+ if (lag->active_port == event_port)
+ return;
+ /* new active port */
+ ice_lag_move_vf_nodes(lag, lag->active_port, event_port);
+ lag->active_port = event_port;
+ } else {
+ /* port not set as currently active (e.g. new active port
+ * has already claimed the nodes and filters
+ */
+ if (lag->active_port != event_port)
+ return;
+ /* This is the case when neither port is active (both link down)
+ * Link down on the bond - set active port to invalid and move
+ * nodes and filters back to primary if not already there
+ */
+ if (event_port != prim_port)
+ ice_lag_move_vf_nodes(lag, event_port, prim_port);
+ lag->active_port = ICE_LAG_INVALID_PORT;
}
+}
- if (info->linking)
- ice_lag_link(lag, info);
- else
- ice_lag_unlink(lag, info);
+/**
+ * ice_lag_chk_comp - evaluate bonded interface for feature support
+ * @lag: lag info struct
+ * @ptr: opaque data for netdev event info
+ */
+static bool
+ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
+{
+ struct net_device *event_netdev, *event_upper;
+ struct netdev_notifier_bonding_info *info;
+ struct netdev_bonding_info *bonding_info;
+ struct list_head *tmp;
+ struct device *dev;
+ int count = 0;
- ice_display_lag_info(lag);
+ if (!lag->primary)
+ return true;
+
+ event_netdev = netdev_notifier_info_to_dev(ptr);
+ rcu_read_lock();
+ event_upper = netdev_master_upper_dev_get_rcu(event_netdev);
+ rcu_read_unlock();
+ if (event_upper != lag->upper_netdev)
+ return true;
+
+ dev = ice_pf_to_dev(lag->pf);
+
+ /* only supporting switchdev mode for SRIOV VF LAG.
+ * primary interface has to be in switchdev mode
+ */
+ if (!ice_is_switchdev_running(lag->pf)) {
+ dev_info(dev, "Primary interface not in switchdev mode - VF LAG disabled\n");
+ return false;
+ }
+
+ info = (struct netdev_notifier_bonding_info *)ptr;
+ bonding_info = &info->bonding_info;
+ lag->bond_mode = bonding_info->master.bond_mode;
+ if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) {
+ dev_info(dev, "Bond Mode not ACTIVE-BACKUP - VF LAG disabled\n");
+ return false;
+ }
+
+ list_for_each(tmp, lag->netdev_head) {
+ struct ice_dcbx_cfg *dcb_cfg, *peer_dcb_cfg;
+ struct ice_lag_netdev_list *entry;
+ struct ice_netdev_priv *peer_np;
+ struct net_device *peer_netdev;
+ struct ice_vsi *vsi, *peer_vsi;
+ struct ice_pf *peer_pf;
+
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ peer_netdev = entry->netdev;
+ if (!netif_is_ice(peer_netdev)) {
+ dev_info(dev, "Found %s non-ice netdev in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
+ return false;
+ }
+
+ count++;
+ if (count > 2) {
+ dev_info(dev, "Found more than two netdevs in LAG - VF LAG disabled\n");
+ return false;
+ }
+
+ peer_np = netdev_priv(peer_netdev);
+ vsi = ice_get_main_vsi(lag->pf);
+ peer_vsi = peer_np->vsi;
+ if (lag->pf->pdev->bus != peer_vsi->back->pdev->bus ||
+ lag->pf->pdev->slot != peer_vsi->back->pdev->slot) {
+ dev_info(dev, "Found %s on different device in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
+ return false;
+ }
+
+ dcb_cfg = &vsi->port_info->qos_cfg.local_dcbx_cfg;
+ peer_dcb_cfg = &peer_vsi->port_info->qos_cfg.local_dcbx_cfg;
+ if (memcmp(dcb_cfg, peer_dcb_cfg,
+ sizeof(struct ice_dcbx_cfg))) {
+ dev_info(dev, "Found %s with different DCB in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
+ return false;
+ }
+
+ peer_pf = peer_vsi->back;
+ if (test_bit(ICE_FLAG_FW_LLDP_AGENT, peer_pf->flags)) {
+ dev_warn(dev, "Found %s with FW LLDP agent active - VF LAG disabled\n",
+ netdev_name(peer_netdev));
+ return false;
+ }
+ }
+
+ return true;
}
/**
- * ice_lag_changelower_event - handle LAG changelower event
+ * ice_lag_unregister - handle netdev unregister events
* @lag: LAG info struct
- * @ptr: opaque data pointer
+ * @event_netdev: netdev struct for target of notifier event
+ */
+static void
+ice_lag_unregister(struct ice_lag *lag, struct net_device *event_netdev)
+{
+ struct ice_netdev_priv *np;
+ struct ice_pf *event_pf;
+ struct ice_lag *p_lag;
+
+ p_lag = ice_lag_find_primary(lag);
+ np = netdev_priv(event_netdev);
+ event_pf = np->vsi->back;
+
+ if (p_lag) {
+ if (p_lag->active_port != p_lag->pf->hw.port_info->lport &&
+ p_lag->active_port != ICE_LAG_INVALID_PORT) {
+ struct ice_hw *active_hw;
+
+ active_hw = ice_lag_find_hw_by_lport(lag,
+ p_lag->active_port);
+ if (active_hw)
+ ice_lag_reclaim_vf_nodes(p_lag, active_hw);
+ lag->active_port = ICE_LAG_INVALID_PORT;
+ }
+ }
+
+ /* primary processing for primary */
+ if (lag->primary && lag->netdev == event_netdev)
+ ice_lag_primary_swid(lag, false);
+
+ /* primary processing for secondary */
+ if (lag->primary && lag->netdev != event_netdev)
+ ice_lag_del_prune_list(lag, event_pf);
+
+ /* secondary processing for secondary */
+ if (!lag->primary && lag->netdev == event_netdev)
+ ice_lag_set_swid(0, lag, false);
+}
+
+/**
+ * ice_lag_monitor_rdma - set and clear rdma functionality
+ * @lag: pointer to lag struct
+ * @ptr: opaque data for netdev event info
+ */
+static void
+ice_lag_monitor_rdma(struct ice_lag *lag, void *ptr)
+{
+ struct netdev_notifier_changeupper_info *info;
+ struct net_device *netdev;
+
+ info = ptr;
+ netdev = netdev_notifier_info_to_dev(ptr);
+
+ if (netdev != lag->netdev)
+ return;
+
+ if (info->linking)
+ ice_clear_rdma_cap(lag->pf);
+ else
+ ice_set_rdma_cap(lag->pf);
+}
+
+/**
+ * ice_lag_chk_disabled_bond - monitor interfaces entering/leaving disabled bond
+ * @lag: lag info struct
+ * @ptr: opaque data containing event
*
- * ptr to be cast to netdev_notifier_changelowerstate_info
+ * as interfaces enter a bond - determine if the bond is currently
+ * SRIOV LAG compliant and flag if not. As interfaces leave the
+ * bond, reset their compliant status.
*/
-static void ice_lag_changelower_event(struct ice_lag *lag, void *ptr)
+static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct ice_lag *prim_lag;
if (netdev != lag->netdev)
return;
- netdev_dbg(netdev, "bonding info\n");
+ if (info->linking) {
+ prim_lag = ice_lag_find_primary(lag);
+ if (prim_lag &&
+ !ice_is_feature_supported(prim_lag->pf, ICE_F_SRIOV_LAG)) {
+ ice_clear_feature_support(lag->pf, ICE_F_SRIOV_LAG);
+ netdev_info(netdev, "Interface added to non-compliant SRIOV LAG aggregate\n");
+ }
+ } else {
+ ice_lag_init_feature_support_flag(lag->pf);
+ }
+}
+
+/**
+ * ice_lag_disable_sriov_bond - set members of bond as not supporting SRIOV LAG
+ * @lag: primary interfaces lag struct
+ */
+static void ice_lag_disable_sriov_bond(struct ice_lag *lag)
+{
+ struct ice_lag_netdev_list *entry;
+ struct ice_netdev_priv *np;
+ struct net_device *netdev;
+ struct ice_pf *pf;
+
+ list_for_each_entry(entry, lag->netdev_head, node) {
+ netdev = entry->netdev;
+ np = netdev_priv(netdev);
+ pf = np->vsi->back;
+
+ ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
+ }
+}
+
+/**
+ * ice_lag_process_event - process a task assigned to the lag_wq
+ * @work: pointer to work_struct
+ */
+static void ice_lag_process_event(struct work_struct *work)
+{
+ struct netdev_notifier_changeupper_info *info;
+ struct ice_lag_work *lag_work;
+ struct net_device *netdev;
+ struct list_head *tmp, *n;
+ struct ice_pf *pf;
+
+ lag_work = container_of(work, struct ice_lag_work, lag_task);
+ pf = lag_work->lag->pf;
+
+ mutex_lock(&pf->lag_mutex);
+ lag_work->lag->netdev_head = &lag_work->netdev_list.node;
+
+ switch (lag_work->event) {
+ case NETDEV_CHANGEUPPER:
+ info = &lag_work->info.changeupper_info;
+ ice_lag_chk_disabled_bond(lag_work->lag, info);
+ if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) {
+ ice_lag_monitor_link(lag_work->lag, info);
+ ice_lag_changeupper_event(lag_work->lag, info);
+ ice_lag_link_unlink(lag_work->lag, info);
+ }
+ ice_lag_monitor_rdma(lag_work->lag, info);
+ break;
+ case NETDEV_BONDING_INFO:
+ if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) {
+ if (!ice_lag_chk_comp(lag_work->lag,
+ &lag_work->info.bonding_info)) {
+ netdev = lag_work->info.bonding_info.info.dev;
+ ice_lag_disable_sriov_bond(lag_work->lag);
+ ice_lag_unregister(lag_work->lag, netdev);
+ goto lag_cleanup;
+ }
+ ice_lag_monitor_active(lag_work->lag,
+ &lag_work->info.bonding_info);
+ ice_lag_cfg_pf_fltrs(lag_work->lag,
+ &lag_work->info.bonding_info);
+ }
+ ice_lag_info_event(lag_work->lag, &lag_work->info.bonding_info);
+ break;
+ case NETDEV_UNREGISTER:
+ if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) {
+ netdev = lag_work->info.bonding_info.info.dev;
+ if ((netdev == lag_work->lag->netdev ||
+ lag_work->lag->primary) && lag_work->lag->bonded)
+ ice_lag_unregister(lag_work->lag, netdev);
+ }
+ break;
+ default:
+ break;
+ }
+
+lag_cleanup:
+ /* cleanup resources allocated for this work item */
+ list_for_each_safe(tmp, n, &lag_work->netdev_list.node) {
+ struct ice_lag_netdev_list *entry;
+
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ lag_work->lag->netdev_head = NULL;
- if (!netif_is_lag_port(netdev))
- netdev_dbg(netdev, "CHANGELOWER rcvd, but netdev not in LAG. Bail\n");
+ mutex_unlock(&pf->lag_mutex);
+
+ kfree(lag_work);
}
/**
@@ -295,34 +1627,79 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct net_device *upper_netdev;
+ struct ice_lag_work *lag_work;
struct ice_lag *lag;
- lag = container_of(notif_blk, struct ice_lag, notif_block);
+ if (!netif_is_ice(netdev))
+ return NOTIFY_DONE;
+
+ if (event != NETDEV_CHANGEUPPER && event != NETDEV_BONDING_INFO &&
+ event != NETDEV_UNREGISTER)
+ return NOTIFY_DONE;
+
+ if (!(netdev->priv_flags & IFF_BONDING))
+ return NOTIFY_DONE;
+ lag = container_of(notif_blk, struct ice_lag, notif_block);
if (!lag->netdev)
return NOTIFY_DONE;
- /* Check that the netdev is in the working namespace */
if (!net_eq(dev_net(netdev), &init_net))
return NOTIFY_DONE;
+ /* This memory will be freed at the end of ice_lag_process_event */
+ lag_work = kzalloc(sizeof(*lag_work), GFP_KERNEL);
+ if (!lag_work)
+ return -ENOMEM;
+
+ lag_work->event_netdev = netdev;
+ lag_work->lag = lag;
+ lag_work->event = event;
+ if (event == NETDEV_CHANGEUPPER) {
+ struct netdev_notifier_changeupper_info *info;
+
+ info = ptr;
+ upper_netdev = info->upper_dev;
+ } else {
+ upper_netdev = netdev_master_upper_dev_get(netdev);
+ }
+
+ INIT_LIST_HEAD(&lag_work->netdev_list.node);
+ if (upper_netdev) {
+ struct ice_lag_netdev_list *nd_list;
+ struct net_device *tmp_nd;
+
+ rcu_read_lock();
+ for_each_netdev_in_bond_rcu(upper_netdev, tmp_nd) {
+ nd_list = kzalloc(sizeof(*nd_list), GFP_KERNEL);
+ if (!nd_list)
+ break;
+
+ nd_list->netdev = tmp_nd;
+ list_add(&nd_list->node, &lag_work->netdev_list.node);
+ }
+ rcu_read_unlock();
+ }
+
switch (event) {
case NETDEV_CHANGEUPPER:
- ice_lag_changeupper_event(lag, ptr);
- break;
- case NETDEV_CHANGELOWERSTATE:
- ice_lag_changelower_event(lag, ptr);
+ lag_work->info.changeupper_info =
+ *((struct netdev_notifier_changeupper_info *)ptr);
break;
case NETDEV_BONDING_INFO:
- ice_lag_info_event(lag, ptr);
- break;
- case NETDEV_UNREGISTER:
- ice_lag_unregister(lag, netdev);
+ lag_work->info.bonding_info =
+ *((struct netdev_notifier_bonding_info *)ptr);
break;
default:
+ lag_work->info.notifier_info =
+ *((struct netdev_notifier_info *)ptr);
break;
}
+ INIT_WORK(&lag_work->lag_task, ice_lag_process_event);
+ queue_work(ice_lag_wq, &lag_work->lag_task);
+
return NOTIFY_DONE;
}
@@ -366,6 +1743,174 @@ static void ice_unregister_lag_handler(struct ice_lag *lag)
}
/**
+ * ice_create_lag_recipe
+ * @hw: pointer to HW struct
+ * @rid: pointer to u16 to pass back recipe index
+ * @base_recipe: recipe to base the new recipe on
+ * @prio: priority for new recipe
+ *
+ * function returns 0 on error
+ */
+static int ice_create_lag_recipe(struct ice_hw *hw, u16 *rid,
+ const u8 *base_recipe, u8 prio)
+{
+ struct ice_aqc_recipe_data_elem *new_rcp;
+ int err;
+
+ err = ice_alloc_recipe(hw, rid);
+ if (err)
+ return err;
+
+ new_rcp = kzalloc(ICE_RECIPE_LEN * ICE_MAX_NUM_RECIPES, GFP_KERNEL);
+ if (!new_rcp)
+ return -ENOMEM;
+
+ memcpy(new_rcp, base_recipe, ICE_RECIPE_LEN);
+ new_rcp->content.act_ctrl_fwd_priority = prio;
+ new_rcp->content.rid = *rid | ICE_AQ_RECIPE_ID_IS_ROOT;
+ new_rcp->recipe_indx = *rid;
+ bitmap_zero((unsigned long *)new_rcp->recipe_bitmap,
+ ICE_MAX_NUM_RECIPES);
+ set_bit(*rid, (unsigned long *)new_rcp->recipe_bitmap);
+
+ err = ice_aq_add_recipe(hw, new_rcp, 1, NULL);
+ if (err)
+ *rid = 0;
+
+ kfree(new_rcp);
+ return err;
+}
+
+/**
+ * ice_lag_move_vf_nodes_tc_sync - move a VF's nodes for a tc during reset
+ * @lag: primary interfaces lag struct
+ * @dest_hw: HW struct for destination's interface
+ * @vsi_num: VSI index in PF space
+ * @tc: traffic class to move
+ */
+static void
+ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw,
+ u16 vsi_num, u8 tc)
+{
+ u16 numq, valq, buf_size, num_moved, qbuf_size;
+ struct device *dev = ice_pf_to_dev(lag->pf);
+ struct ice_aqc_cfg_txqs_buf *qbuf;
+ struct ice_aqc_move_elem *buf;
+ struct ice_sched_node *n_prt;
+ __le32 teid, parent_teid;
+ struct ice_vsi_ctx *ctx;
+ struct ice_hw *hw;
+ u32 tmp_teid;
+
+ hw = &lag->pf->hw;
+ ctx = ice_get_vsi_ctx(hw, vsi_num);
+ if (!ctx) {
+ dev_warn(dev, "LAG rebuild failed after reset due to VSI Context failure\n");
+ return;
+ }
+
+ if (!ctx->sched.vsi_node[tc])
+ return;
+
+ numq = ctx->num_lan_q_entries[tc];
+ teid = ctx->sched.vsi_node[tc]->info.node_teid;
+ tmp_teid = le32_to_cpu(teid);
+ parent_teid = ctx->sched.vsi_node[tc]->info.parent_teid;
+
+ if (!tmp_teid || !numq)
+ return;
+
+ if (ice_sched_suspend_resume_elems(hw, 1, &tmp_teid, true))
+ dev_dbg(dev, "Problem suspending traffic during reset rebuild\n");
+
+ /* reconfig queues for new port */
+ qbuf_size = struct_size(qbuf, queue_info, numq);
+ qbuf = kzalloc(qbuf_size, GFP_KERNEL);
+ if (!qbuf) {
+ dev_warn(dev, "Failure allocating VF queue recfg buffer for reset rebuild\n");
+ goto resume_sync;
+ }
+
+ /* add the per queue info for the reconfigure command buffer */
+ valq = ice_lag_qbuf_recfg(hw, qbuf, vsi_num, numq, tc);
+ if (!valq) {
+ dev_warn(dev, "Failure to reconfig queues for LAG reset rebuild\n");
+ goto sync_none;
+ }
+
+ if (ice_aq_cfg_lan_txq(hw, qbuf, qbuf_size, numq, hw->port_info->lport,
+ dest_hw->port_info->lport, NULL)) {
+ dev_warn(dev, "Failure to configure queues for LAG reset rebuild\n");
+ goto sync_qerr;
+ }
+
+sync_none:
+ kfree(qbuf);
+
+ /* find parent in destination tree */
+ n_prt = ice_lag_get_sched_parent(dest_hw, tc);
+ if (!n_prt)
+ goto resume_sync;
+
+ /* Move node to new parent */
+ buf_size = struct_size(buf, teid, 1);
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf) {
+ dev_warn(dev, "Failure to alloc for VF node move in reset rebuild\n");
+ goto resume_sync;
+ }
+
+ buf->hdr.src_parent_teid = parent_teid;
+ buf->hdr.dest_parent_teid = n_prt->info.node_teid;
+ buf->hdr.num_elems = cpu_to_le16(1);
+ buf->hdr.mode = ICE_AQC_MOVE_ELEM_MODE_KEEP_OWN;
+ buf->teid[0] = teid;
+
+ if (ice_aq_move_sched_elems(&lag->pf->hw, 1, buf, buf_size, &num_moved,
+ NULL))
+ dev_warn(dev, "Failure to move VF nodes for LAG reset rebuild\n");
+ else
+ ice_sched_update_parent(n_prt, ctx->sched.vsi_node[tc]);
+
+ kfree(buf);
+ goto resume_sync;
+
+sync_qerr:
+ kfree(qbuf);
+
+resume_sync:
+ if (ice_sched_suspend_resume_elems(hw, 1, &tmp_teid, false))
+ dev_warn(dev, "Problem restarting traffic for LAG node reset rebuild\n");
+}
+
+/**
+ * ice_lag_move_vf_nodes_sync - move vf nodes to active interface
+ * @lag: primary interfaces lag struct
+ * @dest_hw: lport value for currently active port
+ *
+ * This function is used in a reset context, outside of event handling,
+ * to move the VF nodes to the secondary interface when that interface
+ * is the active interface during a reset rebuild
+ */
+static void
+ice_lag_move_vf_nodes_sync(struct ice_lag *lag, struct ice_hw *dest_hw)
+{
+ struct ice_pf *pf;
+ int i, tc;
+
+ if (!lag->primary || !dest_hw)
+ return;
+
+ pf = lag->pf;
+ ice_for_each_vsi(pf, i)
+ if (pf->vsi[i] && (pf->vsi[i]->type == ICE_VSI_VF ||
+ pf->vsi[i]->type == ICE_VSI_SWITCHDEV_CTRL))
+ ice_for_each_traffic_class(tc)
+ ice_lag_move_vf_nodes_tc_sync(lag, dest_hw, i,
+ tc);
+}
+
+/**
* ice_init_lag - initialize support for LAG
* @pf: PF struct
*
@@ -377,7 +1922,10 @@ int ice_init_lag(struct ice_pf *pf)
struct device *dev = ice_pf_to_dev(pf);
struct ice_lag *lag;
struct ice_vsi *vsi;
- int err;
+ u64 recipe_bits = 0;
+ int n, err;
+
+ ice_lag_init_feature_support_flag(pf);
pf->lag = kzalloc(sizeof(*lag), GFP_KERNEL);
if (!pf->lag)
@@ -394,8 +1942,8 @@ int ice_init_lag(struct ice_pf *pf)
lag->pf = pf;
lag->netdev = vsi->netdev;
lag->role = ICE_LAG_NONE;
+ lag->active_port = ICE_LAG_INVALID_PORT;
lag->bonded = false;
- lag->peer_netdev = NULL;
lag->upper_netdev = NULL;
lag->notif_block.notifier_call = NULL;
@@ -405,6 +1953,25 @@ int ice_init_lag(struct ice_pf *pf)
goto lag_error;
}
+ err = ice_create_lag_recipe(&pf->hw, &lag->pf_recipe, ice_dflt_vsi_rcp,
+ 1);
+ if (err)
+ goto lag_error;
+
+ /* associate recipes to profiles */
+ for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) {
+ err = ice_aq_get_recipe_to_profile(&pf->hw, n,
+ (u8 *)&recipe_bits, NULL);
+ if (err)
+ continue;
+
+ if (recipe_bits & BIT(ICE_SW_LKUP_DFLT)) {
+ recipe_bits |= BIT(lag->pf_recipe);
+ ice_aq_map_recipe_to_profile(&pf->hw, n,
+ (u8 *)&recipe_bits, NULL);
+ }
+ }
+
ice_display_lag_info(lag);
dev_dbg(dev, "INIT LAG complete\n");
@@ -435,11 +2002,94 @@ void ice_deinit_lag(struct ice_pf *pf)
if (lag->pf)
ice_unregister_lag_handler(lag);
- dev_put(lag->upper_netdev);
+ flush_workqueue(ice_lag_wq);
- dev_put(lag->peer_netdev);
+ ice_free_hw_res(&pf->hw, ICE_AQC_RES_TYPE_RECIPE, 1,
+ &pf->lag->pf_recipe);
kfree(lag);
pf->lag = NULL;
}
+
+/**
+ * ice_lag_rebuild - rebuild lag resources after reset
+ * @pf: pointer to local pf struct
+ *
+ * PF resets are promoted to CORER resets when interface in an aggregate. This
+ * means that we need to rebuild the PF resources for the interface. Since
+ * this will happen outside the normal event processing, need to acquire the lag
+ * lock.
+ *
+ * This function will also evaluate the VF resources if this is the primary
+ * interface.
+ */
+void ice_lag_rebuild(struct ice_pf *pf)
+{
+ struct ice_lag_netdev_list ndlist;
+ struct ice_lag *lag, *prim_lag;
+ struct list_head *tmp, *n;
+ u8 act_port, loc_port;
+
+ if (!pf->lag || !pf->lag->bonded)
+ return;
+
+ mutex_lock(&pf->lag_mutex);
+
+ lag = pf->lag;
+ if (lag->primary) {
+ prim_lag = lag;
+ } else {
+ struct ice_lag_netdev_list *nl;
+ struct net_device *tmp_nd;
+
+ INIT_LIST_HEAD(&ndlist.node);
+ rcu_read_lock();
+ for_each_netdev_in_bond_rcu(lag->upper_netdev, tmp_nd) {
+ nl = kzalloc(sizeof(*nl), GFP_KERNEL);
+ if (!nl)
+ break;
+
+ nl->netdev = tmp_nd;
+ list_add(&nl->node, &ndlist.node);
+ }
+ rcu_read_unlock();
+ lag->netdev_head = &ndlist.node;
+ prim_lag = ice_lag_find_primary(lag);
+ }
+
+ if (!prim_lag) {
+ dev_dbg(ice_pf_to_dev(pf), "No primary interface in aggregate, can't rebuild\n");
+ goto lag_rebuild_out;
+ }
+
+ act_port = prim_lag->active_port;
+ loc_port = lag->pf->hw.port_info->lport;
+
+ /* configure SWID for this port */
+ if (lag->primary) {
+ ice_lag_primary_swid(lag, true);
+ } else {
+ ice_lag_set_swid(prim_lag->pf->hw.port_info->sw_id, lag, true);
+ ice_lag_add_prune_list(prim_lag, pf);
+ if (act_port == loc_port)
+ ice_lag_move_vf_nodes_sync(prim_lag, &pf->hw);
+ }
+
+ ice_lag_cfg_cp_fltr(lag, true);
+
+ if (lag->pf_rule_id)
+ if (ice_lag_cfg_dflt_fltr(lag, true))
+ dev_err(ice_pf_to_dev(pf), "Error adding default VSI rule in rebuild\n");
+
+ ice_clear_rdma_cap(pf);
+lag_rebuild_out:
+ list_for_each_safe(tmp, n, &ndlist.node) {
+ struct ice_lag_netdev_list *entry;
+
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ mutex_unlock(&pf->lag_mutex);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h
index 2c373676c42f..18075b82485a 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.h
+++ b/drivers/net/ethernet/intel/ice/ice_lag.h
@@ -14,20 +14,52 @@ enum ice_lag_role {
ICE_LAG_UNSET
};
+#define ICE_LAG_INVALID_PORT 0xFF
+
+#define ICE_LAG_RESET_RETRIES 5
+
struct ice_pf;
+struct ice_vf;
+
+struct ice_lag_netdev_list {
+ struct list_head node;
+ struct net_device *netdev;
+};
/* LAG info struct */
struct ice_lag {
struct ice_pf *pf; /* backlink to PF struct */
struct net_device *netdev; /* this PF's netdev */
- struct net_device *peer_netdev;
struct net_device *upper_netdev; /* upper bonding netdev */
+ struct list_head *netdev_head;
struct notifier_block notif_block;
+ s32 bond_mode;
+ u16 bond_swid; /* swid for primary interface */
+ u8 active_port; /* lport value for the current active port */
u8 bonded:1; /* currently bonded */
u8 primary:1; /* this is primary */
+ u16 pf_recipe;
+ u16 pf_rule_id;
+ u16 cp_rule_idx;
u8 role;
};
+/* LAG workqueue struct */
+struct ice_lag_work {
+ struct work_struct lag_task;
+ struct ice_lag_netdev_list netdev_list;
+ struct ice_lag *lag;
+ unsigned long event;
+ struct net_device *event_netdev;
+ union {
+ struct netdev_notifier_changeupper_info changeupper_info;
+ struct netdev_notifier_bonding_info bonding_info;
+ struct netdev_notifier_info notifier_info;
+ } info;
+};
+
+void ice_lag_move_new_vf_nodes(struct ice_vf *vf);
int ice_init_lag(struct ice_pf *pf);
void ice_deinit_lag(struct ice_pf *pf);
+void ice_lag_rebuild(struct ice_pf *pf);
#endif /* _ICE_LAG_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 0054d7e64ec3..201570cd2e0b 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -907,6 +907,7 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
{
struct ice_hw_common_caps *cap;
struct ice_pf *pf = vsi->back;
+ u16 max_rss_size;
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
vsi->rss_size = 1;
@@ -914,32 +915,31 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi)
}
cap = &pf->hw.func_caps.common_cap;
+ max_rss_size = BIT(cap->rss_table_entry_width);
switch (vsi->type) {
case ICE_VSI_CHNL:
case ICE_VSI_PF:
/* PF VSI will inherit RSS instance of PF */
vsi->rss_table_size = (u16)cap->rss_table_size;
if (vsi->type == ICE_VSI_CHNL)
- vsi->rss_size = min_t(u16, vsi->num_rxq,
- BIT(cap->rss_table_entry_width));
+ vsi->rss_size = min_t(u16, vsi->num_rxq, max_rss_size);
else
vsi->rss_size = min_t(u16, num_online_cpus(),
- BIT(cap->rss_table_entry_width));
- vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF;
+ max_rss_size);
+ vsi->rss_lut_type = ICE_LUT_PF;
break;
case ICE_VSI_SWITCHDEV_CTRL:
- vsi->rss_table_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
- vsi->rss_size = min_t(u16, num_online_cpus(),
- BIT(cap->rss_table_entry_width));
- vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI;
+ vsi->rss_table_size = ICE_LUT_VSI_SIZE;
+ vsi->rss_size = min_t(u16, num_online_cpus(), max_rss_size);
+ vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_VF:
/* VF VSI will get a small RSS table.
* For VSI_LUT, LUT size should be set to 64 bytes.
*/
- vsi->rss_table_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+ vsi->rss_table_size = ICE_LUT_VSI_SIZE;
vsi->rss_size = ICE_MAX_RSS_QS_PER_VF;
- vsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI;
+ vsi->rss_lut_type = ICE_LUT_VSI;
break;
case ICE_VSI_LB:
break;
@@ -1228,6 +1228,17 @@ ice_chnl_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
}
/**
+ * ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not
+ * @vsi: VSI to check whether or not VLAN pruning is enabled.
+ *
+ * returns true if Rx VLAN pruning is enabled and false otherwise.
+ */
+static bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi)
+{
+ return vsi->info.sw_flags2 & ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
+}
+
+/**
* ice_vsi_init - Create and initialize a VSI
* @vsi: the VSI being configured
* @vsi_flags: VSI configuration flags
@@ -1685,6 +1696,27 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
}
/**
+ * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length
+ * @vsi: VSI
+ */
+static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi)
+{
+ if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) {
+ vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX;
+ vsi->rx_buf_len = ICE_RXBUF_1664;
+#if (PAGE_SIZE < 8192)
+ } else if (!ICE_2K_TOO_SMALL_WITH_PADDING &&
+ (vsi->netdev->mtu <= ETH_DATA_LEN)) {
+ vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN;
+ vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN;
+#endif
+ } else {
+ vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX;
+ vsi->rx_buf_len = ICE_RXBUF_3072;
+ }
+}
+
+/**
* ice_pf_state_is_nominal - checks the PF for nominal state
* @pf: pointer to PF to check
*
@@ -1759,27 +1791,6 @@ void ice_update_eth_stats(struct ice_vsi *vsi)
}
/**
- * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length
- * @vsi: VSI
- */
-void ice_vsi_cfg_frame_size(struct ice_vsi *vsi)
-{
- if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) {
- vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX;
- vsi->rx_buf_len = ICE_RXBUF_1664;
-#if (PAGE_SIZE < 8192)
- } else if (!ICE_2K_TOO_SMALL_WITH_PADDING &&
- (vsi->netdev->mtu <= ETH_DATA_LEN)) {
- vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN;
- vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN;
-#endif
- } else {
- vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX;
- vsi->rx_buf_len = ICE_RXBUF_3072;
- }
-}
-
-/**
* ice_write_qrxflxp_cntxt - write/configure QRXFLXP_CNTXT register
* @hw: HW pointer
* @pf_q: index of the Rx queue in the PF's queue space
@@ -2185,20 +2196,6 @@ bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi)
return false;
}
-/**
- * ice_vsi_is_vlan_pruning_ena - check if VLAN pruning is enabled or not
- * @vsi: VSI to check whether or not VLAN pruning is enabled.
- *
- * returns true if Rx VLAN pruning is enabled and false otherwise.
- */
-bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi)
-{
- if (!vsi)
- return false;
-
- return (vsi->info.sw_flags2 & ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA);
-}
-
static void ice_vsi_set_tc_cfg(struct ice_vsi *vsi)
{
if (!test_bit(ICE_FLAG_DCB_ENA, vsi->back->flags)) {
@@ -2944,21 +2941,6 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi)
}
/**
- * ice_napi_del - Remove NAPI handler for the VSI
- * @vsi: VSI for which NAPI handler is to be removed
- */
-void ice_napi_del(struct ice_vsi *vsi)
-{
- int v_idx;
-
- if (!vsi->netdev)
- return;
-
- ice_for_each_q_vector(vsi, v_idx)
- netif_napi_del(&vsi->q_vectors[v_idx]->napi);
-}
-
-/**
* ice_vsi_release - Delete a VSI and free its resources
* @vsi: the VSI being removed
*
@@ -3970,7 +3952,7 @@ bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f)
* @pf: pointer to the struct ice_pf instance
* @f: feature enum to set
*/
-static void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f)
+void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f)
{
if (f < 0 || f >= ICE_F_MAX)
return;
@@ -4076,3 +4058,28 @@ void ice_vsi_ctx_clear_allow_override(struct ice_vsi_ctx *ctx)
{
ctx->info.sec_flags &= ~ICE_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD;
}
+
+/**
+ * ice_vsi_update_local_lb - update sw block in VSI with local loopback bit
+ * @vsi: pointer to VSI structure
+ * @set: set or unset the bit
+ */
+int
+ice_vsi_update_local_lb(struct ice_vsi *vsi, bool set)
+{
+ struct ice_vsi_ctx ctx = {
+ .info = vsi->info,
+ };
+
+ ctx.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
+ if (set)
+ ctx.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_LOCAL_LB;
+ else
+ ctx.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_LOCAL_LB;
+
+ if (ice_update_vsi(&vsi->back->hw, vsi->idx, &ctx, NULL))
+ return -ENODEV;
+
+ vsi->info = ctx.info;
+ return 0;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index e985766e6bb5..f24f5d1e6f9c 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -76,8 +76,6 @@ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi);
int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi);
-bool ice_vsi_is_vlan_pruning_ena(struct ice_vsi *vsi);
-
void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
int ice_set_link(struct ice_vsi *vsi, bool ena);
@@ -93,8 +91,6 @@ void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc);
struct ice_vsi *
ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params);
-void ice_napi_del(struct ice_vsi *vsi);
-
int ice_vsi_release(struct ice_vsi *vsi);
void ice_vsi_close(struct ice_vsi *vsi);
@@ -130,7 +126,6 @@ void ice_update_tx_ring_stats(struct ice_tx_ring *ring, u64 pkts, u64 bytes);
void ice_update_rx_ring_stats(struct ice_rx_ring *ring, u64 pkts, u64 bytes);
-void ice_vsi_cfg_frame_size(struct ice_vsi *vsi);
void ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl);
void ice_write_itr(struct ice_ring_container *rc, u16 itr);
void ice_set_q_vector_intrl(struct ice_q_vector *q_vector);
@@ -157,11 +152,13 @@ void ice_vsi_ctx_clear_antispoof(struct ice_vsi_ctx *ctx);
void ice_vsi_ctx_set_allow_override(struct ice_vsi_ctx *ctx);
void ice_vsi_ctx_clear_allow_override(struct ice_vsi_ctx *ctx);
+int ice_vsi_update_local_lb(struct ice_vsi *vsi, bool set);
int ice_vsi_add_vlan_zero(struct ice_vsi *vsi);
int ice_vsi_del_vlan_zero(struct ice_vsi *vsi);
bool ice_vsi_has_non_zero_vlans(struct ice_vsi *vsi);
u16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi);
bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f);
+void ice_set_feature_support(struct ice_pf *pf, enum ice_feature f);
void ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f);
void ice_init_feature_support(struct ice_pf *pf);
bool ice_vsi_is_rx_queue_active(struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index b40dfe6ae321..c8286adae946 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -64,6 +64,7 @@ struct device *ice_hw_to_dev(struct ice_hw *hw)
}
static struct workqueue_struct *ice_wq;
+struct workqueue_struct *ice_lag_wq;
static const struct net_device_ops ice_netdev_safe_mode_ops;
static const struct net_device_ops ice_netdev_ops;
@@ -80,7 +81,7 @@ ice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb));
-bool netif_is_ice(struct net_device *dev)
+bool netif_is_ice(const struct net_device *dev)
{
return dev && (dev->netdev_ops == &ice_netdev_ops);
}
@@ -635,6 +636,11 @@ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
dev_dbg(dev, "reset_type 0x%x requested\n", reset_type);
+ if (pf->lag && pf->lag->bonded && reset_type == ICE_RESET_PFR) {
+ dev_dbg(dev, "PFR on a bonded interface, promoting to CORER\n");
+ reset_type = ICE_RESET_CORER;
+ }
+
ice_prepare_for_reset(pf, reset_type);
/* trigger the reset */
@@ -718,8 +724,13 @@ static void ice_reset_subtask(struct ice_pf *pf)
}
/* No pending resets to finish processing. Check for new resets */
- if (test_bit(ICE_PFR_REQ, pf->state))
+ if (test_bit(ICE_PFR_REQ, pf->state)) {
reset_type = ICE_RESET_PFR;
+ if (pf->lag && pf->lag->bonded) {
+ dev_dbg(ice_pf_to_dev(pf), "PFR on a bonded interface, promoting to CORER\n");
+ reset_type = ICE_RESET_CORER;
+ }
+ }
if (test_bit(ICE_CORER_REQ, pf->state))
reset_type = ICE_RESET_CORER;
if (test_bit(ICE_GLOBR_REQ, pf->state))
@@ -1239,64 +1250,63 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
return status;
}
-enum ice_aq_task_state {
- ICE_AQ_TASK_WAITING = 0,
- ICE_AQ_TASK_COMPLETE,
- ICE_AQ_TASK_CANCELED,
-};
-
-struct ice_aq_task {
- struct hlist_node entry;
+/**
+ * ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
+ * @pf: pointer to the PF private structure
+ * @task: intermediate helper storage and identifier for waiting
+ * @opcode: the opcode to wait for
+ *
+ * Prepares to wait for a specific AdminQ completion event on the ARQ for
+ * a given PF. Actual wait would be done by a call to ice_aq_wait_for_event().
+ *
+ * Calls are separated to allow caller registering for event before sending
+ * the command, which mitigates a race between registering and FW responding.
+ *
+ * To obtain only the descriptor contents, pass an task->event with null
+ * msg_buf. If the complete data buffer is desired, allocate the
+ * task->event.msg_buf with enough space ahead of time.
+ */
+void ice_aq_prep_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ u16 opcode)
+{
+ INIT_HLIST_NODE(&task->entry);
+ task->opcode = opcode;
+ task->state = ICE_AQ_TASK_WAITING;
- u16 opcode;
- struct ice_rq_event_info *event;
- enum ice_aq_task_state state;
-};
+ spin_lock_bh(&pf->aq_wait_lock);
+ hlist_add_head(&task->entry, &pf->aq_wait_list);
+ spin_unlock_bh(&pf->aq_wait_lock);
+}
/**
* ice_aq_wait_for_event - Wait for an AdminQ event from firmware
* @pf: pointer to the PF private structure
- * @opcode: the opcode to wait for
+ * @task: ptr prepared by ice_aq_prep_for_event()
* @timeout: how long to wait, in jiffies
- * @event: storage for the event info
*
* Waits for a specific AdminQ completion event on the ARQ for a given PF. The
* current thread will be put to sleep until the specified event occurs or
* until the given timeout is reached.
*
- * To obtain only the descriptor contents, pass an event without an allocated
- * msg_buf. If the complete data buffer is desired, allocate the
- * event->msg_buf with enough space ahead of time.
- *
* Returns: zero on success, or a negative error code on failure.
*/
-int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
- struct ice_rq_event_info *event)
+int ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
+ unsigned long timeout)
{
+ enum ice_aq_task_state *state = &task->state;
struct device *dev = ice_pf_to_dev(pf);
- struct ice_aq_task *task;
- unsigned long start;
+ unsigned long start = jiffies;
long ret;
int err;
- task = kzalloc(sizeof(*task), GFP_KERNEL);
- if (!task)
- return -ENOMEM;
-
- INIT_HLIST_NODE(&task->entry);
- task->opcode = opcode;
- task->event = event;
- task->state = ICE_AQ_TASK_WAITING;
-
- spin_lock_bh(&pf->aq_wait_lock);
- hlist_add_head(&task->entry, &pf->aq_wait_list);
- spin_unlock_bh(&pf->aq_wait_lock);
-
- start = jiffies;
-
- ret = wait_event_interruptible_timeout(pf->aq_wait_queue, task->state,
+ ret = wait_event_interruptible_timeout(pf->aq_wait_queue,
+ *state != ICE_AQ_TASK_WAITING,
timeout);
- switch (task->state) {
+ switch (*state) {
+ case ICE_AQ_TASK_NOT_PREPARED:
+ WARN(1, "call to %s without ice_aq_prep_for_event()", __func__);
+ err = -EINVAL;
+ break;
case ICE_AQ_TASK_WAITING:
err = ret < 0 ? ret : -ETIMEDOUT;
break;
@@ -1307,7 +1317,7 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
err = ret < 0 ? ret : 0;
break;
default:
- WARN(1, "Unexpected AdminQ wait task state %u", task->state);
+ WARN(1, "Unexpected AdminQ wait task state %u", *state);
err = -EINVAL;
break;
}
@@ -1315,12 +1325,11 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
dev_dbg(dev, "Waited %u msecs (max %u msecs) for firmware response to op 0x%04x\n",
jiffies_to_msecs(jiffies - start),
jiffies_to_msecs(timeout),
- opcode);
+ task->opcode);
spin_lock_bh(&pf->aq_wait_lock);
hlist_del(&task->entry);
spin_unlock_bh(&pf->aq_wait_lock);
- kfree(task);
return err;
}
@@ -1346,23 +1355,26 @@ int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
static void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
struct ice_rq_event_info *event)
{
+ struct ice_rq_event_info *task_ev;
struct ice_aq_task *task;
bool found = false;
spin_lock_bh(&pf->aq_wait_lock);
hlist_for_each_entry(task, &pf->aq_wait_list, entry) {
- if (task->state || task->opcode != opcode)
+ if (task->state != ICE_AQ_TASK_WAITING)
+ continue;
+ if (task->opcode != opcode)
continue;
- memcpy(&task->event->desc, &event->desc, sizeof(event->desc));
- task->event->msg_len = event->msg_len;
+ task_ev = &task->event;
+ memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
+ task_ev->msg_len = event->msg_len;
/* Only copy the data buffer if a destination was set */
- if (task->event->msg_buf &&
- task->event->buf_len > event->buf_len) {
- memcpy(task->event->msg_buf, event->msg_buf,
+ if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) {
+ memcpy(task_ev->msg_buf, event->msg_buf,
event->buf_len);
- task->event->buf_len = event->buf_len;
+ task_ev->buf_len = event->buf_len;
}
task->state = ICE_AQ_TASK_COMPLETE;
@@ -3392,6 +3404,7 @@ static void ice_set_ops(struct ice_vsi *vsi)
netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
NETDEV_XDP_ACT_XSK_ZEROCOPY |
NETDEV_XDP_ACT_RX_SG;
+ netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD;
}
/**
@@ -3794,6 +3807,7 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf)
static void ice_deinit_pf(struct ice_pf *pf)
{
ice_service_task_stop(pf);
+ mutex_destroy(&pf->lag_mutex);
mutex_destroy(&pf->adev_mutex);
mutex_destroy(&pf->sw_mutex);
mutex_destroy(&pf->tc_mutex);
@@ -3874,6 +3888,7 @@ static int ice_init_pf(struct ice_pf *pf)
mutex_init(&pf->sw_mutex);
mutex_init(&pf->tc_mutex);
mutex_init(&pf->adev_mutex);
+ mutex_init(&pf->lag_mutex);
INIT_HLIST_HEAD(&pf->aq_wait_list);
spin_lock_init(&pf->aq_wait_lock);
@@ -4506,6 +4521,31 @@ static void ice_deinit_eth(struct ice_pf *pf)
ice_decfg_netdev(vsi);
}
+/**
+ * ice_wait_for_fw - wait for full FW readiness
+ * @hw: pointer to the hardware structure
+ * @timeout: milliseconds that can elapse before timing out
+ */
+static int ice_wait_for_fw(struct ice_hw *hw, u32 timeout)
+{
+ int fw_loading;
+ u32 elapsed = 0;
+
+ while (elapsed <= timeout) {
+ fw_loading = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M;
+
+ /* firmware was not yet loaded, we have to wait more */
+ if (fw_loading) {
+ elapsed += 100;
+ msleep(100);
+ continue;
+ }
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
static int ice_init_dev(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
@@ -4518,6 +4558,18 @@ static int ice_init_dev(struct ice_pf *pf)
return err;
}
+ /* Some cards require longer initialization times
+ * due to necessity of loading FW from an external source.
+ * This can take even half a minute.
+ */
+ if (ice_is_pf_c827(hw)) {
+ err = ice_wait_for_fw(hw, 30000);
+ if (err) {
+ dev_err(dev, "ice_wait_for_fw timed out");
+ return err;
+ }
+ }
+
ice_init_feature_support(pf);
ice_request_fw(pf);
@@ -5570,7 +5622,7 @@ static struct pci_driver ice_driver = {
*/
static int __init ice_module_init(void)
{
- int status;
+ int status = -ENOMEM;
pr_info("%s\n", ice_driver_string);
pr_info("%s\n", ice_copyright);
@@ -5578,15 +5630,27 @@ static int __init ice_module_init(void)
ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME);
if (!ice_wq) {
pr_err("Failed to create workqueue\n");
- return -ENOMEM;
+ return status;
+ }
+
+ ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
+ if (!ice_lag_wq) {
+ pr_err("Failed to create LAG workqueue\n");
+ goto err_dest_wq;
}
status = pci_register_driver(&ice_driver);
if (status) {
pr_err("failed to register PCI driver, err %d\n", status);
- destroy_workqueue(ice_wq);
+ goto err_dest_lag_wq;
}
+ return 0;
+
+err_dest_lag_wq:
+ destroy_workqueue(ice_lag_wq);
+err_dest_wq:
+ destroy_workqueue(ice_wq);
return status;
}
module_init(ice_module_init);
@@ -5601,6 +5665,7 @@ static void __exit ice_module_exit(void)
{
pci_unregister_driver(&ice_driver);
destroy_workqueue(ice_wq);
+ destroy_workqueue(ice_lag_wq);
pr_info("module unloaded\n");
}
module_exit(ice_module_exit);
@@ -5703,7 +5768,7 @@ static void ice_set_rx_mode(struct net_device *netdev)
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
- if (!vsi)
+ if (!vsi || ice_is_switchdev_running(vsi->back))
return;
/* Set the flags to synchronize filters
@@ -6255,7 +6320,7 @@ static void ice_tx_dim_work(struct work_struct *work)
u16 itr;
dim = container_of(work, struct dim, work);
- rc = (struct ice_ring_container *)dim->priv;
+ rc = dim->priv;
WARN_ON(dim->profile_ix >= ARRAY_SIZE(tx_profile));
@@ -6275,7 +6340,7 @@ static void ice_rx_dim_work(struct work_struct *work)
u16 itr;
dim = container_of(work, struct dim, work);
- rc = (struct ice_ring_container *)dim->priv;
+ rc = dim->priv;
WARN_ON(dim->profile_ix >= ARRAY_SIZE(rx_profile));
@@ -7356,6 +7421,8 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
clear_bit(ICE_RESET_FAILED, pf->state);
ice_plug_aux_dev(pf);
+ if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
+ ice_lag_rebuild(pf);
return;
err_vsi_rebuild:
diff --git a/drivers/net/ethernet/intel/ice/ice_protocol_type.h b/drivers/net/ethernet/intel/ice/ice_protocol_type.h
index 6a9364761165..f6f27361c3cf 100644
--- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h
@@ -287,6 +287,7 @@ struct ice_nvgre_hdr {
* M = EVLAN (0x8100) - Outer L2 header has EVLAN (ethernet type 0x8100)
* N = EVLAN (0x9100) - Outer L2 header has EVLAN (ethernet type 0x9100)
*/
+#define ICE_PKT_FROM_NETWORK BIT(3)
#define ICE_PKT_VLAN_STAG BIT(12)
#define ICE_PKT_VLAN_ITAG BIT(13)
#define ICE_PKT_VLAN_EVLAN (BIT(14) | BIT(15))
@@ -392,10 +393,10 @@ enum ice_hw_metadata_offset {
};
enum ice_pkt_flags {
- ICE_PKT_FLAGS_VLAN = 0,
- ICE_PKT_FLAGS_TUNNEL = 1,
- ICE_PKT_FLAGS_TCP = 2,
- ICE_PKT_FLAGS_ERROR = 3,
+ ICE_PKT_FLAGS_MDID20 = 0,
+ ICE_PKT_FLAGS_MDID21 = 1,
+ ICE_PKT_FLAGS_MDID22 = 2,
+ ICE_PKT_FLAGS_MDID23 = 3,
};
struct ice_hw_metadata {
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index a38614d21ea8..f818dd215c05 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -131,6 +131,8 @@ static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
case READ_TIME:
cmd_val |= GLTSYN_CMD_READ_TIME;
break;
+ case ICE_PTP_NOP:
+ break;
}
wr32(hw, GLTSYN_CMD, cmd_val);
@@ -293,7 +295,7 @@ static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
*
* Read a PHY register for the given port over the device sideband queue.
*/
-int
+static int
ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
{
struct ice_sbq_msg_input msg = {0};
@@ -370,7 +372,7 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
*
* Write a PHY register for the given port over the device sideband queue.
*/
-int
+static int
ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
{
struct ice_sbq_msg_input msg = {0};
@@ -1079,7 +1081,7 @@ exit_err:
*
* Negative adjustments are supported using 2s complement arithmetic.
*/
-int
+static int
ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
{
u32 l_time, u_time;
@@ -1226,18 +1228,18 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
}
/**
- * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command
+ * ice_ptp_write_port_cmd_e822 - Prepare a single PHY port for a timer command
* @hw: pointer to HW struct
* @port: Port to which cmd has to be sent
* @cmd: Command to be sent to the port
*
* Prepare the requested port for an upcoming timer sync command.
*
- * Note there is no equivalent of this operation on E810, as that device
- * always handles all external PHYs internally.
+ * Do not use this function directly. If you want to configure exactly one
+ * port, use ice_ptp_one_port_cmd() instead.
*/
static int
-ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
+ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
{
u32 cmd_val, val;
u8 tmr_idx;
@@ -1261,6 +1263,8 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
case ADJ_TIME_AT_TIME:
cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
break;
+ case ICE_PTP_NOP:
+ break;
}
/* Tx case */
@@ -1307,6 +1311,39 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
}
/**
+ * ice_ptp_one_port_cmd - Prepare one port for a timer command
+ * @hw: pointer to the HW struct
+ * @configured_port: the port to configure with configured_cmd
+ * @configured_cmd: timer command to prepare on the configured_port
+ *
+ * Prepare the configured_port for the configured_cmd, and prepare all other
+ * ports for ICE_PTP_NOP. This causes the configured_port to execute the
+ * desired command while all other ports perform no operation.
+ */
+static int
+ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
+ enum ice_ptp_tmr_cmd configured_cmd)
+{
+ u8 port;
+
+ for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
+ enum ice_ptp_tmr_cmd cmd;
+ int err;
+
+ if (port == configured_port)
+ cmd = configured_cmd;
+ else
+ cmd = ICE_PTP_NOP;
+
+ err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
* ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
* @hw: pointer to the HW struct
* @cmd: timer command to prepare
@@ -1322,7 +1359,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
int err;
- err = ice_ptp_one_port_cmd(hw, port, cmd);
+ err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
if (err)
return err;
}
@@ -2252,6 +2289,9 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
if (err)
goto err_unlock;
+ /* Do not perform any action on the main timer */
+ ice_ptp_src_cmd(hw, ICE_PTP_NOP);
+
/* Issue the sync to activate the time adjustment */
ice_ptp_exec_tmr_cmd(hw);
@@ -2372,6 +2412,9 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
if (err)
return err;
+ /* Do not perform any action on the main timer */
+ ice_ptp_src_cmd(hw, ICE_PTP_NOP);
+
ice_ptp_exec_tmr_cmd(hw);
err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
@@ -2847,6 +2890,8 @@ static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
case ADJ_TIME_AT_TIME:
cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
break;
+ case ICE_PTP_NOP:
+ return 0;
}
/* Read, modify, write */
@@ -2869,6 +2914,185 @@ static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
return 0;
}
+/**
+ * ice_get_phy_tx_tstamp_ready_e810 - Read Tx memory status register
+ * @hw: pointer to the HW struct
+ * @port: the PHY port to read
+ * @tstamp_ready: contents of the Tx memory status register
+ *
+ * E810 devices do not use a Tx memory status register. Instead simply
+ * indicate that all timestamps are currently ready.
+ */
+static int
+ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
+{
+ *tstamp_ready = 0xFFFFFFFFFFFFFFFF;
+ return 0;
+}
+
+/* E810T SMA functions
+ *
+ * The following functions operate specifically on E810T hardware and are used
+ * to access the extended GPIOs available.
+ */
+
+/**
+ * ice_get_pca9575_handle
+ * @hw: pointer to the hw struct
+ * @pca9575_handle: GPIO controller's handle
+ *
+ * Find and return the GPIO controller's handle in the netlist.
+ * When found - the value will be cached in the hw structure and following calls
+ * will return cached value
+ */
+static int
+ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
+{
+ struct ice_aqc_get_link_topo *cmd;
+ struct ice_aq_desc desc;
+ int status;
+ u8 idx;
+
+ /* If handle was read previously return cached value */
+ if (hw->io_expander_handle) {
+ *pca9575_handle = hw->io_expander_handle;
+ return 0;
+ }
+
+ /* If handle was not detected read it from the netlist */
+ cmd = &desc.params.get_link_topo;
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
+
+ /* Set node type to GPIO controller */
+ cmd->addr.topo_params.node_type_ctx =
+ (ICE_AQC_LINK_TOPO_NODE_TYPE_M &
+ ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
+
+#define SW_PCA9575_SFP_TOPO_IDX 2
+#define SW_PCA9575_QSFP_TOPO_IDX 1
+
+ /* Check if the SW IO expander controlling SMA exists in the netlist. */
+ if (hw->device_id == ICE_DEV_ID_E810C_SFP)
+ idx = SW_PCA9575_SFP_TOPO_IDX;
+ else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
+ idx = SW_PCA9575_QSFP_TOPO_IDX;
+ else
+ return -EOPNOTSUPP;
+
+ cmd->addr.topo_params.index = idx;
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+ if (status)
+ return -EOPNOTSUPP;
+
+ /* Verify if we found the right IO expander type */
+ if (desc.params.get_link_topo.node_part_num !=
+ ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
+ return -EOPNOTSUPP;
+
+ /* If present save the handle and return it */
+ hw->io_expander_handle =
+ le16_to_cpu(desc.params.get_link_topo.addr.handle);
+ *pca9575_handle = hw->io_expander_handle;
+
+ return 0;
+}
+
+/**
+ * ice_read_sma_ctrl_e810t
+ * @hw: pointer to the hw struct
+ * @data: pointer to data to be read from the GPIO controller
+ *
+ * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
+ * PCA9575 expander, so only bits 3-7 in data are valid.
+ */
+int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
+{
+ int status;
+ u16 handle;
+ u8 i;
+
+ status = ice_get_pca9575_handle(hw, &handle);
+ if (status)
+ return status;
+
+ *data = 0;
+
+ for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
+ bool pin;
+
+ status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
+ &pin, NULL);
+ if (status)
+ break;
+ *data |= (u8)(!pin) << i;
+ }
+
+ return status;
+}
+
+/**
+ * ice_write_sma_ctrl_e810t
+ * @hw: pointer to the hw struct
+ * @data: data to be written to the GPIO controller
+ *
+ * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
+ * of the PCA9575 expander, so only bits 3-7 in data are valid.
+ */
+int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
+{
+ int status;
+ u16 handle;
+ u8 i;
+
+ status = ice_get_pca9575_handle(hw, &handle);
+ if (status)
+ return status;
+
+ for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
+ bool pin;
+
+ pin = !(data & (1 << i));
+ status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
+ pin, NULL);
+ if (status)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * ice_read_pca9575_reg_e810t
+ * @hw: pointer to the hw struct
+ * @offset: GPIO controller register offset
+ * @data: pointer to data to be read from the GPIO controller
+ *
+ * Read the register from the GPIO controller
+ */
+int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data)
+{
+ struct ice_aqc_link_topo_addr link_topo;
+ __le16 addr;
+ u16 handle;
+ int err;
+
+ memset(&link_topo, 0, sizeof(link_topo));
+
+ err = ice_get_pca9575_handle(hw, &handle);
+ if (err)
+ return err;
+
+ link_topo.handle = cpu_to_le16(handle);
+ link_topo.topo_params.node_type_ctx =
+ FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
+ ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED);
+
+ addr = cpu_to_le16((u16)offset);
+
+ return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
+}
+
/* Device agnostic functions
*
* The following functions implement shared behavior common to both E822 and
@@ -3130,204 +3354,6 @@ int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
}
/**
- * ice_get_phy_tx_tstamp_ready_e810 - Read Tx memory status register
- * @hw: pointer to the HW struct
- * @port: the PHY port to read
- * @tstamp_ready: contents of the Tx memory status register
- *
- * E810 devices do not use a Tx memory status register. Instead simply
- * indicate that all timestamps are currently ready.
- */
-static int
-ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
-{
- *tstamp_ready = 0xFFFFFFFFFFFFFFFF;
- return 0;
-}
-
-/* E810T SMA functions
- *
- * The following functions operate specifically on E810T hardware and are used
- * to access the extended GPIOs available.
- */
-
-/**
- * ice_get_pca9575_handle
- * @hw: pointer to the hw struct
- * @pca9575_handle: GPIO controller's handle
- *
- * Find and return the GPIO controller's handle in the netlist.
- * When found - the value will be cached in the hw structure and following calls
- * will return cached value
- */
-static int
-ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
-{
- struct ice_aqc_get_link_topo *cmd;
- struct ice_aq_desc desc;
- int status;
- u8 idx;
-
- /* If handle was read previously return cached value */
- if (hw->io_expander_handle) {
- *pca9575_handle = hw->io_expander_handle;
- return 0;
- }
-
- /* If handle was not detected read it from the netlist */
- cmd = &desc.params.get_link_topo;
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
-
- /* Set node type to GPIO controller */
- cmd->addr.topo_params.node_type_ctx =
- (ICE_AQC_LINK_TOPO_NODE_TYPE_M &
- ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
-
-#define SW_PCA9575_SFP_TOPO_IDX 2
-#define SW_PCA9575_QSFP_TOPO_IDX 1
-
- /* Check if the SW IO expander controlling SMA exists in the netlist. */
- if (hw->device_id == ICE_DEV_ID_E810C_SFP)
- idx = SW_PCA9575_SFP_TOPO_IDX;
- else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
- idx = SW_PCA9575_QSFP_TOPO_IDX;
- else
- return -EOPNOTSUPP;
-
- cmd->addr.topo_params.index = idx;
-
- status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
- if (status)
- return -EOPNOTSUPP;
-
- /* Verify if we found the right IO expander type */
- if (desc.params.get_link_topo.node_part_num !=
- ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
- return -EOPNOTSUPP;
-
- /* If present save the handle and return it */
- hw->io_expander_handle =
- le16_to_cpu(desc.params.get_link_topo.addr.handle);
- *pca9575_handle = hw->io_expander_handle;
-
- return 0;
-}
-
-/**
- * ice_read_sma_ctrl_e810t
- * @hw: pointer to the hw struct
- * @data: pointer to data to be read from the GPIO controller
- *
- * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
- * PCA9575 expander, so only bits 3-7 in data are valid.
- */
-int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
-{
- int status;
- u16 handle;
- u8 i;
-
- status = ice_get_pca9575_handle(hw, &handle);
- if (status)
- return status;
-
- *data = 0;
-
- for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
- bool pin;
-
- status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
- &pin, NULL);
- if (status)
- break;
- *data |= (u8)(!pin) << i;
- }
-
- return status;
-}
-
-/**
- * ice_write_sma_ctrl_e810t
- * @hw: pointer to the hw struct
- * @data: data to be written to the GPIO controller
- *
- * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
- * of the PCA9575 expander, so only bits 3-7 in data are valid.
- */
-int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
-{
- int status;
- u16 handle;
- u8 i;
-
- status = ice_get_pca9575_handle(hw, &handle);
- if (status)
- return status;
-
- for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
- bool pin;
-
- pin = !(data & (1 << i));
- status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
- pin, NULL);
- if (status)
- break;
- }
-
- return status;
-}
-
-/**
- * ice_read_pca9575_reg_e810t
- * @hw: pointer to the hw struct
- * @offset: GPIO controller register offset
- * @data: pointer to data to be read from the GPIO controller
- *
- * Read the register from the GPIO controller
- */
-int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data)
-{
- struct ice_aqc_link_topo_addr link_topo;
- __le16 addr;
- u16 handle;
- int err;
-
- memset(&link_topo, 0, sizeof(link_topo));
-
- err = ice_get_pca9575_handle(hw, &handle);
- if (err)
- return err;
-
- link_topo.handle = cpu_to_le16(handle);
- link_topo.topo_params.node_type_ctx =
- FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
- ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED);
-
- addr = cpu_to_le16((u16)offset);
-
- return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
-}
-
-/**
- * ice_is_pca9575_present
- * @hw: pointer to the hw struct
- *
- * Check if the SW IO expander is present in the netlist
- */
-bool ice_is_pca9575_present(struct ice_hw *hw)
-{
- u16 handle = 0;
- int status;
-
- if (!ice_is_e810t(hw))
- return false;
-
- status = ice_get_pca9575_handle(hw, &handle);
-
- return !status && handle;
-}
-
-/**
* ice_ptp_reset_ts_memory - Reset timestamp memory for all blocks
* @hw: pointer to the HW struct
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 3b68cb91bd81..9aa10b0426fd 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -9,7 +9,8 @@ enum ice_ptp_tmr_cmd {
INIT_INCVAL,
ADJ_TIME,
ADJ_TIME_AT_TIME,
- READ_TIME
+ READ_TIME,
+ ICE_PTP_NOP,
};
enum ice_ptp_serdes {
@@ -112,6 +113,9 @@ struct ice_cgu_pll_params_e822 {
extern const struct
ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ];
+#define E810C_QSFP_C827_0_HANDLE 2
+#define E810C_QSFP_C827_1_HANDLE 3
+
/* Table of constants related to possible TIME_REF sources */
extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ];
@@ -138,11 +142,8 @@ int ice_ptp_init_phc(struct ice_hw *hw);
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready);
/* E822 family functions */
-int ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val);
-int ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val);
int ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val);
int ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val);
-int ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time);
void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad);
/**
@@ -196,7 +197,6 @@ int ice_ptp_init_phy_e810(struct ice_hw *hw);
int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data);
int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data);
-bool ice_is_pca9575_present(struct ice_hw *hw);
#define PFTSYN_SEM_BYTES 4
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c
index e30e12321abd..c686ac0935eb 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.c
+++ b/drivers/net/ethernet/intel/ice/ice_repr.c
@@ -254,7 +254,7 @@ static const struct net_device_ops ice_repr_netdev_ops = {
* ice_is_port_repr_netdev - Check if a given netdevice is a port representor netdev
* @netdev: pointer to netdev
*/
-bool ice_is_port_repr_netdev(struct net_device *netdev)
+bool ice_is_port_repr_netdev(const struct net_device *netdev)
{
return netdev && (netdev->netdev_ops == &ice_repr_netdev_ops);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h
index 9c2a6f496b3b..e1ee2d2c1d2d 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.h
+++ b/drivers/net/ethernet/intel/ice/ice_repr.h
@@ -12,6 +12,7 @@ struct ice_repr {
struct ice_q_vector *q_vector;
struct net_device *netdev;
struct metadata_dst *dst;
+ struct ice_esw_br_port *br_port;
#ifdef CONFIG_ICE_SWITCHDEV
/* info about slow path rule */
struct ice_rule_query_data sp_rule;
@@ -27,5 +28,5 @@ void ice_repr_stop_tx_queues(struct ice_repr *repr);
void ice_repr_set_traffic_vsi(struct ice_repr *repr, struct ice_vsi *vsi);
struct ice_repr *ice_netdev_to_repr(struct net_device *netdev);
-bool ice_is_port_repr_netdev(struct net_device *netdev);
+bool ice_is_port_repr_netdev(const struct net_device *netdev);
#endif
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index b664d60fd037..c0533d7b66b9 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -447,7 +447,7 @@ ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req,
*
* Move scheduling elements (0x0408)
*/
-static int
+int
ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
struct ice_aqc_move_elem *buf, u16 buf_size,
u16 *grps_movd, struct ice_sq_cd *cd)
@@ -526,7 +526,7 @@ ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
*
* This function suspends or resumes HW nodes
*/
-static int
+int
ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
bool suspend)
{
@@ -569,18 +569,24 @@ ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
{
struct ice_vsi_ctx *vsi_ctx;
struct ice_q_ctx *q_ctx;
+ u16 idx;
vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
if (!vsi_ctx)
return -EINVAL;
/* allocate LAN queue contexts */
if (!vsi_ctx->lan_q_ctx[tc]) {
- vsi_ctx->lan_q_ctx[tc] = devm_kcalloc(ice_hw_to_dev(hw),
- new_numqs,
- sizeof(*q_ctx),
- GFP_KERNEL);
- if (!vsi_ctx->lan_q_ctx[tc])
+ q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
+ sizeof(*q_ctx), GFP_KERNEL);
+ if (!q_ctx)
return -ENOMEM;
+
+ for (idx = 0; idx < new_numqs; idx++) {
+ q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE;
+ q_ctx[idx].q_teid = ICE_INVAL_TEID;
+ }
+
+ vsi_ctx->lan_q_ctx[tc] = q_ctx;
vsi_ctx->num_lan_q_entries[tc] = new_numqs;
return 0;
}
@@ -592,9 +598,16 @@ ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
sizeof(*q_ctx), GFP_KERNEL);
if (!q_ctx)
return -ENOMEM;
+
memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc],
prev_num * sizeof(*q_ctx));
devm_kfree(ice_hw_to_dev(hw), vsi_ctx->lan_q_ctx[tc]);
+
+ for (idx = prev_num; idx < new_numqs; idx++) {
+ q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE;
+ q_ctx[idx].q_teid = ICE_INVAL_TEID;
+ }
+
vsi_ctx->lan_q_ctx[tc] = q_ctx;
vsi_ctx->num_lan_q_entries[tc] = new_numqs;
}
@@ -1044,7 +1057,7 @@ ice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi,
*
* This function add nodes to a given layer.
*/
-static int
+int
ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
struct ice_sched_node *tc_node,
struct ice_sched_node *parent, u8 layer,
@@ -1119,7 +1132,7 @@ static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)
*
* This function returns the current VSI layer number
*/
-static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
+u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
{
/* Num Layers VSI layer
* 9 6
@@ -1142,7 +1155,7 @@ static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
*
* This function returns the current aggregator layer number
*/
-static u8 ice_sched_get_agg_layer(struct ice_hw *hw)
+u8 ice_sched_get_agg_layer(struct ice_hw *hw)
{
/* Num Layers aggregator layer
* 9 4
@@ -1577,7 +1590,7 @@ ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
* This function retrieves an aggregator node for a given aggregator ID from
* a given TC branch
*/
-static struct ice_sched_node *
+struct ice_sched_node *
ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
u32 agg_id)
{
@@ -2139,7 +2152,7 @@ ice_get_agg_info(struct ice_hw *hw, u32 agg_id)
* This function walks through the aggregator subtree to find a free parent
* node
*/
-static struct ice_sched_node *
+struct ice_sched_node *
ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
u16 *num_nodes)
{
@@ -3958,7 +3971,7 @@ ice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id,
* This function sets BW limit of VSI or Aggregator scheduling node
* based on TC information from passed in argument BW.
*/
-int
+static int
ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id,
enum ice_agg_type agg_type, u8 tc,
enum ice_rl_type rl_type, u32 bw)
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h
index 9c100747445a..0055d9330c07 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.h
+++ b/drivers/net/ethernet/intel/ice/ice_sched.h
@@ -141,13 +141,30 @@ ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
int
ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
enum ice_rl_type rl_type);
-int
-ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id,
- enum ice_agg_type agg_type, u8 tc,
- enum ice_rl_type rl_type, u32 bw);
int ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes);
+int
+ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
+ bool suspend);
+struct ice_sched_node *
+ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
+ u32 agg_id);
+u8 ice_sched_get_agg_layer(struct ice_hw *hw);
+u8 ice_sched_get_vsi_layer(struct ice_hw *hw);
+struct ice_sched_node *
+ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
+ u16 *num_nodes);
+int
+ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
+ struct ice_sched_node *tc_node,
+ struct ice_sched_node *parent, u8 layer,
+ u16 num_nodes, u32 *first_node_teid,
+ u16 *num_nodes_added);
void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw);
void ice_sched_replay_agg(struct ice_hw *hw);
+int
+ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
+ struct ice_aqc_move_elem *buf, u16 buf_size,
+ u16 *grps_movd, struct ice_sq_cd *cd);
int ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle);
int ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx);
#endif /* _ICE_SCHED_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index 1f66914c7a20..31314e7540f8 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -1131,7 +1131,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena)
if (!vf)
return -EINVAL;
- ret = ice_check_vf_ready_for_reset(vf);
+ ret = ice_check_vf_ready_for_cfg(vf);
if (ret)
goto out_put_vf;
@@ -1246,7 +1246,7 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
goto out_put_vf;
}
- ret = ice_check_vf_ready_for_reset(vf);
+ ret = ice_check_vf_ready_for_cfg(vf);
if (ret)
goto out_put_vf;
@@ -1300,7 +1300,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
return -EOPNOTSUPP;
}
- ret = ice_check_vf_ready_for_reset(vf);
+ ret = ice_check_vf_ready_for_cfg(vf);
if (ret)
goto out_put_vf;
@@ -1613,7 +1613,7 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos,
if (!vf)
return -EINVAL;
- ret = ice_check_vf_ready_for_reset(vf);
+ ret = ice_check_vf_ready_for_cfg(vf);
if (ret)
goto out_put_vf;
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 6db4ca7978cb..2f77b684ff76 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -20,12 +20,11 @@
* byte 0 = 0x2: to identify it as locally administered DA MAC
* byte 6 = 0x2: to identify it as locally administered SA MAC
* byte 12 = 0x81 & byte 13 = 0x00:
- * In case of VLAN filter first two bytes defines ether type (0x8100)
- * and remaining two bytes are placeholder for programming a given VLAN ID
- * In case of Ether type filter it is treated as header without VLAN tag
- * and byte 12 and 13 is used to program a given Ether type instead
+ * In case of VLAN filter first two bytes defines ether type (0x8100)
+ * and remaining two bytes are placeholder for programming a given VLAN ID
+ * In case of Ether type filter it is treated as header without VLAN tag
+ * and byte 12 and 13 is used to program a given Ether type instead
*/
-#define DUMMY_ETH_HDR_LEN 16
static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
0x2, 0, 0, 0, 0, 0,
0x81, 0, 0, 0};
@@ -1369,14 +1368,6 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
ICE_PKT_PROFILE(tcp, 0),
};
-#define ICE_SW_RULE_RX_TX_HDR_SIZE(s, l) struct_size((s), hdr_data, (l))
-#define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s) \
- ICE_SW_RULE_RX_TX_HDR_SIZE((s), DUMMY_ETH_HDR_LEN)
-#define ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s) \
- ICE_SW_RULE_RX_TX_HDR_SIZE((s), 0)
-#define ICE_SW_RULE_LG_ACT_SIZE(s, n) struct_size((s), act, (n))
-#define ICE_SW_RULE_VSI_LIST_SIZE(s, n) struct_size((s), vsi, (n))
-
/* this is a recipe to profile association bitmap */
static DECLARE_BITMAP(recipe_to_profile[ICE_MAX_NUM_RECIPES],
ICE_MAX_NUM_PROFILES);
@@ -1841,8 +1832,13 @@ ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
lkup_type == ICE_SW_LKUP_DFLT) {
sw_buf->res_type = cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_REP);
} else if (lkup_type == ICE_SW_LKUP_VLAN) {
- sw_buf->res_type =
- cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
+ if (opc == ice_aqc_opc_alloc_res)
+ sw_buf->res_type =
+ cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE |
+ ICE_AQC_RES_TYPE_FLAG_SHARED);
+ else
+ sw_buf->res_type =
+ cpu_to_le16(ICE_AQC_RES_TYPE_VSI_LIST_PRUNE);
} else {
status = -EINVAL;
goto ice_aq_alloc_free_vsi_list_exit;
@@ -1851,7 +1847,7 @@ ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
if (opc == ice_aqc_opc_free_res)
sw_buf->elem[0].e.sw_resp = cpu_to_le16(*vsi_list_id);
- status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len, opc, NULL);
+ status = ice_aq_alloc_free_res(hw, sw_buf, buf_len, opc);
if (status)
goto ice_aq_alloc_free_vsi_list_exit;
@@ -1910,7 +1906,7 @@ ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
*
* Add(0x0290)
*/
-static int
+int
ice_aq_add_recipe(struct ice_hw *hw,
struct ice_aqc_recipe_data_elem *s_recipe_list,
u16 num_recipes, struct ice_sq_cd *cd)
@@ -1947,7 +1943,7 @@ ice_aq_add_recipe(struct ice_hw *hw,
* The caller must supply enough space in s_recipe_list to hold all possible
* recipes and *num_recipes must equal ICE_MAX_NUM_RECIPES.
*/
-static int
+int
ice_aq_get_recipe(struct ice_hw *hw,
struct ice_aqc_recipe_data_elem *s_recipe_list,
u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd)
@@ -2040,7 +2036,7 @@ error_out:
* @cd: pointer to command details structure or NULL
* Recipe to profile association (0x0291)
*/
-static int
+int
ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
struct ice_sq_cd *cd)
{
@@ -2066,7 +2062,7 @@ ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
* @cd: pointer to command details structure or NULL
* Associate profile ID with given recipe (0x0293)
*/
-static int
+int
ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
struct ice_sq_cd *cd)
{
@@ -2090,7 +2086,7 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
* @hw: pointer to the hardware structure
* @rid: recipe ID returned as response to AQ call
*/
-static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
+int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
{
struct ice_aqc_alloc_free_res_elem *sw_buf;
u16 buf_len;
@@ -2105,8 +2101,8 @@ static int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
ICE_AQC_RES_TYPE_S) |
ICE_AQC_RES_TYPE_FLAG_SHARED);
- status = ice_aq_alloc_free_res(hw, 1, sw_buf, buf_len,
- ice_aqc_opc_alloc_res, NULL);
+ status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
+ ice_aqc_opc_alloc_res);
if (!status)
*rid = le16_to_cpu(sw_buf->elem[0].e.sw_resp);
kfree(sw_buf);
@@ -2272,6 +2268,10 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
/* Propagate some data to the recipe database */
recps[idx].is_root = !!is_root;
recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
+ recps[idx].need_pass_l2 = root_bufs.content.act_ctrl &
+ ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
+ recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl &
+ ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
recps[idx].chain_idx = root_bufs.content.result_indx &
@@ -2460,6 +2460,15 @@ static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)
}
/**
+ * ice_fill_eth_hdr - helper to copy dummy_eth_hdr into supplied buffer
+ * @eth_hdr: pointer to buffer to populate
+ */
+void ice_fill_eth_hdr(u8 *eth_hdr)
+{
+ memcpy(eth_hdr, dummy_eth_header, DUMMY_ETH_HDR_LEN);
+}
+
+/**
* ice_fill_sw_rule - Helper function to fill switch rule structure
* @hw: pointer to the hardware structure
* @f_info: entry containing packet forwarding information
@@ -3118,7 +3127,7 @@ ice_find_rule_entry(struct ice_hw *hw, u8 recp_id, struct ice_fltr_info *f_info)
* handle element. This can be extended further to search VSI list with more
* than 1 vsi_count. Returns pointer to VSI list entry if found.
*/
-static struct ice_vsi_list_map_info *
+struct ice_vsi_list_map_info *
ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
u16 *vsi_list_id)
{
@@ -3129,7 +3138,7 @@ ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
list_head = &sw->recp_list[recp_id].filt_rules;
list_for_each_entry(list_itr, list_head, list_entry) {
- if (list_itr->vsi_count == 1 && list_itr->vsi_list_info) {
+ if (list_itr->vsi_list_info) {
map_info = list_itr->vsi_list_info;
if (test_bit(vsi_handle, map_info->vsi_map)) {
*vsi_list_id = map_info->vsi_list_id;
@@ -3400,54 +3409,6 @@ exit:
}
/**
- * ice_mac_fltr_exist - does this MAC filter exist for given VSI
- * @hw: pointer to the hardware structure
- * @mac: MAC address to be checked (for MAC filter)
- * @vsi_handle: check MAC filter for this VSI
- */
-bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle)
-{
- struct ice_fltr_mgmt_list_entry *entry;
- struct list_head *rule_head;
- struct ice_switch_info *sw;
- struct mutex *rule_lock; /* Lock to protect filter rule list */
- u16 hw_vsi_id;
-
- if (!ice_is_vsi_valid(hw, vsi_handle))
- return false;
-
- hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle);
- sw = hw->switch_info;
- rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
- if (!rule_head)
- return false;
-
- rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
- mutex_lock(rule_lock);
- list_for_each_entry(entry, rule_head, list_entry) {
- struct ice_fltr_info *f_info = &entry->fltr_info;
- u8 *mac_addr = &f_info->l_data.mac.mac_addr[0];
-
- if (is_zero_ether_addr(mac_addr))
- continue;
-
- if (f_info->flag != ICE_FLTR_TX ||
- f_info->src_id != ICE_SRC_ID_VSI ||
- f_info->lkup_type != ICE_SW_LKUP_MAC ||
- f_info->fltr_act != ICE_FWD_TO_VSI ||
- hw_vsi_id != f_info->fwd_id.hw_vsi_id)
- continue;
-
- if (ether_addr_equal(mac, mac_addr)) {
- mutex_unlock(rule_lock);
- return true;
- }
- }
- mutex_unlock(rule_lock);
- return false;
-}
-
-/**
* ice_vlan_fltr_exist - does this VLAN filter exist for given VSI
* @hw: pointer to the hardware structure
* @vlan_id: VLAN ID
@@ -4487,8 +4448,7 @@ ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
ICE_AQC_RES_TYPE_M) | alloc_shared);
- status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
- ice_aqc_opc_alloc_res, NULL);
+ status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
if (status)
goto exit;
@@ -4526,8 +4486,7 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
ICE_AQC_RES_TYPE_M) | alloc_shared);
buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
- status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
- ice_aqc_opc_free_res, NULL);
+ status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
if (status)
ice_debug(hw, ICE_DBG_SW, "counter resource could not be freed\n");
@@ -4540,6 +4499,45 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
.offs = {__VA_ARGS__}, \
}
+/**
+ * ice_share_res - set a resource as shared or dedicated
+ * @hw: hw struct of original owner of resource
+ * @type: resource type
+ * @shared: is the resource being set to shared
+ * @res_id: resource id (descriptor)
+ */
+int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id)
+{
+ struct ice_aqc_alloc_free_res_elem *buf;
+ u16 buf_len;
+ int status;
+
+ buf_len = struct_size(buf, elem, 1);
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf->num_elems = cpu_to_le16(1);
+ if (shared)
+ buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
+ ICE_AQC_RES_TYPE_M) |
+ ICE_AQC_RES_TYPE_FLAG_SHARED);
+ else
+ buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
+ ICE_AQC_RES_TYPE_M) &
+ ~ICE_AQC_RES_TYPE_FLAG_SHARED);
+
+ buf->elem[0].e.sw_resp = cpu_to_le16(res_id);
+ status = ice_aq_alloc_free_res(hw, buf, buf_len,
+ ice_aqc_opc_share_res);
+ if (status)
+ ice_debug(hw, ICE_DBG_SW, "Could not set resource type %u id %u to %s\n",
+ type, res_id, shared ? "SHARED" : "DEDICATED");
+
+ kfree(buf);
+ return status;
+}
+
/* This is mapping table entry that maps every word within a given protocol
* structure to the real byte offset as per the specification of that
* protocol header.
@@ -4613,13 +4611,13 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
* ice_find_recp - find a recipe
* @hw: pointer to the hardware structure
* @lkup_exts: extension sequence to match
- * @tun_type: type of recipe tunnel
+ * @rinfo: information regarding the rule e.g. priority and action info
*
* Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
*/
static u16
ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
- enum ice_sw_tunnel_type tun_type)
+ const struct ice_adv_rule_info *rinfo)
{
bool refresh_required = true;
struct ice_sw_recipe *recp;
@@ -4680,9 +4678,12 @@ ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
}
/* If for "i"th recipe the found was never set to false
* then it means we found our match
- * Also tun type of recipe needs to be checked
+ * Also tun type and *_pass_l2 of recipe needs to be
+ * checked
*/
- if (found && recp[i].tun_type == tun_type)
+ if (found && recp[i].tun_type == rinfo->tun_type &&
+ recp[i].need_pass_l2 == rinfo->need_pass_l2 &&
+ recp[i].allow_pass_l2 == rinfo->allow_pass_l2)
return i; /* Return the recipe ID */
}
}
@@ -4952,6 +4953,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
unsigned long *profiles)
{
DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
+ struct ice_aqc_recipe_content *content;
struct ice_aqc_recipe_data_elem *tmp;
struct ice_aqc_recipe_data_elem *buf;
struct ice_recp_grp_entry *entry;
@@ -5012,6 +5014,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
if (status)
goto err_unroll;
+ content = &buf[recps].content;
+
/* Clear the result index of the located recipe, as this will be
* updated, if needed, later in the recipe creation process.
*/
@@ -5022,26 +5026,24 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
/* if the recipe is a non-root recipe RID should be programmed
* as 0 for the rules to be applied correctly.
*/
- buf[recps].content.rid = 0;
- memset(&buf[recps].content.lkup_indx, 0,
- sizeof(buf[recps].content.lkup_indx));
+ content->rid = 0;
+ memset(&content->lkup_indx, 0,
+ sizeof(content->lkup_indx));
/* All recipes use look-up index 0 to match switch ID. */
- buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
- buf[recps].content.mask[0] =
- cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
+ content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
+ content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
* to be 0
*/
for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
- buf[recps].content.lkup_indx[i] = 0x80;
- buf[recps].content.mask[i] = 0;
+ content->lkup_indx[i] = 0x80;
+ content->mask[i] = 0;
}
for (i = 0; i < entry->r_group.n_val_pairs; i++) {
- buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
- buf[recps].content.mask[i + 1] =
- cpu_to_le16(entry->fv_mask[i]);
+ content->lkup_indx[i + 1] = entry->fv_idx[i];
+ content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]);
}
if (rm->n_grp_count > 1) {
@@ -5055,7 +5057,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
}
entry->chain_idx = chain_idx;
- buf[recps].content.result_indx =
+ content->result_indx =
ICE_AQ_RECIPE_RESULT_EN |
((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
ICE_AQ_RECIPE_RESULT_DATA_M);
@@ -5069,7 +5071,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
ICE_MAX_NUM_RECIPES);
set_bit(buf[recps].recipe_indx,
(unsigned long *)buf[recps].recipe_bitmap);
- buf[recps].content.act_ctrl_fwd_priority = rm->priority;
+ content->act_ctrl_fwd_priority = rm->priority;
+
+ if (rm->need_pass_l2)
+ content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
+
+ if (rm->allow_pass_l2)
+ content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
recps++;
}
@@ -5107,9 +5115,11 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
if (status)
goto err_unroll;
+ content = &buf[recps].content;
+
buf[recps].recipe_indx = (u8)rid;
- buf[recps].content.rid = (u8)rid;
- buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
+ content->rid = (u8)rid;
+ content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
/* the new entry created should also be part of rg_list to
* make sure we have complete recipe
*/
@@ -5121,16 +5131,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
goto err_unroll;
}
last_chain_entry->rid = rid;
- memset(&buf[recps].content.lkup_indx, 0,
- sizeof(buf[recps].content.lkup_indx));
+ memset(&content->lkup_indx, 0, sizeof(content->lkup_indx));
/* All recipes use look-up index 0 to match switch ID. */
- buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
- buf[recps].content.mask[0] =
- cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
+ content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
+ content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
- buf[recps].content.lkup_indx[i] =
- ICE_AQ_RECIPE_LKUP_IGNORE;
- buf[recps].content.mask[i] = 0;
+ content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE;
+ content->mask[i] = 0;
}
i = 1;
@@ -5142,8 +5149,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
list_for_each_entry(entry, &rm->rg_list, l_entry) {
last_chain_entry->fv_idx[i] = entry->chain_idx;
- buf[recps].content.lkup_indx[i] = entry->chain_idx;
- buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
+ content->lkup_indx[i] = entry->chain_idx;
+ content->mask[i++] = cpu_to_le16(0xFFFF);
set_bit(entry->rid, rm->r_bitmap);
}
list_add(&last_chain_entry->l_entry, &rm->rg_list);
@@ -5155,7 +5162,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
status = -EINVAL;
goto err_unroll;
}
- buf[recps].content.act_ctrl_fwd_priority = rm->priority;
+ content->act_ctrl_fwd_priority = rm->priority;
recps++;
rm->root_rid = (u8)rid;
@@ -5220,6 +5227,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
recp->n_grp_count = rm->n_grp_count;
recp->tun_type = rm->tun_type;
+ recp->need_pass_l2 = rm->need_pass_l2;
+ recp->allow_pass_l2 = rm->allow_pass_l2;
recp->recp_created = true;
}
rm->root_buf = buf;
@@ -5388,6 +5397,9 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
/* set the recipe priority if specified */
rm->priority = (u8)rinfo->priority;
+ rm->need_pass_l2 = rinfo->need_pass_l2;
+ rm->allow_pass_l2 = rinfo->allow_pass_l2;
+
/* Find offsets from the field vector. Pick the first one for all the
* recipes.
*/
@@ -5403,7 +5415,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
}
/* Look for a recipe which matches our requested fv / mask list */
- *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type);
+ *rid = ice_find_recp(hw, lkup_exts, rinfo);
if (*rid < ICE_MAX_NUM_RECIPES)
/* Success if found a recipe that match the existing criteria */
goto err_unroll;
@@ -5839,7 +5851,9 @@ static bool ice_rules_equal(const struct ice_adv_rule_info *first,
return first->sw_act.flag == second->sw_act.flag &&
first->tun_type == second->tun_type &&
first->vlan_type == second->vlan_type &&
- first->src_vsi == second->src_vsi;
+ first->src_vsi == second->src_vsi &&
+ first->need_pass_l2 == second->need_pass_l2 &&
+ first->allow_pass_l2 == second->allow_pass_l2;
}
/**
@@ -5994,14 +6008,21 @@ ice_adv_add_update_vsi_list(struct ice_hw *hw,
void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup)
{
lkup->type = ICE_HW_METADATA;
- lkup->m_u.metadata.flags[ICE_PKT_FLAGS_TUNNEL] =
+ lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID21] |=
cpu_to_be16(ICE_PKT_TUNNEL_MASK);
}
+void ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup)
+{
+ lkup->type = ICE_HW_METADATA;
+ lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
+ cpu_to_be16(ICE_PKT_FROM_NETWORK);
+}
+
void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup)
{
lkup->type = ICE_HW_METADATA;
- lkup->m_u.metadata.flags[ICE_PKT_FLAGS_VLAN] =
+ lkup->m_u.metadata.flags[ICE_PKT_FLAGS_MDID20] |=
cpu_to_be16(ICE_PKT_VLAN_MASK);
}
@@ -6078,7 +6099,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
- rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) {
+ rinfo->sw_act.fltr_act == ICE_DROP_PACKET ||
+ rinfo->sw_act.fltr_act == ICE_NOP)) {
status = -EIO;
goto free_pkt_profile;
}
@@ -6089,7 +6111,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
goto free_pkt_profile;
}
- if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
+ if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
+ rinfo->sw_act.fltr_act == ICE_NOP)
rinfo->sw_act.fwd_id.hw_vsi_id =
ice_get_hw_vsi_num(hw, vsi_handle);
@@ -6159,6 +6182,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
ICE_SINGLE_ACT_VALID_BIT;
break;
+ case ICE_NOP:
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+ rinfo->sw_act.fwd_id.hw_vsi_id);
+ act &= ~ICE_SINGLE_ACT_VALID_BIT;
+ break;
default:
status = -EIO;
goto err_ice_add_adv_rule;
@@ -6439,7 +6467,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
return -EIO;
}
- rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type);
+ rid = ice_find_recp(hw, &lkup_exts, rinfo);
/* If did not find a recipe that match the existing criteria */
if (rid == ICE_MAX_NUM_RECIPES)
return -EINVAL;
@@ -6533,59 +6561,6 @@ ice_rem_adv_rule_by_id(struct ice_hw *hw,
}
/**
- * ice_rem_adv_rule_for_vsi - removes existing advanced switch rules for a
- * given VSI handle
- * @hw: pointer to the hardware structure
- * @vsi_handle: VSI handle for which we are supposed to remove all the rules.
- *
- * This function is used to remove all the rules for a given VSI and as soon
- * as removing a rule fails, it will return immediately with the error code,
- * else it will return success.
- */
-int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle)
-{
- struct ice_adv_fltr_mgmt_list_entry *list_itr, *tmp_entry;
- struct ice_vsi_list_map_info *map_info;
- struct ice_adv_rule_info rinfo;
- struct list_head *list_head;
- struct ice_switch_info *sw;
- int status;
- u8 rid;
-
- sw = hw->switch_info;
- for (rid = 0; rid < ICE_MAX_NUM_RECIPES; rid++) {
- if (!sw->recp_list[rid].recp_created)
- continue;
- if (!sw->recp_list[rid].adv_rule)
- continue;
-
- list_head = &sw->recp_list[rid].filt_rules;
- list_for_each_entry_safe(list_itr, tmp_entry, list_head,
- list_entry) {
- rinfo = list_itr->rule_info;
-
- if (rinfo.sw_act.fltr_act == ICE_FWD_TO_VSI_LIST) {
- map_info = list_itr->vsi_list_info;
- if (!map_info)
- continue;
-
- if (!test_bit(vsi_handle, map_info->vsi_map))
- continue;
- } else if (rinfo.sw_act.vsi_handle != vsi_handle) {
- continue;
- }
-
- rinfo.sw_act.vsi_handle = vsi_handle;
- status = ice_rem_adv_rule(hw, list_itr->lkups,
- list_itr->lkups_cnt, &rinfo);
- if (status)
- return status;
- }
- }
- return 0;
-}
-
-/**
* ice_replay_vsi_adv_rule - Replay advanced rule for requested VSI
* @hw: pointer to the hardware structure
* @vsi_handle: driver VSI handle
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h
index c84b56fe84a5..db7e501b7e0a 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.h
+++ b/drivers/net/ethernet/intel/ice/ice_switch.h
@@ -22,6 +22,16 @@
#define ICE_PROFID_IPV6_GTPU_TEID 46
#define ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER 70
+#define ICE_SW_RULE_VSI_LIST_SIZE(s, n) struct_size((s), vsi, (n))
+#define ICE_SW_RULE_RX_TX_HDR_SIZE(s, l) struct_size((s), hdr_data, (l))
+#define ICE_SW_RULE_RX_TX_ETH_HDR_SIZE(s) \
+ ICE_SW_RULE_RX_TX_HDR_SIZE((s), DUMMY_ETH_HDR_LEN)
+#define ICE_SW_RULE_RX_TX_NO_HDR_SIZE(s) \
+ ICE_SW_RULE_RX_TX_HDR_SIZE((s), 0)
+#define ICE_SW_RULE_LG_ACT_SIZE(s, n) struct_size((s), act, (n))
+
+#define DUMMY_ETH_HDR_LEN 16
+
/* VSI context structure for add/get/update/free operations */
struct ice_vsi_ctx {
u16 vsi_num;
@@ -191,6 +201,8 @@ struct ice_adv_rule_info {
u16 vlan_type;
u16 fltr_rule_id;
u32 priority;
+ u16 need_pass_l2:1;
+ u16 allow_pass_l2:1;
u16 src_vsi;
struct ice_sw_act_ctrl sw_act;
struct ice_adv_rule_flags_info flags_info;
@@ -254,6 +266,9 @@ struct ice_sw_recipe {
*/
u8 priority;
+ u8 need_pass_l2:1;
+ u8 allow_pass_l2:1;
+
struct list_head rg_list;
/* AQ buffer associated with this recipe */
@@ -340,9 +355,11 @@ ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
int
ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
u16 counter_id);
+int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id);
/* Switch/bridge related commands */
void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup);
+void ice_rule_add_direction_metadata(struct ice_adv_lkup_elem *lkup);
void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup);
void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup);
int
@@ -354,7 +371,6 @@ int ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);
int ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list);
int ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
int ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
-bool ice_mac_fltr_exist(struct ice_hw *hw, u8 *mac, u16 vsi_handle);
bool ice_vlan_fltr_exist(struct ice_hw *hw, u16 vlan_id, u16 vsi_handle);
int ice_add_eth_mac(struct ice_hw *hw, struct list_head *em_list);
int ice_remove_eth_mac(struct ice_hw *hw, struct list_head *em_list);
@@ -379,7 +395,6 @@ int
ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
bool rm_vlan_promisc);
-int ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle);
int
ice_rem_adv_rule_by_id(struct ice_hw *hw,
struct ice_rule_query_data *remove_entry);
@@ -389,6 +404,7 @@ u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
int ice_replay_vsi_all_fltr(struct ice_hw *hw, u16 vsi_handle);
void ice_rm_all_sw_replay_rule_info(struct ice_hw *hw);
+void ice_fill_eth_hdr(u8 *eth_hdr);
int
ice_aq_sw_rules(struct ice_hw *hw, void *rule_list, u16 rule_list_sz,
@@ -397,4 +413,21 @@ int
ice_update_recipe_lkup_idx(struct ice_hw *hw,
struct ice_update_recipe_lkup_idx_params *params);
void ice_change_proto_id_to_dvm(void);
+struct ice_vsi_list_map_info *
+ice_find_vsi_list_entry(struct ice_hw *hw, u8 recp_id, u16 vsi_handle,
+ u16 *vsi_list_id);
+int ice_alloc_recipe(struct ice_hw *hw, u16 *rid);
+int ice_aq_get_recipe(struct ice_hw *hw,
+ struct ice_aqc_recipe_data_elem *s_recipe_list,
+ u16 *num_recipes, u16 recipe_root, struct ice_sq_cd *cd);
+int ice_aq_add_recipe(struct ice_hw *hw,
+ struct ice_aqc_recipe_data_elem *s_recipe_list,
+ u16 num_recipes, struct ice_sq_cd *cd);
+int
+ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
+ struct ice_sq_cd *cd);
+int
+ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
+ struct ice_sq_cd *cd);
+
#endif /* _ICE_SWITCH_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
index 4a34ef5f58d3..37b54db91df2 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
@@ -7,6 +7,8 @@
#include "ice_lib.h"
#include "ice_protocol_type.h"
+#define ICE_TC_METADATA_LKUP_IDX 0
+
/**
* ice_tc_count_lkups - determine lookup count for switch filter
* @flags: TC-flower flags
@@ -19,7 +21,13 @@ static int
ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
struct ice_tc_flower_fltr *fltr)
{
- int lkups_cnt = 0;
+ int lkups_cnt = 1; /* 0th lookup is metadata */
+
+ /* Always add metadata as the 0th lookup. Included elements:
+ * - Direction flag (always present)
+ * - ICE_TC_FLWR_FIELD_VLAN_TPID (present if specified)
+ * - Tunnel flag (present if tunnel)
+ */
if (flags & ICE_TC_FLWR_FIELD_TENANT_ID)
lkups_cnt++;
@@ -54,10 +62,6 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
if (flags & (ICE_TC_FLWR_FIELD_VLAN | ICE_TC_FLWR_FIELD_VLAN_PRIO))
lkups_cnt++;
- /* is VLAN TPID specified */
- if (flags & ICE_TC_FLWR_FIELD_VLAN_TPID)
- lkups_cnt++;
-
/* is CVLAN specified? */
if (flags & (ICE_TC_FLWR_FIELD_CVLAN | ICE_TC_FLWR_FIELD_CVLAN_PRIO))
lkups_cnt++;
@@ -84,10 +88,6 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
ICE_TC_FLWR_FIELD_SRC_L4_PORT))
lkups_cnt++;
- /* matching for tunneled packets in metadata */
- if (fltr->tunnel_type != TNL_LAST)
- lkups_cnt++;
-
return lkups_cnt;
}
@@ -176,10 +176,9 @@ static u16 ice_check_supported_vlan_tpid(u16 vlan_tpid)
static int
ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
- struct ice_adv_lkup_elem *list)
+ struct ice_adv_lkup_elem *list, int i)
{
struct ice_tc_flower_lyr_2_4_hdrs *hdr = &fltr->outer_headers;
- int i = 0;
if (flags & ICE_TC_FLWR_FIELD_TENANT_ID) {
u32 tenant_id;
@@ -329,8 +328,7 @@ ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
}
/* always fill matching on tunneled packets in metadata */
- ice_rule_add_tunnel_metadata(&list[i]);
- i++;
+ ice_rule_add_tunnel_metadata(&list[ICE_TC_METADATA_LKUP_IDX]);
return i;
}
@@ -358,13 +356,16 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
struct ice_tc_flower_lyr_2_4_hdrs *headers = &tc_fltr->outer_headers;
bool inner = false;
u16 vlan_tpid = 0;
- int i = 0;
+ int i = 1; /* 0th lookup is metadata */
rule_info->vlan_type = vlan_tpid;
+ /* Always add direction metadata */
+ ice_rule_add_direction_metadata(&list[ICE_TC_METADATA_LKUP_IDX]);
+
rule_info->tun_type = ice_sw_type_from_tunnel(tc_fltr->tunnel_type);
if (tc_fltr->tunnel_type != TNL_LAST) {
- i = ice_tc_fill_tunnel_outer(flags, tc_fltr, list);
+ i = ice_tc_fill_tunnel_outer(flags, tc_fltr, list, i);
headers = &tc_fltr->inner_headers;
inner = true;
@@ -431,8 +432,7 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
rule_info->vlan_type =
ice_check_supported_vlan_tpid(vlan_tpid);
- ice_rule_add_vlan_metadata(&list[i]);
- i++;
+ ice_rule_add_vlan_metadata(&list[ICE_TC_METADATA_LKUP_IDX]);
}
if (flags & (ICE_TC_FLWR_FIELD_CVLAN | ICE_TC_FLWR_FIELD_CVLAN_PRIO)) {
@@ -1343,24 +1343,24 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
dissector = rule->match.dissector;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_CVLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) |
- BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_PPPOE) |
- BIT(FLOW_DISSECTOR_KEY_L2TPV3))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_OPTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PPPOE) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_L2TPV3))) {
NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported key used");
return -EOPNOTSUPP;
}
@@ -1382,10 +1382,10 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
*/
headers = &fltr->inner_headers;
} else if (dissector->used_keys &
- (BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS))) {
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS))) {
NL_SET_ERR_MSG_MOD(fltr->extack, "Tunnel key used, but device isn't a tunnel");
return -EOPNOTSUPP;
} else {
diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h
index ae98d5a8ff60..b2f5c9fe0149 100644
--- a/drivers/net/ethernet/intel/ice/ice_trace.h
+++ b/drivers/net/ethernet/intel/ice/ice_trace.h
@@ -21,6 +21,7 @@
#define _ICE_TRACE_H_
#include <linux/tracepoint.h>
+#include "ice_eswitch_br.h"
/* ice_trace() macro enables shared code to refer to trace points
* like:
@@ -240,6 +241,95 @@ DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_req);
DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_done);
DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_complete);
+DECLARE_EVENT_CLASS(ice_esw_br_fdb_template,
+ TP_PROTO(struct ice_esw_br_fdb_entry *fdb),
+ TP_ARGS(fdb),
+ TP_STRUCT__entry(__array(char, dev_name, IFNAMSIZ)
+ __array(unsigned char, addr, ETH_ALEN)
+ __field(u16, vid)
+ __field(int, flags)),
+ TP_fast_assign(strscpy(__entry->dev_name,
+ netdev_name(fdb->dev),
+ IFNAMSIZ);
+ memcpy(__entry->addr, fdb->data.addr, ETH_ALEN);
+ __entry->vid = fdb->data.vid;
+ __entry->flags = fdb->flags;),
+ TP_printk("net_device=%s addr=%pM vid=%u flags=%x",
+ __entry->dev_name,
+ __entry->addr,
+ __entry->vid,
+ __entry->flags)
+);
+
+DEFINE_EVENT(ice_esw_br_fdb_template,
+ ice_eswitch_br_fdb_entry_create,
+ TP_PROTO(struct ice_esw_br_fdb_entry *fdb),
+ TP_ARGS(fdb)
+);
+
+DEFINE_EVENT(ice_esw_br_fdb_template,
+ ice_eswitch_br_fdb_entry_find_and_delete,
+ TP_PROTO(struct ice_esw_br_fdb_entry *fdb),
+ TP_ARGS(fdb)
+);
+
+DECLARE_EVENT_CLASS(ice_esw_br_vlan_template,
+ TP_PROTO(struct ice_esw_br_vlan *vlan),
+ TP_ARGS(vlan),
+ TP_STRUCT__entry(__field(u16, vid)
+ __field(u16, flags)),
+ TP_fast_assign(__entry->vid = vlan->vid;
+ __entry->flags = vlan->flags;),
+ TP_printk("vid=%u flags=%x",
+ __entry->vid,
+ __entry->flags)
+);
+
+DEFINE_EVENT(ice_esw_br_vlan_template,
+ ice_eswitch_br_vlan_create,
+ TP_PROTO(struct ice_esw_br_vlan *vlan),
+ TP_ARGS(vlan)
+);
+
+DEFINE_EVENT(ice_esw_br_vlan_template,
+ ice_eswitch_br_vlan_cleanup,
+ TP_PROTO(struct ice_esw_br_vlan *vlan),
+ TP_ARGS(vlan)
+);
+
+#define ICE_ESW_BR_PORT_NAME_L 16
+
+DECLARE_EVENT_CLASS(ice_esw_br_port_template,
+ TP_PROTO(struct ice_esw_br_port *port),
+ TP_ARGS(port),
+ TP_STRUCT__entry(__field(u16, vport_num)
+ __array(char, port_type, ICE_ESW_BR_PORT_NAME_L)),
+ TP_fast_assign(__entry->vport_num = port->vsi_idx;
+ if (port->type == ICE_ESWITCH_BR_UPLINK_PORT)
+ strscpy(__entry->port_type,
+ "Uplink",
+ ICE_ESW_BR_PORT_NAME_L);
+ else
+ strscpy(__entry->port_type,
+ "VF Representor",
+ ICE_ESW_BR_PORT_NAME_L);),
+ TP_printk("vport_num=%u port type=%s",
+ __entry->vport_num,
+ __entry->port_type)
+);
+
+DEFINE_EVENT(ice_esw_br_port_template,
+ ice_eswitch_br_port_link,
+ TP_PROTO(struct ice_esw_br_port *port),
+ TP_ARGS(port)
+);
+
+DEFINE_EVENT(ice_esw_br_port_template,
+ ice_eswitch_br_port_unlink,
+ TP_PROTO(struct ice_esw_br_port *port),
+ TP_ARGS(port)
+);
+
/* End tracepoints */
#endif /* _ICE_TRACE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index a09556e57803..5e353b0cbe6f 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -277,6 +277,8 @@ struct ice_hw_common_caps {
u8 dcb;
u8 ieee_1588;
u8 rdma;
+ u8 roce_lag;
+ u8 sriov_lag;
bool nvm_update_pending_nvm;
bool nvm_update_pending_orom;
@@ -1033,14 +1035,15 @@ enum ice_sw_fwd_act_type {
ICE_FWD_TO_Q,
ICE_FWD_TO_QGRP,
ICE_DROP_PACKET,
+ ICE_NOP,
ICE_INVAL_ACT
};
struct ice_aq_get_set_rss_lut_params {
- u16 vsi_handle; /* software VSI handle */
- u16 lut_size; /* size of the LUT buffer */
- u8 lut_type; /* type of the LUT (i.e. VSI, PF, Global) */
u8 *lut; /* input RSS LUT for set and output RSS LUT for get */
+ enum ice_lut_size lut_size; /* size of the LUT buffer */
+ enum ice_lut_type lut_type; /* type of the LUT (i.e. VSI, PF, Global) */
+ u16 vsi_handle; /* software VSI handle */
u8 global_lut_id; /* only valid when lut_type is global */
};
@@ -1142,9 +1145,6 @@ struct ice_aq_get_set_rss_lut_params {
#define ICE_SR_WORDS_IN_1KB 512
-/* Hash redirection LUT for VSI - maximum array size */
-#define ICE_VSIQF_HLUT_ARRAY_SIZE ((VSIQF_HLUT_MAX_INDEX + 1) * 4)
-
/* AQ API version for LLDP_FILTER_CONTROL */
#define ICE_FW_API_LLDP_FLTR_MAJ 1
#define ICE_FW_API_LLDP_FLTR_MIN 7
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index b26ce4425f45..24e4f4d897b6 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -186,25 +186,6 @@ int ice_check_vf_ready_for_cfg(struct ice_vf *vf)
}
/**
- * ice_check_vf_ready_for_reset - check if VF is ready to be reset
- * @vf: VF to check if it's ready to be reset
- *
- * The purpose of this function is to ensure that the VF is not in reset,
- * disabled, and is both initialized and active, thus enabling us to safely
- * initialize another reset.
- */
-int ice_check_vf_ready_for_reset(struct ice_vf *vf)
-{
- int ret;
-
- ret = ice_check_vf_ready_for_cfg(vf);
- if (!ret && !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
- ret = -EAGAIN;
-
- return ret;
-}
-
-/**
* ice_trigger_vf_reset - Reset a VF on HW
* @vf: pointer to the VF structure
* @is_vflr: true if VFLR was issued, false if not
@@ -323,6 +304,237 @@ static int ice_vf_rebuild_vsi(struct ice_vf *vf)
}
/**
+ * ice_vf_rebuild_host_vlan_cfg - add VLAN 0 filter or rebuild the Port VLAN
+ * @vf: VF to add MAC filters for
+ * @vsi: Pointer to VSI
+ *
+ * Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
+ * always re-adds either a VLAN 0 or port VLAN based filter after reset.
+ */
+static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf, struct ice_vsi *vsi)
+{
+ struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
+ struct device *dev = ice_pf_to_dev(vf->pf);
+ int err;
+
+ if (ice_vf_is_port_vlan_ena(vf)) {
+ err = vlan_ops->set_port_vlan(vsi, &vf->port_vlan_info);
+ if (err) {
+ dev_err(dev, "failed to configure port VLAN via VSI parameters for VF %u, error %d\n",
+ vf->vf_id, err);
+ return err;
+ }
+
+ err = vlan_ops->add_vlan(vsi, &vf->port_vlan_info);
+ } else {
+ err = ice_vsi_add_vlan_zero(vsi);
+ }
+
+ if (err) {
+ dev_err(dev, "failed to add VLAN %u filter for VF %u during VF rebuild, error %d\n",
+ ice_vf_is_port_vlan_ena(vf) ?
+ ice_vf_get_port_vlan_id(vf) : 0, vf->vf_id, err);
+ return err;
+ }
+
+ err = vlan_ops->ena_rx_filtering(vsi);
+ if (err)
+ dev_warn(dev, "failed to enable Rx VLAN filtering for VF %d VSI %d during VF rebuild, error %d\n",
+ vf->vf_id, vsi->idx, err);
+
+ return 0;
+}
+
+/**
+ * ice_vf_rebuild_host_tx_rate_cfg - re-apply the Tx rate limiting configuration
+ * @vf: VF to re-apply the configuration for
+ *
+ * Called after a VF VSI has been re-added/rebuild during reset. The PF driver
+ * needs to re-apply the host configured Tx rate limiting configuration.
+ */
+static int ice_vf_rebuild_host_tx_rate_cfg(struct ice_vf *vf)
+{
+ struct device *dev = ice_pf_to_dev(vf->pf);
+ struct ice_vsi *vsi = ice_get_vf_vsi(vf);
+ int err;
+
+ if (WARN_ON(!vsi))
+ return -EINVAL;
+
+ if (vf->min_tx_rate) {
+ err = ice_set_min_bw_limit(vsi, (u64)vf->min_tx_rate * 1000);
+ if (err) {
+ dev_err(dev, "failed to set min Tx rate to %d Mbps for VF %u, error %d\n",
+ vf->min_tx_rate, vf->vf_id, err);
+ return err;
+ }
+ }
+
+ if (vf->max_tx_rate) {
+ err = ice_set_max_bw_limit(vsi, (u64)vf->max_tx_rate * 1000);
+ if (err) {
+ dev_err(dev, "failed to set max Tx rate to %d Mbps for VF %u, error %d\n",
+ vf->max_tx_rate, vf->vf_id, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vf_set_host_trust_cfg - set trust setting based on pre-reset value
+ * @vf: VF to configure trust setting for
+ */
+static void ice_vf_set_host_trust_cfg(struct ice_vf *vf)
+{
+ assign_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps, vf->trusted);
+}
+
+/**
+ * ice_vf_rebuild_host_mac_cfg - add broadcast and the VF's perm_addr/LAA
+ * @vf: VF to add MAC filters for
+ *
+ * Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
+ * always re-adds a broadcast filter and the VF's perm_addr/LAA after reset.
+ */
+static int ice_vf_rebuild_host_mac_cfg(struct ice_vf *vf)
+{
+ struct device *dev = ice_pf_to_dev(vf->pf);
+ struct ice_vsi *vsi = ice_get_vf_vsi(vf);
+ u8 broadcast[ETH_ALEN];
+ int status;
+
+ if (WARN_ON(!vsi))
+ return -EINVAL;
+
+ if (ice_is_eswitch_mode_switchdev(vf->pf))
+ return 0;
+
+ eth_broadcast_addr(broadcast);
+ status = ice_fltr_add_mac(vsi, broadcast, ICE_FWD_TO_VSI);
+ if (status) {
+ dev_err(dev, "failed to add broadcast MAC filter for VF %u, error %d\n",
+ vf->vf_id, status);
+ return status;
+ }
+
+ vf->num_mac++;
+
+ if (is_valid_ether_addr(vf->hw_lan_addr)) {
+ status = ice_fltr_add_mac(vsi, vf->hw_lan_addr,
+ ICE_FWD_TO_VSI);
+ if (status) {
+ dev_err(dev, "failed to add default unicast MAC filter %pM for VF %u, error %d\n",
+ &vf->hw_lan_addr[0], vf->vf_id,
+ status);
+ return status;
+ }
+ vf->num_mac++;
+
+ ether_addr_copy(vf->dev_lan_addr, vf->hw_lan_addr);
+ }
+
+ return 0;
+}
+
+/**
+ * ice_vf_rebuild_aggregator_node_cfg - rebuild aggregator node config
+ * @vsi: Pointer to VSI
+ *
+ * This function moves VSI into corresponding scheduler aggregator node
+ * based on cached value of "aggregator node info" per VSI
+ */
+static void ice_vf_rebuild_aggregator_node_cfg(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct device *dev;
+ int status;
+
+ if (!vsi->agg_node)
+ return;
+
+ dev = ice_pf_to_dev(pf);
+ if (vsi->agg_node->num_vsis == ICE_MAX_VSIS_IN_AGG_NODE) {
+ dev_dbg(dev,
+ "agg_id %u already has reached max_num_vsis %u\n",
+ vsi->agg_node->agg_id, vsi->agg_node->num_vsis);
+ return;
+ }
+
+ status = ice_move_vsi_to_agg(pf->hw.port_info, vsi->agg_node->agg_id,
+ vsi->idx, vsi->tc_cfg.ena_tc);
+ if (status)
+ dev_dbg(dev, "unable to move VSI idx %u into aggregator %u node",
+ vsi->idx, vsi->agg_node->agg_id);
+ else
+ vsi->agg_node->num_vsis++;
+}
+
+/**
+ * ice_vf_rebuild_host_cfg - host admin configuration is persistent across reset
+ * @vf: VF to rebuild host configuration on
+ */
+static void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
+{
+ struct device *dev = ice_pf_to_dev(vf->pf);
+ struct ice_vsi *vsi = ice_get_vf_vsi(vf);
+
+ if (WARN_ON(!vsi))
+ return;
+
+ ice_vf_set_host_trust_cfg(vf);
+
+ if (ice_vf_rebuild_host_mac_cfg(vf))
+ dev_err(dev, "failed to rebuild default MAC configuration for VF %d\n",
+ vf->vf_id);
+
+ if (ice_vf_rebuild_host_vlan_cfg(vf, vsi))
+ dev_err(dev, "failed to rebuild VLAN configuration for VF %u\n",
+ vf->vf_id);
+
+ if (ice_vf_rebuild_host_tx_rate_cfg(vf))
+ dev_err(dev, "failed to rebuild Tx rate limiting configuration for VF %u\n",
+ vf->vf_id);
+
+ if (ice_vsi_apply_spoofchk(vsi, vf->spoofchk))
+ dev_err(dev, "failed to rebuild spoofchk configuration for VF %d\n",
+ vf->vf_id);
+
+ /* rebuild aggregator node config for main VF VSI */
+ ice_vf_rebuild_aggregator_node_cfg(vsi);
+}
+
+/**
+ * ice_set_vf_state_qs_dis - Set VF queues state to disabled
+ * @vf: pointer to the VF structure
+ */
+static void ice_set_vf_state_qs_dis(struct ice_vf *vf)
+{
+ /* Clear Rx/Tx enabled queues flag */
+ bitmap_zero(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF);
+ bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
+ clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
+}
+
+/**
+ * ice_vf_set_initialized - VF is ready for VIRTCHNL communication
+ * @vf: VF to set in initialized state
+ *
+ * After this function the VF will be ready to receive/handle the
+ * VIRTCHNL_OP_GET_VF_RESOURCES message
+ */
+static void ice_vf_set_initialized(struct ice_vf *vf)
+{
+ ice_set_vf_state_qs_dis(vf);
+ clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states);
+ clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states);
+ clear_bit(ICE_VF_STATE_DIS, vf->vf_states);
+ set_bit(ICE_VF_STATE_INIT, vf->vf_states);
+ memset(&vf->vlan_v2_caps, 0, sizeof(vf->vlan_v2_caps));
+}
+
+/**
* ice_vf_post_vsi_rebuild - Reset tasks that occur after VSI rebuild
* @vf: the VF being reset
*
@@ -631,11 +843,17 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
return 0;
}
+ if (flags & ICE_VF_RESET_LOCK)
+ mutex_lock(&vf->cfg_lock);
+ else
+ lockdep_assert_held(&vf->cfg_lock);
+
if (ice_is_vf_disabled(vf)) {
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
dev_dbg(dev, "VF is already removed\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto out_unlock;
}
ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, vf->vf_id);
@@ -644,14 +862,9 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
dev_dbg(dev, "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n",
vf->vf_id);
- return 0;
+ goto out_unlock;
}
- if (flags & ICE_VF_RESET_LOCK)
- mutex_lock(&vf->cfg_lock);
- else
- lockdep_assert_held(&vf->cfg_lock);
-
/* Set VF disable bit state here, before triggering reset */
set_bit(ICE_VF_STATE_DIS, vf->vf_states);
ice_trigger_vf_reset(vf, flags & ICE_VF_RESET_VFLR, false);
@@ -726,18 +939,6 @@ out_unlock:
}
/**
- * ice_set_vf_state_qs_dis - Set VF queues state to disabled
- * @vf: pointer to the VF structure
- */
-static void ice_set_vf_state_qs_dis(struct ice_vf *vf)
-{
- /* Clear Rx/Tx enabled queues flag */
- bitmap_zero(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF);
- bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
- clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
-}
-
-/**
* ice_set_vf_state_dis - Set VF state to disabled
* @vf: pointer to the VF structure
*/
@@ -978,211 +1179,6 @@ bool ice_is_vf_link_up(struct ice_vf *vf)
}
/**
- * ice_vf_set_host_trust_cfg - set trust setting based on pre-reset value
- * @vf: VF to configure trust setting for
- */
-static void ice_vf_set_host_trust_cfg(struct ice_vf *vf)
-{
- if (vf->trusted)
- set_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
- else
- clear_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
-}
-
-/**
- * ice_vf_rebuild_host_mac_cfg - add broadcast and the VF's perm_addr/LAA
- * @vf: VF to add MAC filters for
- *
- * Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
- * always re-adds a broadcast filter and the VF's perm_addr/LAA after reset.
- */
-static int ice_vf_rebuild_host_mac_cfg(struct ice_vf *vf)
-{
- struct device *dev = ice_pf_to_dev(vf->pf);
- struct ice_vsi *vsi = ice_get_vf_vsi(vf);
- u8 broadcast[ETH_ALEN];
- int status;
-
- if (WARN_ON(!vsi))
- return -EINVAL;
-
- if (ice_is_eswitch_mode_switchdev(vf->pf))
- return 0;
-
- eth_broadcast_addr(broadcast);
- status = ice_fltr_add_mac(vsi, broadcast, ICE_FWD_TO_VSI);
- if (status) {
- dev_err(dev, "failed to add broadcast MAC filter for VF %u, error %d\n",
- vf->vf_id, status);
- return status;
- }
-
- vf->num_mac++;
-
- if (is_valid_ether_addr(vf->hw_lan_addr)) {
- status = ice_fltr_add_mac(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
- if (status) {
- dev_err(dev, "failed to add default unicast MAC filter %pM for VF %u, error %d\n",
- &vf->hw_lan_addr[0], vf->vf_id,
- status);
- return status;
- }
- vf->num_mac++;
-
- ether_addr_copy(vf->dev_lan_addr, vf->hw_lan_addr);
- }
-
- return 0;
-}
-
-/**
- * ice_vf_rebuild_host_vlan_cfg - add VLAN 0 filter or rebuild the Port VLAN
- * @vf: VF to add MAC filters for
- * @vsi: Pointer to VSI
- *
- * Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
- * always re-adds either a VLAN 0 or port VLAN based filter after reset.
- */
-static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf, struct ice_vsi *vsi)
-{
- struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
- struct device *dev = ice_pf_to_dev(vf->pf);
- int err;
-
- if (ice_vf_is_port_vlan_ena(vf)) {
- err = vlan_ops->set_port_vlan(vsi, &vf->port_vlan_info);
- if (err) {
- dev_err(dev, "failed to configure port VLAN via VSI parameters for VF %u, error %d\n",
- vf->vf_id, err);
- return err;
- }
-
- err = vlan_ops->add_vlan(vsi, &vf->port_vlan_info);
- } else {
- err = ice_vsi_add_vlan_zero(vsi);
- }
-
- if (err) {
- dev_err(dev, "failed to add VLAN %u filter for VF %u during VF rebuild, error %d\n",
- ice_vf_is_port_vlan_ena(vf) ?
- ice_vf_get_port_vlan_id(vf) : 0, vf->vf_id, err);
- return err;
- }
-
- err = vlan_ops->ena_rx_filtering(vsi);
- if (err)
- dev_warn(dev, "failed to enable Rx VLAN filtering for VF %d VSI %d during VF rebuild, error %d\n",
- vf->vf_id, vsi->idx, err);
-
- return 0;
-}
-
-/**
- * ice_vf_rebuild_host_tx_rate_cfg - re-apply the Tx rate limiting configuration
- * @vf: VF to re-apply the configuration for
- *
- * Called after a VF VSI has been re-added/rebuild during reset. The PF driver
- * needs to re-apply the host configured Tx rate limiting configuration.
- */
-static int ice_vf_rebuild_host_tx_rate_cfg(struct ice_vf *vf)
-{
- struct device *dev = ice_pf_to_dev(vf->pf);
- struct ice_vsi *vsi = ice_get_vf_vsi(vf);
- int err;
-
- if (WARN_ON(!vsi))
- return -EINVAL;
-
- if (vf->min_tx_rate) {
- err = ice_set_min_bw_limit(vsi, (u64)vf->min_tx_rate * 1000);
- if (err) {
- dev_err(dev, "failed to set min Tx rate to %d Mbps for VF %u, error %d\n",
- vf->min_tx_rate, vf->vf_id, err);
- return err;
- }
- }
-
- if (vf->max_tx_rate) {
- err = ice_set_max_bw_limit(vsi, (u64)vf->max_tx_rate * 1000);
- if (err) {
- dev_err(dev, "failed to set max Tx rate to %d Mbps for VF %u, error %d\n",
- vf->max_tx_rate, vf->vf_id, err);
- return err;
- }
- }
-
- return 0;
-}
-
-/**
- * ice_vf_rebuild_aggregator_node_cfg - rebuild aggregator node config
- * @vsi: Pointer to VSI
- *
- * This function moves VSI into corresponding scheduler aggregator node
- * based on cached value of "aggregator node info" per VSI
- */
-static void ice_vf_rebuild_aggregator_node_cfg(struct ice_vsi *vsi)
-{
- struct ice_pf *pf = vsi->back;
- struct device *dev;
- int status;
-
- if (!vsi->agg_node)
- return;
-
- dev = ice_pf_to_dev(pf);
- if (vsi->agg_node->num_vsis == ICE_MAX_VSIS_IN_AGG_NODE) {
- dev_dbg(dev,
- "agg_id %u already has reached max_num_vsis %u\n",
- vsi->agg_node->agg_id, vsi->agg_node->num_vsis);
- return;
- }
-
- status = ice_move_vsi_to_agg(pf->hw.port_info, vsi->agg_node->agg_id,
- vsi->idx, vsi->tc_cfg.ena_tc);
- if (status)
- dev_dbg(dev, "unable to move VSI idx %u into aggregator %u node",
- vsi->idx, vsi->agg_node->agg_id);
- else
- vsi->agg_node->num_vsis++;
-}
-
-/**
- * ice_vf_rebuild_host_cfg - host admin configuration is persistent across reset
- * @vf: VF to rebuild host configuration on
- */
-void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
-{
- struct device *dev = ice_pf_to_dev(vf->pf);
- struct ice_vsi *vsi = ice_get_vf_vsi(vf);
-
- if (WARN_ON(!vsi))
- return;
-
- ice_vf_set_host_trust_cfg(vf);
-
- if (ice_vf_rebuild_host_mac_cfg(vf))
- dev_err(dev, "failed to rebuild default MAC configuration for VF %d\n",
- vf->vf_id);
-
- if (ice_vf_rebuild_host_vlan_cfg(vf, vsi))
- dev_err(dev, "failed to rebuild VLAN configuration for VF %u\n",
- vf->vf_id);
-
- if (ice_vf_rebuild_host_tx_rate_cfg(vf))
- dev_err(dev, "failed to rebuild Tx rate limiting configuration for VF %u\n",
- vf->vf_id);
-
- if (ice_vsi_apply_spoofchk(vsi, vf->spoofchk))
- dev_err(dev, "failed to rebuild spoofchk configuration for VF %d\n",
- vf->vf_id);
-
- /* rebuild aggregator node config for main VF VSI */
- ice_vf_rebuild_aggregator_node_cfg(vsi);
-}
-
-/**
* ice_vf_ctrl_invalidate_vsi - invalidate ctrl_vsi_idx to remove VSI access
* @vf: VF that control VSI is being invalidated on
*/
@@ -1311,23 +1307,6 @@ void ice_vf_vsi_release(struct ice_vf *vf)
}
/**
- * ice_vf_set_initialized - VF is ready for VIRTCHNL communication
- * @vf: VF to set in initialized state
- *
- * After this function the VF will be ready to receive/handle the
- * VIRTCHNL_OP_GET_VF_RESOURCES message
- */
-void ice_vf_set_initialized(struct ice_vf *vf)
-{
- ice_set_vf_state_qs_dis(vf);
- clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states);
- clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states);
- clear_bit(ICE_VF_STATE_DIS, vf->vf_states);
- set_bit(ICE_VF_STATE_INIT, vf->vf_states);
- memset(&vf->vlan_v2_caps, 0, sizeof(vf->vlan_v2_caps));
-}
-
-/**
* ice_get_vf_ctrl_vsi - Get first VF control VSI pointer
* @pf: the PF private structure
* @vsi: pointer to the VSI
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 67172fdd9bc2..48fea6fa0362 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -215,7 +215,6 @@ u16 ice_get_num_vfs(struct ice_pf *pf);
struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf);
bool ice_is_vf_disabled(struct ice_vf *vf);
int ice_check_vf_ready_for_cfg(struct ice_vf *vf);
-int ice_check_vf_ready_for_reset(struct ice_vf *vf);
void ice_set_vf_state_dis(struct ice_vf *vf);
bool ice_is_any_vf_in_unicast_promisc(struct ice_pf *pf);
void
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
index 6f3293b793b5..0c7e77c0a09f 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
@@ -32,13 +32,11 @@ int ice_vsi_apply_spoofchk(struct ice_vsi *vsi, bool enable);
bool ice_is_vf_trusted(struct ice_vf *vf);
bool ice_vf_has_no_qs_ena(struct ice_vf *vf);
bool ice_is_vf_link_up(struct ice_vf *vf);
-void ice_vf_rebuild_host_cfg(struct ice_vf *vf);
void ice_vf_ctrl_invalidate_vsi(struct ice_vf *vf);
void ice_vf_ctrl_vsi_release(struct ice_vf *vf);
struct ice_vsi *ice_vf_ctrl_vsi_setup(struct ice_vf *vf);
int ice_vf_init_host_cfg(struct ice_vf *vf, struct ice_vsi *vsi);
void ice_vf_invalidate_vsi(struct ice_vf *vf);
void ice_vf_vsi_release(struct ice_vf *vf);
-void ice_vf_set_initialized(struct ice_vf *vf);
#endif /* _ICE_VF_LIB_PRIVATE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c
index b1ffb81893d4..d7b10dc67f03 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c
@@ -21,6 +21,99 @@ noop_vlan(struct ice_vsi __always_unused *vsi)
return 0;
}
+static void ice_port_vlan_on(struct ice_vsi *vsi)
+{
+ struct ice_vsi_vlan_ops *vlan_ops;
+ struct ice_pf *pf = vsi->back;
+
+ if (ice_is_dvm_ena(&pf->hw)) {
+ vlan_ops = &vsi->outer_vlan_ops;
+
+ /* setup outer VLAN ops */
+ vlan_ops->set_port_vlan = ice_vsi_set_outer_port_vlan;
+ vlan_ops->clear_port_vlan = ice_vsi_clear_outer_port_vlan;
+ vlan_ops->clear_port_vlan = ice_vsi_clear_outer_port_vlan;
+
+ /* setup inner VLAN ops */
+ vlan_ops = &vsi->inner_vlan_ops;
+ vlan_ops->add_vlan = noop_vlan_arg;
+ vlan_ops->del_vlan = noop_vlan_arg;
+ vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
+ vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
+ vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
+ vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
+ } else {
+ vlan_ops = &vsi->inner_vlan_ops;
+
+ vlan_ops->set_port_vlan = ice_vsi_set_inner_port_vlan;
+ vlan_ops->clear_port_vlan = ice_vsi_clear_inner_port_vlan;
+ vlan_ops->clear_port_vlan = ice_vsi_clear_inner_port_vlan;
+ }
+ vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
+}
+
+static void ice_port_vlan_off(struct ice_vsi *vsi)
+{
+ struct ice_vsi_vlan_ops *vlan_ops;
+ struct ice_pf *pf = vsi->back;
+
+ /* setup inner VLAN ops */
+ vlan_ops = &vsi->inner_vlan_ops;
+
+ vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
+ vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
+ vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
+ vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
+
+ if (ice_is_dvm_ena(&pf->hw)) {
+ vlan_ops = &vsi->outer_vlan_ops;
+
+ vlan_ops->del_vlan = ice_vsi_del_vlan;
+ vlan_ops->ena_stripping = ice_vsi_ena_outer_stripping;
+ vlan_ops->dis_stripping = ice_vsi_dis_outer_stripping;
+ vlan_ops->ena_insertion = ice_vsi_ena_outer_insertion;
+ vlan_ops->dis_insertion = ice_vsi_dis_outer_insertion;
+ } else {
+ vlan_ops->del_vlan = ice_vsi_del_vlan;
+ }
+
+ if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags))
+ vlan_ops->ena_rx_filtering = noop_vlan;
+ else
+ vlan_ops->ena_rx_filtering =
+ ice_vsi_ena_rx_vlan_filtering;
+}
+
+/**
+ * ice_vf_vsi_enable_port_vlan - Set VSI VLAN ops to support port VLAN
+ * @vsi: VF's VSI being configured
+ *
+ * The function won't create port VLAN, it only allows to create port VLAN
+ * using VLAN ops on the VF VSI.
+ */
+void ice_vf_vsi_enable_port_vlan(struct ice_vsi *vsi)
+{
+ if (WARN_ON_ONCE(!vsi->vf))
+ return;
+
+ ice_port_vlan_on(vsi);
+}
+
+/**
+ * ice_vf_vsi_disable_port_vlan - Clear VSI support for creating port VLAN
+ * @vsi: VF's VSI being configured
+ *
+ * The function should be called after removing port VLAN on VSI
+ * (using VLAN ops)
+ */
+void ice_vf_vsi_disable_port_vlan(struct ice_vsi *vsi)
+{
+ if (WARN_ON_ONCE(!vsi->vf))
+ return;
+
+ ice_port_vlan_off(vsi);
+}
+
/**
* ice_vf_vsi_init_vlan_ops - Initialize default VSI VLAN ops for VF VSI
* @vsi: VF's VSI being configured
@@ -39,91 +132,18 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi)
if (WARN_ON(!vf))
return;
- if (ice_is_dvm_ena(&pf->hw)) {
- vlan_ops = &vsi->outer_vlan_ops;
+ if (ice_vf_is_port_vlan_ena(vf))
+ ice_port_vlan_on(vsi);
+ else
+ ice_port_vlan_off(vsi);
- /* outer VLAN ops regardless of port VLAN config */
- vlan_ops->add_vlan = ice_vsi_add_vlan;
- vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
- vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
-
- if (ice_vf_is_port_vlan_ena(vf)) {
- /* setup outer VLAN ops */
- vlan_ops->set_port_vlan = ice_vsi_set_outer_port_vlan;
- /* all Rx traffic should be in the domain of the
- * assigned port VLAN, so prevent disabling Rx VLAN
- * filtering
- */
- vlan_ops->dis_rx_filtering = noop_vlan;
- vlan_ops->ena_rx_filtering =
- ice_vsi_ena_rx_vlan_filtering;
-
- /* setup inner VLAN ops */
- vlan_ops = &vsi->inner_vlan_ops;
- vlan_ops->add_vlan = noop_vlan_arg;
- vlan_ops->del_vlan = noop_vlan_arg;
- vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
- vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
- vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
- vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
- } else {
- vlan_ops->dis_rx_filtering =
- ice_vsi_dis_rx_vlan_filtering;
-
- if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags))
- vlan_ops->ena_rx_filtering = noop_vlan;
- else
- vlan_ops->ena_rx_filtering =
- ice_vsi_ena_rx_vlan_filtering;
-
- vlan_ops->del_vlan = ice_vsi_del_vlan;
- vlan_ops->ena_stripping = ice_vsi_ena_outer_stripping;
- vlan_ops->dis_stripping = ice_vsi_dis_outer_stripping;
- vlan_ops->ena_insertion = ice_vsi_ena_outer_insertion;
- vlan_ops->dis_insertion = ice_vsi_dis_outer_insertion;
-
- /* setup inner VLAN ops */
- vlan_ops = &vsi->inner_vlan_ops;
-
- vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
- vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
- vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
- vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
- }
- } else {
- vlan_ops = &vsi->inner_vlan_ops;
+ vlan_ops = ice_is_dvm_ena(&pf->hw) ?
+ &vsi->outer_vlan_ops : &vsi->inner_vlan_ops;
- /* inner VLAN ops regardless of port VLAN config */
- vlan_ops->add_vlan = ice_vsi_add_vlan;
- vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
- vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
- vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
-
- if (ice_vf_is_port_vlan_ena(vf)) {
- vlan_ops->set_port_vlan = ice_vsi_set_inner_port_vlan;
- vlan_ops->ena_rx_filtering =
- ice_vsi_ena_rx_vlan_filtering;
- /* all Rx traffic should be in the domain of the
- * assigned port VLAN, so prevent disabling Rx VLAN
- * filtering
- */
- vlan_ops->dis_rx_filtering = noop_vlan;
- } else {
- vlan_ops->dis_rx_filtering =
- ice_vsi_dis_rx_vlan_filtering;
- if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags))
- vlan_ops->ena_rx_filtering = noop_vlan;
- else
- vlan_ops->ena_rx_filtering =
- ice_vsi_ena_rx_vlan_filtering;
-
- vlan_ops->del_vlan = ice_vsi_del_vlan;
- vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
- vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
- vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
- vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
- }
- }
+ vlan_ops->add_vlan = ice_vsi_add_vlan;
+ vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
+ vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
+ vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.h b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.h
index 875a4e615f39..df8aa09df3e3 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.h
@@ -13,7 +13,11 @@ void ice_vf_vsi_cfg_svm_legacy_vlan_mode(struct ice_vsi *vsi);
#ifdef CONFIG_PCI_IOV
void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi);
+void ice_vf_vsi_enable_port_vlan(struct ice_vsi *vsi);
+void ice_vf_vsi_disable_port_vlan(struct ice_vsi *vsi);
#else
static inline void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi) { }
+static inline void ice_vf_vsi_enable_port_vlan(struct ice_vsi *vsi) { }
+static inline void ice_vf_vsi_disable_port_vlan(struct ice_vsi *vsi) { }
#endif /* CONFIG_PCI_IOV */
#endif /* _ICE_PF_VSI_VLAN_OPS_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
index efbc2968a7bf..b03426ac932b 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
@@ -428,7 +428,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
goto err;
}
- len = sizeof(struct virtchnl_vf_resource);
+ len = virtchnl_struct_size(vfres, vsi_res, 0);
vfres = kzalloc(len, GFP_KERNEL);
if (!vfres) {
@@ -500,7 +500,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
vfres->num_queue_pairs = vsi->num_txq;
vfres->max_vectors = vf->pf->vfs.num_msix_per;
vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE;
- vfres->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+ vfres->rss_lut_size = ICE_LUT_VSI_SIZE;
vfres->max_mtu = ice_vc_get_max_frame_size(vf);
vfres->vsi_res[0].vsi_id = vf->lan_vsi_num;
@@ -962,7 +962,7 @@ static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- if (vrl->lut_entries != ICE_VSIQF_HLUT_ARRAY_SIZE) {
+ if (vrl->lut_entries != ICE_LUT_VSI_SIZE) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
@@ -978,7 +978,7 @@ static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
goto error_param;
}
- if (ice_set_rss_lut(vsi, vrl->lut, ICE_VSIQF_HLUT_ARRAY_SIZE))
+ if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE))
v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
error_param:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret,
@@ -1724,6 +1724,8 @@ error_param:
vf->vf_id, i);
}
+ ice_lag_move_new_vf_nodes(vf);
+
/* send the response to the VF */
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
VIRTCHNL_STATUS_ERR_PARAM, NULL, 0);
@@ -3947,7 +3949,6 @@ error_handler:
ice_vc_notify_vf_link_state(vf);
break;
case VIRTCHNL_OP_RESET_VF:
- clear_bit(ICE_VF_STATE_ACTIVE, vf->vf_states);
ops->reset_vf(vf);
break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
index 5b4a0abb4607..76266e709a39 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
@@ -202,6 +202,24 @@ int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi)
return ice_vsi_manage_vlan_insertion(vsi);
}
+static void
+ice_save_vlan_info(struct ice_aqc_vsi_props *info,
+ struct ice_vsi_vlan_info *vlan)
+{
+ vlan->sw_flags2 = info->sw_flags2;
+ vlan->inner_vlan_flags = info->inner_vlan_flags;
+ vlan->outer_vlan_flags = info->outer_vlan_flags;
+}
+
+static void
+ice_restore_vlan_info(struct ice_aqc_vsi_props *info,
+ struct ice_vsi_vlan_info *vlan)
+{
+ info->sw_flags2 = vlan->sw_flags2;
+ info->inner_vlan_flags = vlan->inner_vlan_flags;
+ info->outer_vlan_flags = vlan->outer_vlan_flags;
+}
+
/**
* __ice_vsi_set_inner_port_vlan - set port VLAN VSI context settings to enable a port VLAN
* @vsi: the VSI to update
@@ -218,6 +236,7 @@ static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info)
if (!ctxt)
return -ENOMEM;
+ ice_save_vlan_info(&vsi->info, &vsi->vlan_info);
ctxt->info = vsi->info;
info = &ctxt->info;
info->inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ACCEPTUNTAGGED |
@@ -259,6 +278,33 @@ int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
return __ice_vsi_set_inner_port_vlan(vsi, port_vlan_info);
}
+int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_aqc_vsi_props *info;
+ struct ice_vsi_ctx *ctxt;
+ int ret;
+
+ ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ if (!ctxt)
+ return -ENOMEM;
+
+ ice_restore_vlan_info(&vsi->info, &vsi->vlan_info);
+ vsi->info.port_based_inner_vlan = 0;
+ ctxt->info = vsi->info;
+ info = &ctxt->info;
+ info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
+ ICE_AQ_VSI_PROP_SW_VALID);
+
+ ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
+ if (ret)
+ dev_err(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
+ ret, ice_aq_str(hw->adminq.sq_last_status));
+
+ kfree(ctxt);
+ return ret;
+}
+
/**
* ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
* @vsi: VSI to enable or disable VLAN pruning on
@@ -647,6 +693,7 @@ __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
if (!ctxt)
return -ENOMEM;
+ ice_save_vlan_info(&vsi->info, &vsi->vlan_info);
ctxt->info = vsi->info;
ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
@@ -689,9 +736,6 @@ __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
* used if DVM is supported. Also, this function should never be called directly
* as it should be part of ice_vsi_vlan_ops if it's needed.
*
- * This function does not support clearing the port VLAN as there is currently
- * no use case for this.
- *
* Use the ice_vlan structure passed in to set this VSI in a port VLAN.
*/
int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
@@ -705,3 +749,37 @@ int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
return __ice_vsi_set_outer_port_vlan(vsi, port_vlan_info, vlan->tpid);
}
+
+/**
+ * ice_vsi_clear_outer_port_vlan - clear outer port vlan
+ * @vsi: VSI to configure
+ *
+ * The function is restoring previously set vlan config (saved in
+ * vsi->vlan_info). Setting happens in port vlan configuration.
+ */
+int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx *ctxt;
+ int err;
+
+ ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ if (!ctxt)
+ return -ENOMEM;
+
+ ice_restore_vlan_info(&vsi->info, &vsi->vlan_info);
+ vsi->info.port_based_outer_vlan = 0;
+ ctxt->info = vsi->info;
+
+ ctxt->info.valid_sections =
+ cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID |
+ ICE_AQ_VSI_PROP_SW_VALID);
+
+ err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
+ if (err)
+ dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing outer port based VLAN failed, err %d aq_err %s\n",
+ err, ice_aq_str(hw->adminq.sq_last_status));
+
+ kfree(ctxt);
+ return err;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.h b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.h
index f459909490ec..f0d84d11bd5b 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.h
@@ -7,6 +7,12 @@
#include <linux/types.h>
#include "ice_vlan.h"
+struct ice_vsi_vlan_info {
+ u8 sw_flags2;
+ u8 inner_vlan_flags;
+ u8 outer_vlan_flags;
+};
+
struct ice_vsi;
int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
@@ -17,6 +23,7 @@ int ice_vsi_dis_inner_stripping(struct ice_vsi *vsi);
int ice_vsi_ena_inner_insertion(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi);
int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
+int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi);
int ice_vsi_ena_rx_vlan_filtering(struct ice_vsi *vsi);
int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi);
@@ -28,5 +35,6 @@ int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi);
int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi);
int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
+int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi);
#endif /* _ICE_VSI_VLAN_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_ops.h b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_ops.h
index 5b47568f6256..b2d2330dedcb 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_ops.h
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_ops.h
@@ -21,6 +21,7 @@ struct ice_vsi_vlan_ops {
int (*ena_tx_filtering)(struct ice_vsi *vsi);
int (*dis_tx_filtering)(struct ice_vsi *vsi);
int (*set_port_vlan)(struct ice_vsi *vsi, struct ice_vlan *vlan);
+ int (*clear_port_vlan)(struct ice_vsi *vsi);
};
void ice_vsi_init_vlan_ops(struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index a7fe2b4ce655..2a3f0834e139 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -546,19 +546,6 @@ bool ice_alloc_rx_bufs_zc(struct ice_rx_ring *rx_ring, u16 count)
}
/**
- * ice_bump_ntc - Bump the next_to_clean counter of an Rx ring
- * @rx_ring: Rx ring
- */
-static void ice_bump_ntc(struct ice_rx_ring *rx_ring)
-{
- int ntc = rx_ring->next_to_clean + 1;
-
- ntc = (ntc < rx_ring->count) ? ntc : 0;
- rx_ring->next_to_clean = ntc;
- prefetch(ICE_RX_DESC(rx_ring, ntc));
-}
-
-/**
* ice_construct_skb_zc - Create an sk_buff from zero-copy buffer
* @rx_ring: Rx ring
* @xdp: Pointer to XDP buffer
@@ -572,8 +559,14 @@ ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
{
unsigned int totalsize = xdp->data_end - xdp->data_meta;
unsigned int metasize = xdp->data - xdp->data_meta;
+ struct skb_shared_info *sinfo = NULL;
struct sk_buff *skb;
+ u32 nr_frags = 0;
+ if (unlikely(xdp_buff_has_frags(xdp))) {
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ nr_frags = sinfo->nr_frags;
+ }
net_prefetch(xdp->data_meta);
skb = __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize,
@@ -589,6 +582,29 @@ ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
__skb_pull(skb, metasize);
}
+ if (likely(!xdp_buff_has_frags(xdp)))
+ goto out;
+
+ for (int i = 0; i < nr_frags; i++) {
+ struct skb_shared_info *skinfo = skb_shinfo(skb);
+ skb_frag_t *frag = &sinfo->frags[i];
+ struct page *page;
+ void *addr;
+
+ page = dev_alloc_page();
+ if (!page) {
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+ addr = page_to_virt(page);
+
+ memcpy(addr, skb_frag_page(frag), skb_frag_size(frag));
+
+ __skb_fill_page_desc_noacc(skinfo, skinfo->nr_frags++,
+ addr, 0, skb_frag_size(frag));
+ }
+
+out:
xsk_buff_free(xdp);
return skb;
}
@@ -597,7 +613,7 @@ ice_construct_skb_zc(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
* ice_clean_xdp_irq_zc - produce AF_XDP descriptors to CQ
* @xdp_ring: XDP Tx ring
*/
-static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring)
+static u32 ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring)
{
u16 ntc = xdp_ring->next_to_clean;
struct ice_tx_desc *tx_desc;
@@ -619,7 +635,7 @@ static void ice_clean_xdp_irq_zc(struct ice_tx_ring *xdp_ring)
}
if (!completed_frames)
- return;
+ return 0;
if (likely(!xdp_ring->xdp_tx_active)) {
xsk_frames = completed_frames;
@@ -649,6 +665,8 @@ skip:
xdp_ring->next_to_clean -= cnt;
if (xsk_frames)
xsk_tx_completed(xdp_ring->xsk_pool, xsk_frames);
+
+ return completed_frames;
}
/**
@@ -666,37 +684,72 @@ skip:
static int ice_xmit_xdp_tx_zc(struct xdp_buff *xdp,
struct ice_tx_ring *xdp_ring)
{
+ struct skb_shared_info *sinfo = NULL;
u32 size = xdp->data_end - xdp->data;
u32 ntu = xdp_ring->next_to_use;
struct ice_tx_desc *tx_desc;
struct ice_tx_buf *tx_buf;
- dma_addr_t dma;
-
- if (ICE_DESC_UNUSED(xdp_ring) < ICE_RING_QUARTER(xdp_ring)) {
- ice_clean_xdp_irq_zc(xdp_ring);
- if (!ICE_DESC_UNUSED(xdp_ring)) {
- xdp_ring->ring_stats->tx_stats.tx_busy++;
- return ICE_XDP_CONSUMED;
- }
+ struct xdp_buff *head;
+ u32 nr_frags = 0;
+ u32 free_space;
+ u32 frag = 0;
+
+ free_space = ICE_DESC_UNUSED(xdp_ring);
+ if (free_space < ICE_RING_QUARTER(xdp_ring))
+ free_space += ice_clean_xdp_irq_zc(xdp_ring);
+
+ if (unlikely(!free_space))
+ goto busy;
+
+ if (unlikely(xdp_buff_has_frags(xdp))) {
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ nr_frags = sinfo->nr_frags;
+ if (free_space < nr_frags + 1)
+ goto busy;
}
- dma = xsk_buff_xdp_get_dma(xdp);
- xsk_buff_raw_dma_sync_for_device(xdp_ring->xsk_pool, dma, size);
-
- tx_buf = &xdp_ring->tx_buf[ntu];
- tx_buf->xdp = xdp;
- tx_buf->type = ICE_TX_BUF_XSK_TX;
tx_desc = ICE_TX_DESC(xdp_ring, ntu);
- tx_desc->buf_addr = cpu_to_le64(dma);
- tx_desc->cmd_type_offset_bsz = ice_build_ctob(ICE_TX_DESC_CMD_EOP,
- 0, size, 0);
- xdp_ring->xdp_tx_active++;
+ tx_buf = &xdp_ring->tx_buf[ntu];
+ head = xdp;
+
+ for (;;) {
+ dma_addr_t dma;
+
+ dma = xsk_buff_xdp_get_dma(xdp);
+ xsk_buff_raw_dma_sync_for_device(xdp_ring->xsk_pool, dma, size);
+
+ tx_buf->xdp = xdp;
+ tx_buf->type = ICE_TX_BUF_XSK_TX;
+ tx_desc->buf_addr = cpu_to_le64(dma);
+ tx_desc->cmd_type_offset_bsz = ice_build_ctob(0, 0, size, 0);
+ /* account for each xdp_buff from xsk_buff_pool */
+ xdp_ring->xdp_tx_active++;
+
+ if (++ntu == xdp_ring->count)
+ ntu = 0;
+
+ if (frag == nr_frags)
+ break;
+
+ tx_desc = ICE_TX_DESC(xdp_ring, ntu);
+ tx_buf = &xdp_ring->tx_buf[ntu];
+
+ xdp = xsk_buff_get_frag(head);
+ size = skb_frag_size(&sinfo->frags[frag]);
+ frag++;
+ }
- if (++ntu == xdp_ring->count)
- ntu = 0;
xdp_ring->next_to_use = ntu;
+ /* update last descriptor from a frame with EOP */
+ tx_desc->cmd_type_offset_bsz |=
+ cpu_to_le64(ICE_TX_DESC_CMD_EOP << ICE_TXD_QW1_CMD_S);
return ICE_XDP_TX;
+
+busy:
+ xdp_ring->ring_stats->tx_stats.tx_busy++;
+
+ return ICE_XDP_CONSUMED;
}
/**
@@ -752,6 +805,34 @@ out_failure:
return result;
}
+static int
+ice_add_xsk_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *first,
+ struct xdp_buff *xdp, const unsigned int size)
+{
+ struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(first);
+
+ if (!size)
+ return 0;
+
+ if (!xdp_buff_has_frags(first)) {
+ sinfo->nr_frags = 0;
+ sinfo->xdp_frags_size = 0;
+ xdp_buff_set_frags_flag(first);
+ }
+
+ if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) {
+ xsk_buff_free(first);
+ return -ENOMEM;
+ }
+
+ __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++,
+ virt_to_page(xdp->data_hard_start), 0, size);
+ sinfo->xdp_frags_size += size;
+ xsk_buff_add_frag(xdp);
+
+ return 0;
+}
+
/**
* ice_clean_rx_irq_zc - consumes packets from the hardware ring
* @rx_ring: AF_XDP Rx ring
@@ -762,9 +843,14 @@ out_failure:
int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ struct xsk_buff_pool *xsk_pool = rx_ring->xsk_pool;
+ u32 ntc = rx_ring->next_to_clean;
+ u32 ntu = rx_ring->next_to_use;
+ struct xdp_buff *first = NULL;
struct ice_tx_ring *xdp_ring;
unsigned int xdp_xmit = 0;
struct bpf_prog *xdp_prog;
+ u32 cnt = rx_ring->count;
bool failure = false;
int entries_to_alloc;
@@ -774,6 +860,9 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
xdp_ring = rx_ring->xdp_ring;
+ if (ntc != rx_ring->first_desc)
+ first = *ice_xdp_buf(rx_ring, rx_ring->first_desc);
+
while (likely(total_rx_packets < (unsigned int)budget)) {
union ice_32b_rx_flex_desc *rx_desc;
unsigned int size, xdp_res = 0;
@@ -783,7 +872,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
u16 vlan_tag = 0;
u16 rx_ptype;
- rx_desc = ICE_RX_DESC(rx_ring, rx_ring->next_to_clean);
+ rx_desc = ICE_RX_DESC(rx_ring, ntc);
stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S);
if (!ice_test_staterr(rx_desc->wb.status_error0, stat_err_bits))
@@ -795,51 +884,61 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
*/
dma_rmb();
- if (unlikely(rx_ring->next_to_clean == rx_ring->next_to_use))
+ if (unlikely(ntc == ntu))
break;
- xdp = *ice_xdp_buf(rx_ring, rx_ring->next_to_clean);
+ xdp = *ice_xdp_buf(rx_ring, ntc);
size = le16_to_cpu(rx_desc->wb.pkt_len) &
ICE_RX_FLX_DESC_PKT_LEN_M;
- if (!size) {
- xdp->data = NULL;
- xdp->data_end = NULL;
- xdp->data_hard_start = NULL;
- xdp->data_meta = NULL;
- goto construct_skb;
- }
xsk_buff_set_size(xdp, size);
- xsk_buff_dma_sync_for_cpu(xdp, rx_ring->xsk_pool);
+ xsk_buff_dma_sync_for_cpu(xdp, xsk_pool);
+
+ if (!first) {
+ first = xdp;
+ xdp_buff_clear_frags_flag(first);
+ } else if (ice_add_xsk_frag(rx_ring, first, xdp, size)) {
+ break;
+ }
+
+ if (++ntc == cnt)
+ ntc = 0;
- xdp_res = ice_run_xdp_zc(rx_ring, xdp, xdp_prog, xdp_ring);
+ if (ice_is_non_eop(rx_ring, rx_desc))
+ continue;
+
+ xdp_res = ice_run_xdp_zc(rx_ring, first, xdp_prog, xdp_ring);
if (likely(xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR))) {
xdp_xmit |= xdp_res;
} else if (xdp_res == ICE_XDP_EXIT) {
failure = true;
+ first = NULL;
+ rx_ring->first_desc = ntc;
break;
} else if (xdp_res == ICE_XDP_CONSUMED) {
- xsk_buff_free(xdp);
+ xsk_buff_free(first);
} else if (xdp_res == ICE_XDP_PASS) {
goto construct_skb;
}
- total_rx_bytes += size;
+ total_rx_bytes += xdp_get_buff_len(first);
total_rx_packets++;
- ice_bump_ntc(rx_ring);
+ first = NULL;
+ rx_ring->first_desc = ntc;
continue;
construct_skb:
/* XDP_PASS path */
- skb = ice_construct_skb_zc(rx_ring, xdp);
+ skb = ice_construct_skb_zc(rx_ring, first);
if (!skb) {
rx_ring->ring_stats->rx_stats.alloc_buf_failed++;
break;
}
- ice_bump_ntc(rx_ring);
+ first = NULL;
+ rx_ring->first_desc = ntc;
if (eth_skb_pad(skb)) {
skb = NULL;
@@ -858,18 +957,22 @@ construct_skb:
ice_receive_skb(rx_ring, skb, vlan_tag);
}
- entries_to_alloc = ICE_DESC_UNUSED(rx_ring);
+ rx_ring->next_to_clean = ntc;
+ entries_to_alloc = ICE_RX_DESC_UNUSED(rx_ring);
if (entries_to_alloc > ICE_RING_QUARTER(rx_ring))
failure |= !ice_alloc_rx_bufs_zc(rx_ring, entries_to_alloc);
ice_finalize_xdp_rx(xdp_ring, xdp_xmit, 0);
ice_update_rx_ring_stats(rx_ring, total_rx_packets, total_rx_bytes);
- if (xsk_uses_need_wakeup(rx_ring->xsk_pool)) {
- if (failure || rx_ring->next_to_clean == rx_ring->next_to_use)
- xsk_set_rx_need_wakeup(rx_ring->xsk_pool);
+ if (xsk_uses_need_wakeup(xsk_pool)) {
+ /* ntu could have changed when allocating entries above, so
+ * use rx_ring value instead of stack based one
+ */
+ if (failure || ntc == rx_ring->next_to_use)
+ xsk_set_rx_need_wakeup(xsk_pool);
else
- xsk_clear_rx_need_wakeup(rx_ring->xsk_pool);
+ xsk_clear_rx_need_wakeup(xsk_pool);
return (int)total_rx_packets;
}
@@ -894,7 +997,7 @@ static void ice_xmit_pkt(struct ice_tx_ring *xdp_ring, struct xdp_desc *desc,
tx_desc = ICE_TX_DESC(xdp_ring, xdp_ring->next_to_use++);
tx_desc->buf_addr = cpu_to_le64(dma);
- tx_desc->cmd_type_offset_bsz = ice_build_ctob(ICE_TX_DESC_CMD_EOP,
+ tx_desc->cmd_type_offset_bsz = ice_build_ctob(xsk_is_eop_desc(desc),
0, desc->len, 0);
*total_bytes += desc->len;
@@ -921,7 +1024,7 @@ static void ice_xmit_pkt_batch(struct ice_tx_ring *xdp_ring, struct xdp_desc *de
tx_desc = ICE_TX_DESC(xdp_ring, ntu++);
tx_desc->buf_addr = cpu_to_le64(dma);
- tx_desc->cmd_type_offset_bsz = ice_build_ctob(ICE_TX_DESC_CMD_EOP,
+ tx_desc->cmd_type_offset_bsz = ice_build_ctob(xsk_is_eop_desc(&descs[i]),
0, descs[i].len, 0);
*total_bytes += descs[i].len;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 9a2561409b06..1ab787ed254d 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2615,10 +2615,10 @@ static int igb_parse_cls_flower(struct igb_adapter *adapter,
struct netlink_ext_ack *extack = f->common.extack;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported key used, only BASIC, CONTROL, ETH_ADDRS and VLAN are supported");
return -EOPNOTSUPP;
@@ -4814,6 +4814,10 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
struct igb_ring *rx_ring)
{
+#if (PAGE_SIZE < 8192)
+ struct e1000_hw *hw = &adapter->hw;
+#endif
+
/* set build_skb and buffer size flags */
clear_ring_build_skb_enabled(rx_ring);
clear_ring_uses_large_buffer(rx_ring);
@@ -4824,10 +4828,9 @@ static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
set_ring_build_skb_enabled(rx_ring);
#if (PAGE_SIZE < 8192)
- if (adapter->max_frame_size <= IGB_MAX_FRAME_BUILD_SKB)
- return;
-
- set_ring_uses_large_buffer(rx_ring);
+ if (adapter->max_frame_size > IGB_MAX_FRAME_BUILD_SKB ||
+ rd32(E1000_RCTL) & E1000_RCTL_SBP)
+ set_ring_uses_large_buffer(rx_ring);
#endif
}
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 405886ee5261..319c544b9f04 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -1385,18 +1385,6 @@ void igb_ptp_init(struct igb_adapter *adapter)
return;
}
- spin_lock_init(&adapter->tmreg_lock);
- INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
-
- if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK)
- INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
- igb_ptp_overflow_check);
-
- adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
- adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
-
- igb_ptp_reset(adapter);
-
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
&adapter->pdev->dev);
if (IS_ERR(adapter->ptp_clock)) {
@@ -1406,6 +1394,18 @@ void igb_ptp_init(struct igb_adapter *adapter)
dev_info(&adapter->pdev->dev, "added PHC on %s\n",
adapter->netdev->name);
adapter->ptp_flags |= IGB_PTP_ENABLED;
+
+ spin_lock_init(&adapter->tmreg_lock);
+ INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
+
+ if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK)
+ INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
+ igb_ptp_overflow_check);
+
+ adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+ adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
+
+ igb_ptp_reset(adapter);
}
}
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 38901d2a4680..8ebe6999a528 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -15,6 +15,7 @@
#include <linux/net_tstamp.h>
#include <linux/bitfield.h>
#include <linux/hrtimer.h>
+#include <net/xdp.h>
#include "igc_hw.h"
@@ -37,6 +38,8 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_FLEX_FILTER 32
+#define IGC_MAX_TX_TSTAMP_REGS 4
+
enum igc_mac_filter_type {
IGC_MAC_FILTER_TYPE_DST = 0,
IGC_MAC_FILTER_TYPE_SRC
@@ -69,6 +72,15 @@ struct igc_rx_packet_stats {
u64 other_packets;
};
+struct igc_tx_timestamp_request {
+ struct sk_buff *skb; /* reference to the packet being timestamped */
+ unsigned long start; /* when the tstamp request started (jiffies) */
+ u32 mask; /* _TSYNCTXCTL_TXTT_{X} bit for this request */
+ u32 regl; /* which TXSTMPL_{X} register should be used */
+ u32 regh; /* which TXSTMPH_{X} register should be used */
+ u32 flags; /* flags that should be added to the tx_buffer */
+};
+
struct igc_ring_container {
struct igc_ring *ring; /* pointer to linked list of rings */
unsigned int total_bytes; /* total bytes processed this int */
@@ -244,9 +256,8 @@ struct igc_adapter {
* ptp_tx_lock.
*/
spinlock_t ptp_tx_lock;
- struct sk_buff *ptp_tx_skb;
+ struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
struct hwtstamp_config tstamp_config;
- unsigned long ptp_tx_start;
unsigned int ptp_flags;
/* System time value lock */
spinlock_t tmreg_lock;
@@ -454,6 +465,10 @@ enum igc_tx_flags {
/* olinfo flags */
IGC_TX_FLAGS_IPV4 = 0x10,
IGC_TX_FLAGS_CSUM = 0x20,
+
+ IGC_TX_FLAGS_TSTAMP_1 = 0x100,
+ IGC_TX_FLAGS_TSTAMP_2 = 0x200,
+ IGC_TX_FLAGS_TSTAMP_3 = 0x400,
};
enum igc_boards {
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h
index 9f3827eda157..f7d6491d4c60 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.h
+++ b/drivers/net/ethernet/intel/igc/igc_base.h
@@ -34,6 +34,9 @@ struct igc_adv_tx_context_desc {
/* Adv Transmit Descriptor Config Masks */
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
+#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
+#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
+#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index 44a507029946..b3037016f31d 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -454,6 +454,9 @@
/* Time Sync Transmit Control bit definitions */
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
+#define IGC_TSYNCTXCTL_TXTT_1 0x00000002 /* Tx timestamp reg 1 valid */
+#define IGC_TSYNCTXCTL_TXTT_2 0x00000004 /* Tx timestamp reg 2 valid */
+#define IGC_TSYNCTXCTL_TXTT_3 0x00000008 /* Tx timestamp reg 3 valid */
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
@@ -461,6 +464,10 @@
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
+#define IGC_TSYNCTXCTL_TXTT_ANY ( \
+ IGC_TSYNCTXCTL_TXTT_0 | IGC_TSYNCTXCTL_TXTT_1 | \
+ IGC_TSYNCTXCTL_TXTT_2 | IGC_TSYNCTXCTL_TXTT_3)
+
/* Timer selection bits */
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
@@ -546,10 +553,10 @@
#define IGC_PTM_CTRL_START_NOW BIT(29) /* Start PTM Now */
#define IGC_PTM_CTRL_EN BIT(30) /* Enable PTM */
#define IGC_PTM_CTRL_TRIG BIT(31) /* PTM Cycle trigger */
-#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x2f) << 2)
+#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2)
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
-#define IGC_PTM_SHORT_CYC_DEFAULT 10 /* Default Short/interrupted cycle interval */
+#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 6f557e843e49..293b45717683 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1271,10 +1271,21 @@ static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
(IGC_ADVTXD_DCMD_TSE));
- /* set timestamp bit if present */
+ /* set timestamp bit if present, will select the register set
+ * based on the _TSTAMP(_X) bit.
+ */
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
(IGC_ADVTXD_MAC_TSTAMP));
+ cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_1,
+ (IGC_ADVTXD_TSTAMP_REG_1));
+
+ cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_2,
+ (IGC_ADVTXD_TSTAMP_REG_2));
+
+ cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_3,
+ (IGC_ADVTXD_TSTAMP_REG_3));
+
/* insert frame checksum */
cmd_type ^= IGC_SET_FLAG(skb->no_fcs, 1, IGC_ADVTXD_DCMD_IFCS);
@@ -1533,6 +1544,26 @@ static int igc_tso(struct igc_ring *tx_ring,
return 1;
}
+static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *skb, u32 *flags)
+{
+ int i;
+
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+ if (tstamp->skb)
+ continue;
+
+ tstamp->skb = skb_get(skb);
+ tstamp->start = jiffies;
+ *flags = tstamp->flags;
+
+ return true;
+ }
+
+ return false;
+}
+
static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
struct igc_ring *tx_ring)
{
@@ -1614,14 +1645,12 @@ done:
* timestamping request.
*/
unsigned long flags;
+ u32 tstamp_flags;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
- if (!adapter->ptp_tx_skb) {
+ if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- tx_flags |= IGC_TX_FLAGS_TSTAMP;
-
- adapter->ptp_tx_skb = skb_get(skb);
- adapter->ptp_tx_start = jiffies;
+ tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
} else {
adapter->tx_hwtstamp_skipped++;
}
@@ -6162,6 +6191,26 @@ static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
return 0;
}
+static void igc_taprio_stats(struct net_device *dev,
+ struct tc_taprio_qopt_stats *stats)
+{
+ /* When Strict_End is enabled, the tx_overruns counter
+ * will always be zero.
+ */
+ stats->tx_overruns = 0;
+}
+
+static void igc_taprio_queue_stats(struct net_device *dev,
+ struct tc_taprio_qopt_queue_stats *queue_stats)
+{
+ struct tc_taprio_qopt_stats *stats = &queue_stats->stats;
+
+ /* When Strict_End is enabled, the tx_overruns counter
+ * will always be zero.
+ */
+ stats->tx_overruns = 0;
+}
+
static int igc_save_qbv_schedule(struct igc_adapter *adapter,
struct tc_taprio_qopt_offload *qopt)
{
@@ -6173,11 +6222,20 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter,
size_t n;
int i;
- if (qopt->cmd == TAPRIO_CMD_DESTROY)
+ switch (qopt->cmd) {
+ case TAPRIO_CMD_REPLACE:
+ break;
+ case TAPRIO_CMD_DESTROY:
return igc_tsn_clear_schedule(adapter);
-
- if (qopt->cmd != TAPRIO_CMD_REPLACE)
+ case TAPRIO_CMD_STATS:
+ igc_taprio_stats(adapter->netdev, &qopt->stats);
+ return 0;
+ case TAPRIO_CMD_QUEUE_STATS:
+ igc_taprio_queue_stats(adapter->netdev, &qopt->queue_stats);
+ return 0;
+ default:
return -EOPNOTSUPP;
+ }
if (qopt->base_time < 0)
return -ERANGE;
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index f0b979a70655..928f38792203 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -558,11 +558,16 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
{
unsigned long flags;
+ int i;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
- dev_kfree_skb_any(adapter->ptp_tx_skb);
- adapter->ptp_tx_skb = NULL;
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+ dev_kfree_skb_any(tstamp->skb);
+ tstamp->skb = NULL;
+ }
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
@@ -659,61 +664,106 @@ static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter,
}
/* Requires adapter->ptp_tx_lock held by caller. */
-static void igc_ptp_tx_timeout(struct igc_adapter *adapter)
+static void igc_ptp_tx_timeout(struct igc_adapter *adapter,
+ struct igc_tx_timestamp_request *tstamp)
{
- struct igc_hw *hw = &adapter->hw;
-
- dev_kfree_skb_any(adapter->ptp_tx_skb);
- adapter->ptp_tx_skb = NULL;
+ dev_kfree_skb_any(tstamp->skb);
+ tstamp->skb = NULL;
adapter->tx_hwtstamp_timeouts++;
- /* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */
- rd32(IGC_TXSTMPH);
+
netdev_warn(adapter->netdev, "Tx timestamp timeout\n");
}
void igc_ptp_tx_hang(struct igc_adapter *adapter)
{
+ struct igc_tx_timestamp_request *tstamp;
+ struct igc_hw *hw = &adapter->hw;
unsigned long flags;
+ bool found = false;
+ int i;
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
- if (!adapter->ptp_tx_skb)
- goto unlock;
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ tstamp = &adapter->tx_tstamp[i];
+
+ if (!tstamp->skb)
+ continue;
- if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT))
- goto unlock;
+ if (time_is_after_jiffies(tstamp->start + IGC_PTP_TX_TIMEOUT))
+ continue;
- igc_ptp_tx_timeout(adapter);
+ igc_ptp_tx_timeout(adapter, tstamp);
+ found = true;
+ }
+
+ if (found) {
+ /* Reading the high register of the first set of timestamp registers
+ * clears all the equivalent bits in the TSYNCTXCTL register.
+ */
+ rd32(IGC_TXSTMPH_0);
+ }
-unlock:
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
+static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
+ struct igc_tx_timestamp_request *tstamp, u64 regval)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sk_buff *skb;
+ int adjust = 0;
+
+ skb = tstamp->skb;
+ if (!skb)
+ return;
+
+ if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
+ return;
+
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ adjust = IGC_I225_TX_LATENCY_10;
+ break;
+ case SPEED_100:
+ adjust = IGC_I225_TX_LATENCY_100;
+ break;
+ case SPEED_1000:
+ adjust = IGC_I225_TX_LATENCY_1000;
+ break;
+ case SPEED_2500:
+ adjust = IGC_I225_TX_LATENCY_2500;
+ break;
+ }
+
+ shhwtstamps.hwtstamp =
+ ktime_add_ns(shhwtstamps.hwtstamp, adjust);
+
+ tstamp->skb = NULL;
+
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
+}
+
/**
* igc_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure
*
- * If we were asked to do hardware stamping and such a time stamp is
- * available, then it must have been for this skb here because we only
- * allow only one such packet into the queue.
+ * Check against the ready mask for which of the timestamp register
+ * sets are ready to be retrieved, then retrieve that and notify the
+ * rest of the stack.
*
* Context: Expects adapter->ptp_tx_lock to be held by caller.
*/
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
{
- struct sk_buff *skb = adapter->ptp_tx_skb;
- struct skb_shared_hwtstamps shhwtstamps;
struct igc_hw *hw = &adapter->hw;
- u32 tsynctxctl;
- int adjust = 0;
u64 regval;
+ u32 mask;
+ int i;
- if (WARN_ON_ONCE(!skb))
- return;
-
- tsynctxctl = rd32(IGC_TSYNCTXCTL);
- tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0;
- if (tsynctxctl) {
+ mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
+ if (mask & IGC_TSYNCTXCTL_TXTT_0) {
regval = rd32(IGC_TXSTMPL);
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
} else {
@@ -742,37 +792,30 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
txstmpl_new = rd32(IGC_TXSTMPL);
if (txstmpl_old == txstmpl_new)
- return;
+ goto done;
regval = txstmpl_new;
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
}
- if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
- return;
- switch (adapter->link_speed) {
- case SPEED_10:
- adjust = IGC_I225_TX_LATENCY_10;
- break;
- case SPEED_100:
- adjust = IGC_I225_TX_LATENCY_100;
- break;
- case SPEED_1000:
- adjust = IGC_I225_TX_LATENCY_1000;
- break;
- case SPEED_2500:
- adjust = IGC_I225_TX_LATENCY_2500;
- break;
- }
+ igc_ptp_tx_reg_to_stamp(adapter, &adapter->tx_tstamp[0], regval);
- shhwtstamps.hwtstamp =
- ktime_add_ns(shhwtstamps.hwtstamp, adjust);
+done:
+ /* Now that the problematic first register was handled, we can
+ * use retrieve the timestamps from the other registers
+ * (starting from '1') with less complications.
+ */
+ for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
- adapter->ptp_tx_skb = NULL;
+ if (!(tstamp->mask & mask))
+ continue;
- /* Notify the stack and free the skb after we've unlocked */
- skb_tstamp_tx(skb, &shhwtstamps);
- dev_kfree_skb_any(skb);
+ regval = rd32(tstamp->regl);
+ regval |= (u64)rd32(tstamp->regh) << 32;
+
+ igc_ptp_tx_reg_to_stamp(adapter, tstamp, regval);
+ }
}
/**
@@ -788,12 +831,8 @@ void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter)
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
- if (!adapter->ptp_tx_skb)
- goto unlock;
-
igc_ptp_tx_hwtstamp(adapter);
-unlock:
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
@@ -1006,9 +1045,34 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
void igc_ptp_init(struct igc_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct igc_tx_timestamp_request *tstamp;
struct igc_hw *hw = &adapter->hw;
int i;
+ tstamp = &adapter->tx_tstamp[0];
+ tstamp->mask = IGC_TSYNCTXCTL_TXTT_0;
+ tstamp->regl = IGC_TXSTMPL_0;
+ tstamp->regh = IGC_TXSTMPH_0;
+ tstamp->flags = 0;
+
+ tstamp = &adapter->tx_tstamp[1];
+ tstamp->mask = IGC_TSYNCTXCTL_TXTT_1;
+ tstamp->regl = IGC_TXSTMPL_1;
+ tstamp->regh = IGC_TXSTMPH_1;
+ tstamp->flags = IGC_TX_FLAGS_TSTAMP_1;
+
+ tstamp = &adapter->tx_tstamp[2];
+ tstamp->mask = IGC_TSYNCTXCTL_TXTT_2;
+ tstamp->regl = IGC_TXSTMPL_2;
+ tstamp->regh = IGC_TXSTMPH_2;
+ tstamp->flags = IGC_TX_FLAGS_TSTAMP_2;
+
+ tstamp = &adapter->tx_tstamp[3];
+ tstamp->mask = IGC_TSYNCTXCTL_TXTT_3;
+ tstamp->regl = IGC_TXSTMPL_3;
+ tstamp->regh = IGC_TXSTMPH_3;
+ tstamp->flags = IGC_TX_FLAGS_TSTAMP_3;
+
switch (hw->mac.type) {
case igc_i225:
for (i = 0; i < IGC_N_SDP; i++) {
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h
index dba5a5759b1c..20e17f5fbce3 100644
--- a/drivers/net/ethernet/intel/igc/igc_regs.h
+++ b/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -243,6 +243,18 @@
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
+/* TX Timestamp Low */
+#define IGC_TXSTMPL_0 0x0B618
+#define IGC_TXSTMPL_1 0x0B698
+#define IGC_TXSTMPL_2 0x0B6B8
+#define IGC_TXSTMPL_3 0x0B6D8
+
+/* TX Timestamp High */
+#define IGC_TXSTMPH_0 0x0B61C
+#define IGC_TXSTMPH_1 0x0B69C
+#define IGC_TXSTMPH_2 0x0B6BC
+#define IGC_TXSTMPH_3 0x0B6DC
+
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 63d4e32df029..b6f0376e42f4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -945,8 +945,6 @@ void ixgbe_update_pf_promisc_vlvf(struct ixgbe_adapter *adapter, u32 vid);
void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *,
struct ixgbe_ring *);
-void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *,
- struct ixgbe_tx_buffer *);
void ixgbe_alloc_rx_buffers(struct ixgbe_ring *, u16);
void ixgbe_write_eitr(struct ixgbe_q_vector *);
int ixgbe_poll(struct napi_struct *napi, int budget);
@@ -997,10 +995,6 @@ int ixgbe_setup_fcoe_ddp_resources(struct ixgbe_adapter *adapter);
void ixgbe_free_fcoe_ddp_resources(struct ixgbe_adapter *adapter);
int ixgbe_fcoe_enable(struct net_device *netdev);
int ixgbe_fcoe_disable(struct net_device *netdev);
-#ifdef CONFIG_IXGBE_DCB
-u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter);
-u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up);
-#endif /* CONFIG_IXGBE_DCB */
int ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type);
int ixgbe_fcoe_get_hbainfo(struct net_device *netdev,
struct netdev_fcoe_hbainfo *info);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index 4b531e8ae38a..34761e691d52 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -8,7 +8,6 @@
#include "ixgbe.h"
u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw);
-s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw);
s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw);
s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 8eb9839a3ca6..dd03b017dfc5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -10042,9 +10042,6 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
- if (nla_len(attr) < sizeof(mode))
- return -EINVAL;
-
mode = nla_get_u16(attr);
status = ixgbe_configure_bridge_mode(adapter, mode);
if (status)
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 149c733fcc2b..130cb868774c 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -486,9 +486,6 @@ static inline int ixgbevf_ipsec_tx(struct ixgbevf_ring *tx_ring,
{ return 0; }
#endif /* CONFIG_IXGBEVF_IPSEC */
-void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter);
-void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter);
-
#define ixgbevf_hw_to_netdev(hw) \
(((struct ixgbevf_adapter *)(hw)->back)->netdev)
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index 8537578e1cf1..5f6ae11212ae 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -43,7 +43,7 @@
#include <linux/ioport.h>
#include <linux/iopoll.h>
#include <linux/in.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 8662543ca5c8..674913184ebf 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -24,8 +24,8 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
@@ -269,7 +269,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
struct orion_mdio_dev *dev;
int i, ret;
- type = (enum orion_mdio_bus_type)device_get_match_data(&pdev->dev);
+ type = (uintptr_t)device_get_match_data(&pdev->dev);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index acf4f6ba73a6..d483b8c00ec0 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -37,7 +37,7 @@
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/tso.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/pkt_sched.h>
#include <linux/bpf_trace.h>
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 11e603686a27..e809f91c08fb 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -16,7 +16,7 @@
#include <linux/phy.h>
#include <linux/phylink.h>
#include <net/flow_offload.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <linux/bpf.h>
#include <net/xdp.h>
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
index 75e83ea2a926..0f9bc4f8ec3b 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c
@@ -593,8 +593,6 @@ static int mvpp2_dbgfs_c2_entry_init(struct dentry *parent,
sprintf(c2_entry_name, "%03d", id);
c2_entry_dir = debugfs_create_dir(c2_entry_name, parent);
- if (!c2_entry_dir)
- return -ENOMEM;
entry = &priv->dbgfs_entries->c2_entries[id];
@@ -626,8 +624,6 @@ static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
sprintf(flow_tbl_entry_name, "%03d", id);
flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
- if (!flow_tbl_entry_dir)
- return -ENOMEM;
entry = &priv->dbgfs_entries->flt_entries[id];
@@ -646,12 +642,8 @@ static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
int i, ret;
cls_dir = debugfs_create_dir("classifier", parent);
- if (!cls_dir)
- return -ENOMEM;
c2_dir = debugfs_create_dir("c2", cls_dir);
- if (!c2_dir)
- return -ENOMEM;
for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
@@ -660,8 +652,6 @@ static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
}
flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
- if (!flow_tbl_dir)
- return -ENOMEM;
for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 1fec84b4c068..eb74ccddb440 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -24,7 +24,6 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/phy/phy.h>
@@ -36,6 +35,7 @@
#include <uapi/linux/ppp_defs.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <net/page_pool/helpers.h>
#include <net/tso.h>
#include <linux/bpf_trace.h>
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cp_version.h b/drivers/net/ethernet/marvell/octeon_ep/octep_cp_version.h
new file mode 100644
index 000000000000..0c741e752db6
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cp_version.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+#ifndef __OCTEP_CP_VERSION_H__
+#define __OCTEP_CP_VERSION_H__
+
+#define OCTEP_CP_VERSION(a, b, c) ((((a) & 0xff) << 16) + \
+ (((b) & 0xff) << 8) + \
+ ((c) & 0xff))
+
+#endif /* __OCTEP_CP_VERSION_H__ */
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c
index dab61cc1acb5..9d53c1402cb4 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.c
@@ -37,7 +37,9 @@
#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(m) (m)
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(m) ((m) + 8)
+#define OCTEP_CTRL_MBOX_INFO_HOST_VERSION(m) ((m) + 16)
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS(m) ((m) + 24)
+#define OCTEP_CTRL_MBOX_INFO_FW_VERSION(m) ((m) + 136)
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS(m) ((m) + 144)
#define OCTEP_CTRL_MBOX_H2FQ_INFO(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ)
@@ -71,7 +73,7 @@ static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
{
- u64 magic_num, status;
+ u64 magic_num, status, fw_versions;
if (!mbox)
return -EINVAL;
@@ -93,6 +95,9 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
return -EINVAL;
}
+ fw_versions = readq(OCTEP_CTRL_MBOX_INFO_FW_VERSION(mbox->barmem));
+ mbox->min_fw_version = ((fw_versions & 0xffffffff00000000ull) >> 32);
+ mbox->max_fw_version = (fw_versions & 0xffffffff);
mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));
writeq(OCTEP_CTRL_MBOX_STATUS_INIT,
@@ -113,6 +118,7 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +
mbox->h2fq.sz;
+ writeq(mbox->version, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem));
/* ensure ready state is seen after everything is initialized */
wmb();
writeq(OCTEP_CTRL_MBOX_STATUS_READY,
@@ -258,6 +264,7 @@ int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
if (!mbox->barmem)
return -EINVAL;
+ writeq(0, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem));
writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
/* ensure uninit state is written before uninitialization */
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
index 9c4ff0fba6a0..7f8135788efc 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
@@ -121,6 +121,8 @@ struct octep_ctrl_mbox_q {
};
struct octep_ctrl_mbox {
+ /* control plane version */
+ u64 version;
/* size of bar memory */
u32 barmem_sz;
/* pointer to BAR memory */
@@ -133,6 +135,10 @@ struct octep_ctrl_mbox {
struct mutex h2fq_lock;
/* lock for f2hq */
struct mutex f2hq_lock;
+ /* Min control plane version supported by firmware */
+ u32 min_fw_version;
+ /* Max control plane version supported by firmware */
+ u32 max_fw_version;
};
/* Initialize control mbox.
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
index 565320ec24f8..17bfd5cdf462 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
@@ -14,6 +14,9 @@
#include "octep_main.h"
#include "octep_ctrl_net.h"
+/* Control plane version */
+#define OCTEP_CP_VERSION_CURRENT OCTEP_CP_VERSION(1, 0, 0)
+
static const u32 req_hdr_sz = sizeof(union octep_ctrl_net_req_hdr);
static const u32 mtu_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mtu);
static const u32 mac_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mac);
@@ -21,6 +24,18 @@ static const u32 state_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_state);
static const u32 link_info_sz = sizeof(struct octep_ctrl_net_link_info);
static atomic_t ctrl_net_msg_id;
+/* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */
+static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = {
+ [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_LINK_INFO] =
+ OCTEP_CP_VERSION(1, 0, 0)
+};
+
+/* Control plane version in which OCTEP_CTRL_NET_F2H_CMD was added */
+static const u32 octep_ctrl_net_f2h_cmd_versions[OCTEP_CTRL_NET_F2H_CMD_MAX] = {
+ [OCTEP_CTRL_NET_F2H_CMD_INVALID ... OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS] =
+ OCTEP_CP_VERSION(1, 0, 0)
+};
+
static void init_send_req(struct octep_ctrl_mbox_msg *msg, void *buf,
u16 sz, int vfid)
{
@@ -41,7 +56,13 @@ static int octep_send_mbox_req(struct octep_device *oct,
struct octep_ctrl_net_wait_data *d,
bool wait_for_response)
{
- int err, ret;
+ int err, ret, cmd;
+
+ /* check if firmware is compatible for this request */
+ cmd = d->data.req.hdr.s.cmd;
+ if (octep_ctrl_net_h2f_cmd_versions[cmd] > oct->ctrl_mbox.max_fw_version ||
+ octep_ctrl_net_h2f_cmd_versions[cmd] < oct->ctrl_mbox.min_fw_version)
+ return -EOPNOTSUPP;
err = octep_ctrl_mbox_send(&oct->ctrl_mbox, &d->msg);
if (err < 0)
@@ -84,12 +105,16 @@ int octep_ctrl_net_init(struct octep_device *oct)
/* Initialize control mbox */
ctrl_mbox = &oct->ctrl_mbox;
+ ctrl_mbox->version = OCTEP_CP_VERSION_CURRENT;
ctrl_mbox->barmem = CFG_GET_CTRL_MBOX_MEM_ADDR(oct->conf);
ret = octep_ctrl_mbox_init(ctrl_mbox);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize control mbox\n");
return ret;
}
+ dev_info(&pdev->dev, "Control plane versions host: %llx, firmware: %x:%x\n",
+ ctrl_mbox->version, ctrl_mbox->min_fw_version,
+ ctrl_mbox->max_fw_version);
oct->ctrl_mbox_ifstats_offset = ctrl_mbox->barmem_sz;
return 0;
@@ -273,9 +298,17 @@ static int process_mbox_notify(struct octep_device *oct,
{
struct net_device *netdev = oct->netdev;
struct octep_ctrl_net_f2h_req *req;
+ int cmd;
req = (struct octep_ctrl_net_f2h_req *)msg->sg_list[0].msg;
- switch (req->hdr.s.cmd) {
+ cmd = req->hdr.s.cmd;
+
+ /* check if we support this command */
+ if (octep_ctrl_net_f2h_cmd_versions[cmd] > OCTEP_CP_VERSION_CURRENT ||
+ octep_ctrl_net_f2h_cmd_versions[cmd] < OCTEP_CP_VERSION_CURRENT)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:
if (netif_running(netdev)) {
if (req->link.state) {
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
index 37880dd79116..1c2ef4ee31d9 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
@@ -7,6 +7,8 @@
#ifndef __OCTEP_CTRL_NET_H__
#define __OCTEP_CTRL_NET_H__
+#include "octep_cp_version.h"
+
#define OCTEP_CTRL_NET_INVALID_VFID (-1)
/* Supported commands */
@@ -39,12 +41,14 @@ enum octep_ctrl_net_h2f_cmd {
OCTEP_CTRL_NET_H2F_CMD_LINK_STATUS,
OCTEP_CTRL_NET_H2F_CMD_RX_STATE,
OCTEP_CTRL_NET_H2F_CMD_LINK_INFO,
+ OCTEP_CTRL_NET_H2F_CMD_MAX
};
/* Supported fw to host commands */
enum octep_ctrl_net_f2h_cmd {
OCTEP_CTRL_NET_F2H_CMD_INVALID = 0,
OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS,
+ OCTEP_CTRL_NET_F2H_CMD_MAX
};
union octep_ctrl_net_req_hdr {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index 592037f4e55b..e06f77ad6106 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -55,6 +55,7 @@ static const char *cgx_lmactype_string[LMAC_MODE_MAX] = {
[LMAC_MODE_50G_R] = "50G_R",
[LMAC_MODE_100G_R] = "100G_R",
[LMAC_MODE_USXGMII] = "USXGMII",
+ [LMAC_MODE_USGMII] = "USGMII",
};
/* CGX PHY management internal APIs */
@@ -223,24 +224,6 @@ int cgx_get_link_info(void *cgxd, int lmac_id,
return 0;
}
-static u64 mac2u64 (u8 *mac_addr)
-{
- u64 mac = 0;
- int index;
-
- for (index = ETH_ALEN - 1; index >= 0; index--)
- mac |= ((u64)*mac_addr++) << (8 * index);
- return mac;
-}
-
-static void cfg2mac(u64 cfg, u8 *mac_addr)
-{
- int i, index = 0;
-
- for (i = ETH_ALEN - 1; i >= 0; i--, index++)
- mac_addr[i] = (cfg >> (8 * index)) & 0xFF;
-}
-
int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
{
struct cgx *cgx_dev = cgx_get_pdata(cgx_id);
@@ -249,13 +232,16 @@ int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
int index, id;
u64 cfg;
+ if (!lmac)
+ return -ENODEV;
+
/* access mac_ops to know csr_offset */
mac_ops = cgx_dev->mac_ops;
/* copy 6bytes from macaddr */
/* memcpy(&cfg, mac_addr, 6); */
- cfg = mac2u64 (mac_addr);
+ cfg = ether_addr_to_u64(mac_addr);
id = get_sequence_id_of_lmac(cgx_dev, lmac_id);
@@ -322,7 +308,7 @@ int cgx_lmac_addr_add(u8 cgx_id, u8 lmac_id, u8 *mac_addr)
index = id * lmac->mac_to_index_bmap.max + idx;
- cfg = mac2u64 (mac_addr);
+ cfg = ether_addr_to_u64(mac_addr);
cfg |= CGX_DMAC_CAM_ADDR_ENABLE;
cfg |= ((u64)lmac_id << 49);
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
@@ -405,7 +391,7 @@ int cgx_lmac_addr_update(u8 cgx_id, u8 lmac_id, u8 *mac_addr, u8 index)
cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
cfg &= ~CGX_RX_DMAC_ADR_MASK;
- cfg |= mac2u64 (mac_addr);
+ cfg |= ether_addr_to_u64(mac_addr);
cgx_write(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)), cfg);
return 0;
@@ -441,7 +427,7 @@ int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index)
/* Read MAC address to check whether it is ucast or mcast */
cfg = cgx_read(cgx_dev, 0, (CGXX_CMRX_RX_DMAC_CAM0 + (index * 0x8)));
- cfg2mac(cfg, mac);
+ u64_to_ether_addr(cfg, mac);
if (is_multicast_ether_addr(mac))
lmac->mcast_filters_count--;
@@ -567,15 +553,16 @@ void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable)
{
struct cgx *cgx = cgx_get_pdata(cgx_id);
struct lmac *lmac = lmac_pdata(lmac_id, cgx);
- u16 max_dmac = lmac->mac_to_index_bmap.max;
struct mac_ops *mac_ops;
+ u16 max_dmac;
int index, i;
u64 cfg = 0;
int id;
- if (!cgx)
+ if (!cgx || !lmac)
return;
+ max_dmac = lmac->mac_to_index_bmap.max;
id = get_sequence_id_of_lmac(cgx, lmac_id);
mac_ops = cgx->mac_ops;
@@ -748,7 +735,7 @@ int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp)
int corr_reg, uncorr_reg;
struct cgx *cgx = cgxd;
- if (!cgx || lmac_id >= cgx->lmac_count)
+ if (!is_lmac_valid(cgx, lmac_id))
return -ENODEV;
if (cgx->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_NONE)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 574114179688..6f7d1dee5830 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -110,6 +110,7 @@ enum LMAC_TYPE {
LMAC_MODE_50G_R = 8,
LMAC_MODE_100G_R = 9,
LMAC_MODE_USXGMII = 10,
+ LMAC_MODE_USGMII = 11,
LMAC_MODE_MAX,
};
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index eba307eee2b2..6b5b06c2b4e9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -136,6 +136,7 @@ M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \
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) \
/* 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) \
@@ -235,7 +236,7 @@ M(NPC_GET_KEX_CFG, 0x600c, npc_get_kex_cfg, \
M(NPC_INSTALL_FLOW, 0x600d, npc_install_flow, \
npc_install_flow_req, npc_install_flow_rsp) \
M(NPC_DELETE_FLOW, 0x600e, npc_delete_flow, \
- npc_delete_flow_req, msg_rsp) \
+ npc_delete_flow_req, npc_delete_flow_rsp) \
M(NPC_MCAM_READ_ENTRY, 0x600f, npc_mcam_read_entry, \
npc_mcam_read_entry_req, \
npc_mcam_read_entry_rsp) \
@@ -1437,6 +1438,12 @@ struct npc_get_kex_cfg_rsp {
u8 mkex_pfl_name[MKEX_NAME_LEN];
};
+struct ptp_get_cap_rsp {
+ struct mbox_msghdr hdr;
+#define PTP_CAP_HW_ATOMIC_UPDATE BIT_ULL(0)
+ u64 cap;
+};
+
struct flow_msg {
unsigned char dmac[6];
unsigned char smac[6];
@@ -1451,6 +1458,10 @@ struct flow_msg {
__be32 ip4dst;
__be32 ip6dst[4];
};
+ union {
+ __be32 spi;
+ };
+
u8 tos;
u8 ip_ver;
u8 ip_proto;
@@ -1461,6 +1472,7 @@ struct flow_msg {
u8 ip_flag;
u8 next_header;
};
+ __be16 vlan_itci;
};
struct npc_install_flow_req {
@@ -1491,6 +1503,8 @@ struct npc_install_flow_req {
u8 vtag0_op;
u16 vtag1_def;
u8 vtag1_op;
+ /* old counter value */
+ u16 cntr_val;
};
struct npc_install_flow_rsp {
@@ -1506,6 +1520,11 @@ struct npc_delete_flow_req {
u8 all; /* PF + VFs */
};
+struct npc_delete_flow_rsp {
+ struct mbox_msghdr hdr;
+ u16 cntr_val;
+};
+
struct npc_mcam_read_entry_req {
struct mbox_msghdr hdr;
u16 entry; /* MCAM entry to read */
@@ -1556,6 +1575,8 @@ enum ptp_op {
PTP_OP_GET_TSTMP = 2,
PTP_OP_SET_THRESH = 3,
PTP_OP_EXTTS_ON = 4,
+ PTP_OP_ADJTIME = 5,
+ PTP_OP_SET_CLOCK = 6,
};
struct ptp_req {
@@ -1564,11 +1585,14 @@ struct ptp_req {
s64 scaled_ppm;
u64 thresh;
int extts_on;
+ s64 delta;
+ u64 clk;
};
struct ptp_rsp {
struct mbox_msghdr hdr;
u64 clk;
+ u64 tsc;
};
struct npc_get_field_status_req {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
index 9beeead56d7b..de9fbd98dfb7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -184,6 +184,7 @@ enum key_fields {
NPC_VLAN_ETYPE_CTAG, /* 0x8100 */
NPC_VLAN_ETYPE_STAG, /* 0x88A8 */
NPC_OUTER_VID,
+ NPC_INNER_VID,
NPC_TOS,
NPC_IPFRAG_IPV4,
NPC_SIP_IPV4,
@@ -204,6 +205,7 @@ enum key_fields {
NPC_DPORT_UDP,
NPC_SPORT_SCTP,
NPC_DPORT_SCTP,
+ NPC_IPSEC_SPI,
NPC_HEADER_FIELDS_MAX,
NPC_CHAN = NPC_HEADER_FIELDS_MAX, /* Valid when Rx */
NPC_PF_FUNC, /* Valid when Tx */
@@ -229,6 +231,8 @@ enum key_fields {
NPC_VLAN_TAG1,
/* outer vlan tci for double tagged frame */
NPC_VLAN_TAG2,
+ /* inner vlan tci for double tagged frame */
+ NPC_VLAN_TAG3,
/* other header fields programmed to extract but not of our interest */
NPC_UNKNOWN,
NPC_KEY_FIELDS_MAX,
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/ptp.c b/drivers/net/ethernet/marvell/octeontx2/af/ptp.c
index 0ee420a489fc..ffbd22797163 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/ptp.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/ptp.c
@@ -12,8 +12,8 @@
#include <linux/hrtimer.h>
#include <linux/ktime.h>
-#include "ptp.h"
#include "mbox.h"
+#include "ptp.h"
#include "rvu.h"
#define DRV_NAME "Marvell PTP Driver"
@@ -40,6 +40,7 @@
#define PTP_CLOCK_CFG_TSTMP_EDGE BIT_ULL(9)
#define PTP_CLOCK_CFG_TSTMP_EN BIT_ULL(8)
#define PTP_CLOCK_CFG_TSTMP_IN_MASK GENMASK_ULL(15, 10)
+#define PTP_CLOCK_CFG_ATOMIC_OP_MASK GENMASK_ULL(28, 26)
#define PTP_CLOCK_CFG_PPS_EN BIT_ULL(30)
#define PTP_CLOCK_CFG_PPS_INV BIT_ULL(31)
@@ -53,36 +54,62 @@
#define PTP_TIMESTAMP 0xF20ULL
#define PTP_CLOCK_SEC 0xFD0ULL
#define PTP_SEC_ROLLOVER 0xFD8ULL
+/* Atomic update related CSRs */
+#define PTP_FRNS_TIMESTAMP 0xFE0ULL
+#define PTP_NXT_ROLLOVER_SET 0xFE8ULL
+#define PTP_CURR_ROLLOVER_SET 0xFF0ULL
+#define PTP_NANO_TIMESTAMP 0xFF8ULL
+#define PTP_SEC_TIMESTAMP 0x1000ULL
#define CYCLE_MULT 1000
+#define is_rev_A0(ptp) (((ptp)->pdev->revision & 0x0F) == 0x0)
+#define is_rev_A1(ptp) (((ptp)->pdev->revision & 0x0F) == 0x1)
+
+/* PTP atomic update operation type */
+enum atomic_opcode {
+ ATOMIC_SET = 1,
+ ATOMIC_INC = 3,
+ ATOMIC_DEC = 4
+};
+
static struct ptp *first_ptp_block;
static const struct pci_device_id ptp_id_table[];
-static bool is_ptp_dev_cnf10kb(struct ptp *ptp)
+static bool is_ptp_dev_cnf10ka(struct ptp *ptp)
{
- return (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_B_PTP) ? true : false;
+ return ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP;
}
-static bool is_ptp_dev_cn10k(struct ptp *ptp)
+static bool is_ptp_dev_cn10ka(struct ptp *ptp)
{
- return (ptp->pdev->device == PCI_DEVID_CN10K_PTP) ? true : false;
+ return ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP;
}
static bool cn10k_ptp_errata(struct ptp *ptp)
{
- if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
- ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
+ if ((is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) &&
+ (is_rev_A0(ptp) || is_rev_A1(ptp)))
return true;
+
return false;
}
-static bool is_ptp_tsfmt_sec_nsec(struct ptp *ptp)
+static bool is_tstmp_atomic_update_supported(struct rvu *rvu)
{
- if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
- ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
- return true;
- return false;
+ struct ptp *ptp = rvu->ptp;
+
+ if (is_rvu_otx2(rvu))
+ return false;
+
+ /* On older silicon variants of CN10K, atomic update feature
+ * is not available.
+ */
+ if ((is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) &&
+ (is_rev_A0(ptp) || is_rev_A1(ptp)))
+ return false;
+
+ return true;
}
static enum hrtimer_restart ptp_reset_thresh(struct hrtimer *hrtimer)
@@ -222,6 +249,65 @@ void ptp_put(struct ptp *ptp)
pci_dev_put(ptp->pdev);
}
+static void ptp_atomic_update(struct ptp *ptp, u64 timestamp)
+{
+ u64 regval, curr_rollover_set, nxt_rollover_set;
+
+ /* First setup NSECs and SECs */
+ writeq(timestamp, ptp->reg_base + PTP_NANO_TIMESTAMP);
+ writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
+ writeq(timestamp / NSEC_PER_SEC,
+ ptp->reg_base + PTP_SEC_TIMESTAMP);
+
+ nxt_rollover_set = roundup(timestamp, NSEC_PER_SEC);
+ curr_rollover_set = nxt_rollover_set - NSEC_PER_SEC;
+ writeq(nxt_rollover_set, ptp->reg_base + PTP_NXT_ROLLOVER_SET);
+ writeq(curr_rollover_set, ptp->reg_base + PTP_CURR_ROLLOVER_SET);
+
+ /* Now, initiate atomic update */
+ regval = readq(ptp->reg_base + PTP_CLOCK_CFG);
+ regval &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
+ regval |= (ATOMIC_SET << 26);
+ writeq(regval, ptp->reg_base + PTP_CLOCK_CFG);
+}
+
+static void ptp_atomic_adjtime(struct ptp *ptp, s64 delta)
+{
+ bool neg_adj = false, atomic_inc_dec = false;
+ u64 regval, ptp_clock_hi;
+
+ if (delta < 0) {
+ delta = -delta;
+ neg_adj = true;
+ }
+
+ /* use atomic inc/dec when delta < 1 second */
+ if (delta < NSEC_PER_SEC)
+ atomic_inc_dec = true;
+
+ if (!atomic_inc_dec) {
+ ptp_clock_hi = readq(ptp->reg_base + PTP_CLOCK_HI);
+ if (neg_adj) {
+ if (ptp_clock_hi > delta)
+ ptp_clock_hi -= delta;
+ else
+ ptp_clock_hi = delta - ptp_clock_hi;
+ } else {
+ ptp_clock_hi += delta;
+ }
+ ptp_atomic_update(ptp, ptp_clock_hi);
+ } else {
+ writeq(delta, ptp->reg_base + PTP_NANO_TIMESTAMP);
+ writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
+
+ /* initiate atomic inc/dec */
+ regval = readq(ptp->reg_base + PTP_CLOCK_CFG);
+ regval &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
+ regval |= neg_adj ? (ATOMIC_DEC << 26) : (ATOMIC_INC << 26);
+ writeq(regval, ptp->reg_base + PTP_CLOCK_CFG);
+ }
+}
+
static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
{
bool neg_adj = false;
@@ -277,8 +363,9 @@ static int ptp_get_clock(struct ptp *ptp, u64 *clk)
return 0;
}
-void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
+void ptp_start(struct rvu *rvu, u64 sclk, u32 ext_clk_freq, u32 extts)
{
+ struct ptp *ptp = rvu->ptp;
struct pci_dev *pdev;
u64 clock_comp;
u64 clock_cfg;
@@ -297,8 +384,14 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
ptp->clock_rate = sclk * 1000000;
/* Program the seconds rollover value to 1 second */
- if (is_ptp_dev_cnf10kb(ptp))
+ if (is_tstmp_atomic_update_supported(rvu)) {
+ writeq(0, ptp->reg_base + PTP_NANO_TIMESTAMP);
+ writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
+ writeq(0, ptp->reg_base + PTP_SEC_TIMESTAMP);
+ writeq(0, ptp->reg_base + PTP_CURR_ROLLOVER_SET);
+ writeq(0x3b9aca00, ptp->reg_base + PTP_NXT_ROLLOVER_SET);
writeq(0x3b9aca00, ptp->reg_base + PTP_SEC_ROLLOVER);
+ }
/* Enable PTP clock */
clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
@@ -320,6 +413,10 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
clock_cfg |= PTP_CLOCK_CFG_PPS_EN | PTP_CLOCK_CFG_PPS_INV;
writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
+ clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
+ clock_cfg &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
+ clock_cfg |= (ATOMIC_SET << 26);
+ writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
/* Set 50% duty cycle for 1Hz output */
writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR);
@@ -350,7 +447,7 @@ static int ptp_get_tstmp(struct ptp *ptp, u64 *clk)
{
u64 timestamp;
- if (is_ptp_dev_cn10k(ptp)) {
+ if (is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) {
timestamp = readq(ptp->reg_base + PTP_TIMESTAMP);
*clk = (timestamp >> 32) * NSEC_PER_SEC + (timestamp & 0xFFFFFFFF);
} else {
@@ -414,14 +511,12 @@ static int ptp_probe(struct pci_dev *pdev,
first_ptp_block = ptp;
spin_lock_init(&ptp->ptp_lock);
- if (is_ptp_tsfmt_sec_nsec(ptp))
- ptp->read_ptp_tstmp = &read_ptp_tstmp_sec_nsec;
- else
- ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;
-
if (cn10k_ptp_errata(ptp)) {
+ ptp->read_ptp_tstmp = &read_ptp_tstmp_sec_nsec;
hrtimer_init(&ptp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ptp->hrtimer.function = ptp_reset_thresh;
+ } else {
+ ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;
}
return 0;
@@ -521,6 +616,12 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
case PTP_OP_EXTTS_ON:
err = ptp_extts_on(rvu->ptp, req->extts_on);
break;
+ case PTP_OP_ADJTIME:
+ ptp_atomic_adjtime(rvu->ptp, req->delta);
+ break;
+ case PTP_OP_SET_CLOCK:
+ ptp_atomic_update(rvu->ptp, (u64)req->clk);
+ break;
default:
err = -EINVAL;
break;
@@ -528,3 +629,17 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
return err;
}
+
+int rvu_mbox_handler_ptp_get_cap(struct rvu *rvu, struct msg_req *req,
+ struct ptp_get_cap_rsp *rsp)
+{
+ if (!rvu->ptp)
+ return -ENODEV;
+
+ if (is_tstmp_atomic_update_supported(rvu))
+ rsp->cap |= PTP_CAP_HW_ATOMIC_UPDATE;
+ else
+ rsp->cap &= ~BIT_ULL_MASK(0);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/ptp.h b/drivers/net/ethernet/marvell/octeontx2/af/ptp.h
index b9d92abc3844..1229344c7279 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/ptp.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/ptp.h
@@ -23,9 +23,10 @@ struct ptp {
u32 clock_period;
};
+struct rvu;
struct ptp *ptp_get(void);
void ptp_put(struct ptp *ptp);
-void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts);
+void ptp_start(struct rvu *rvu, u64 sclk, u32 ext_clk_freq, u32 extts);
extern struct pci_driver ptp_driver;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
index b4fcb20c3f4f..af21e2030cff 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
@@ -355,8 +355,8 @@ int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
{
+ u64 cfg, pfc_class_mask_cfg;
rpm_t *rpm = rpmd;
- u64 cfg;
/* ALL pause frames received are completely ignored */
cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
@@ -380,9 +380,11 @@ void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
rpm_write(rpm, 0, RPMX_CMR_CHAN_MSK_OR, ~0ULL);
/* Disable all PFC classes */
- cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL);
+ pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL :
+ RPMX_CMRX_PRT_CBFC_CTL;
+ cfg = rpm_read(rpm, lmac_id, pfc_class_mask_cfg);
cfg = FIELD_SET(RPM_PFC_CLASS_MASK, 0, cfg);
- rpm_write(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL, cfg);
+ rpm_write(rpm, lmac_id, pfc_class_mask_cfg, cfg);
}
int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat)
@@ -605,8 +607,11 @@ int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 p
if (!is_lmac_valid(rpm, lmac_id))
return -ENODEV;
+ pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL :
+ RPMX_CMRX_PRT_CBFC_CTL;
+
cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
- class_en = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL);
+ class_en = rpm_read(rpm, lmac_id, pfc_class_mask_cfg);
pfc_en |= FIELD_GET(RPM_PFC_CLASS_MASK, class_en);
if (rx_pause) {
@@ -635,10 +640,6 @@ int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 p
cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
-
- pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL :
- RPMX_CMRX_PRT_CBFC_CTL;
-
rpm_write(rpm, lmac_id, pfc_class_mask_cfg, class_en);
return 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index 73df2d564545..22c395c7d040 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -3322,7 +3322,7 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&rvu->rswitch.switch_lock);
if (rvu->fwdata)
- ptp_start(rvu->ptp, rvu->fwdata->sclk, rvu->fwdata->ptp_ext_clk_rate,
+ ptp_start(rvu, rvu->fwdata->sclk, rvu->fwdata->ptp_ext_clk_rate,
rvu->fwdata->ptp_ext_tstamp);
return 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index e8e65fd7888d..c4d999ef5ab4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -17,6 +17,7 @@
#include "mbox.h"
#include "npc.h"
#include "rvu_reg.h"
+#include "ptp.h"
/* PCI device IDs */
#define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065
@@ -26,6 +27,7 @@
#define PCI_SUBSYS_DEVID_98XX 0xB100
#define PCI_SUBSYS_DEVID_96XX 0xB200
#define PCI_SUBSYS_DEVID_CN10K_A 0xB900
+#define PCI_SUBSYS_DEVID_CNF10K_A 0xBA00
#define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00
#define PCI_SUBSYS_DEVID_CN10K_B 0xBD00
@@ -634,6 +636,16 @@ static inline bool is_rvu_otx2(struct rvu *rvu)
midr == PCI_REVISION_ID_95XXMM || midr == PCI_REVISION_ID_95XXO);
}
+static inline bool is_cnf10ka_a0(struct rvu *rvu)
+{
+ struct pci_dev *pdev = rvu->pdev;
+
+ if (pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A &&
+ (pdev->revision & 0x0F) == 0x0)
+ return true;
+ return false;
+}
+
static inline bool is_rvu_npc_hash_extract_en(struct rvu *rvu)
{
u64 npc_const3;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 095b2cc4a699..f2b1edf1bb43 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -236,6 +236,11 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
linfo = &event->link_uinfo;
pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id);
+ if (!pfmap) {
+ dev_err(rvu->dev, "CGX port%d:%d not mapped with PF\n",
+ event->cgx_id, event->lmac_id);
+ return;
+ }
do {
pfid = find_first_bit(&pfmap,
@@ -345,7 +350,7 @@ int rvu_cgx_init(struct rvu *rvu)
rvu->cgx_cnt_max = cgx_get_cgxcnt_max();
if (!rvu->cgx_cnt_max) {
dev_info(rvu->dev, "No CGX devices found!\n");
- return -ENODEV;
+ return 0;
}
rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt_max *
@@ -686,7 +691,7 @@ int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
{
int pf = rvu_get_pf(req->hdr.pcifunc);
u8 cgx_id, lmac_id;
- int rc = 0, i;
+ int rc = 0;
u64 cfg;
if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
@@ -697,8 +702,7 @@ int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
rsp->hdr.rc = rc;
cfg = cgx_lmac_addr_get(cgx_id, lmac_id);
/* copy 48 bit mac address to req->mac_addr */
- for (i = 0; i < ETH_ALEN; i++)
- rsp->mac_addr[i] = cfg >> (ETH_ALEN - 1 - i) * 8;
+ u64_to_ether_addr(cfg, rsp->mac_addr);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index 3b26893efdf8..d30e84803481 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -2787,6 +2787,11 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
seq_printf(s, "mask 0x%x\n",
ntohs(rule->mask.vlan_tci));
break;
+ case NPC_INNER_VID:
+ seq_printf(s, "0x%x ", ntohs(rule->packet.vlan_itci));
+ seq_printf(s, "mask 0x%x\n",
+ ntohs(rule->mask.vlan_itci));
+ break;
case NPC_TOS:
seq_printf(s, "%d ", rule->packet.tos);
seq_printf(s, "mask 0x%x\n", rule->mask.tos);
@@ -2827,6 +2832,10 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
seq_printf(s, "%d ", ntohs(rule->packet.dport));
seq_printf(s, "mask 0x%x\n", ntohs(rule->mask.dport));
break;
+ case NPC_IPSEC_SPI:
+ seq_printf(s, "0x%x ", ntohl(rule->packet.spi));
+ seq_printf(s, "mask 0x%x\n", ntohl(rule->mask.spi));
+ break;
default:
seq_puts(s, "\n");
break;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 04b0e885f9d2..c2f68678e947 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -4270,9 +4270,10 @@ rx_frscfg:
if (link < 0)
return NIX_AF_ERR_RX_LINK_INVALID;
- nix_find_link_frs(rvu, req, pcifunc);
linkcfg:
+ nix_find_link_frs(rvu, req, pcifunc);
+
cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_LINKX_CFG(link));
cfg = (cfg & ~(0xFFFFULL << 16)) | ((u64)req->maxlen << 16);
if (req->update_minlen)
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 952319453701..237f82082ebe 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -20,6 +20,7 @@ static const char * const npc_flow_names[] = {
[NPC_VLAN_ETYPE_CTAG] = "vlan ether type ctag",
[NPC_VLAN_ETYPE_STAG] = "vlan ether type stag",
[NPC_OUTER_VID] = "outer vlan id",
+ [NPC_INNER_VID] = "inner vlan id",
[NPC_TOS] = "tos",
[NPC_IPFRAG_IPV4] = "fragmented IPv4 header ",
[NPC_SIP_IPV4] = "ipv4 source ip",
@@ -41,6 +42,7 @@ static const char * const npc_flow_names[] = {
[NPC_SPORT_SCTP] = "sctp source port",
[NPC_DPORT_SCTP] = "sctp destination port",
[NPC_LXMB] = "Mcast/Bcast header ",
+ [NPC_IPSEC_SPI] = "SPI ",
[NPC_UNKNOWN] = "unknown",
};
@@ -327,6 +329,8 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
*/
struct npc_key_field *vlan_tag1;
struct npc_key_field *vlan_tag2;
+ /* Inner VLAN TCI for double tagged frames */
+ struct npc_key_field *vlan_tag3;
u64 *features;
u8 start_lid;
int i;
@@ -349,6 +353,7 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
etype_tag2 = &key_fields[NPC_ETYPE_TAG2];
vlan_tag1 = &key_fields[NPC_VLAN_TAG1];
vlan_tag2 = &key_fields[NPC_VLAN_TAG2];
+ vlan_tag3 = &key_fields[NPC_VLAN_TAG3];
/* if key profile programmed does not extract Ethertype at all */
if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) {
@@ -430,6 +435,12 @@ vlan_tci:
goto done;
}
*features |= BIT_ULL(NPC_OUTER_VID);
+
+ /* If key profile extracts inner vlan tci */
+ if (vlan_tag3->nr_kws) {
+ key_fields[NPC_INNER_VID] = *vlan_tag3;
+ *features |= BIT_ULL(NPC_INNER_VID);
+ }
done:
return;
}
@@ -512,7 +523,12 @@ do { \
NPC_SCAN_HDR(NPC_ETYPE_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 8, 2);
NPC_SCAN_HDR(NPC_VLAN_TAG1, NPC_LID_LB, NPC_LT_LB_CTAG, 2, 2);
NPC_SCAN_HDR(NPC_VLAN_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 2, 2);
+ NPC_SCAN_HDR(NPC_VLAN_TAG3, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 6, 2);
NPC_SCAN_HDR(NPC_DMAC, NPC_LID_LA, la_ltype, la_start, 6);
+
+ NPC_SCAN_HDR(NPC_IPSEC_SPI, NPC_LID_LD, NPC_LT_LD_AH, 4, 4);
+ NPC_SCAN_HDR(NPC_IPSEC_SPI, NPC_LID_LE, NPC_LT_LE_ESP, 0, 4);
+
/* SMAC follows the DMAC(which is 6 bytes) */
NPC_SCAN_HDR(NPC_SMAC, NPC_LID_LA, la_ltype, la_start + 6, 6);
/* PF_FUNC is 2 bytes at 0th byte of NPC_LT_LA_IH_NIX_ETHER */
@@ -564,6 +580,11 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
if (!npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features &= ~BIT_ULL(NPC_OUTER_VID);
+ /* Set SPI flag only if AH/ESP and IPSEC_SPI are in the key */
+ if (npc_check_field(rvu, blkaddr, NPC_IPSEC_SPI, intf) &&
+ (*features & (BIT_ULL(NPC_IPPROTO_ESP) | BIT_ULL(NPC_IPPROTO_AH))))
+ *features |= BIT_ULL(NPC_IPSEC_SPI);
+
/* for vlan ethertypes corresponding layer type should be in the key */
if (npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) |
@@ -930,8 +951,13 @@ do { \
NPC_WRITE_FLOW(NPC_DPORT_SCTP, dport, ntohs(pkt->dport), 0,
ntohs(mask->dport), 0);
+ NPC_WRITE_FLOW(NPC_IPSEC_SPI, spi, ntohl(pkt->spi), 0,
+ ntohl(mask->spi), 0);
+
NPC_WRITE_FLOW(NPC_OUTER_VID, vlan_tci, ntohs(pkt->vlan_tci), 0,
ntohs(mask->vlan_tci), 0);
+ NPC_WRITE_FLOW(NPC_INNER_VID, vlan_itci, ntohs(pkt->vlan_itci), 0,
+ ntohs(mask->vlan_itci), 0);
NPC_WRITE_FLOW(NPC_IPFRAG_IPV6, next_header, pkt->next_header, 0,
mask->next_header, 0);
@@ -1192,7 +1218,7 @@ find_rule:
write_req.enable_entry = (u8)enable;
/* if counter is available then clear and use it */
if (req->set_cntr && rule->has_cntr) {
- rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), 0x00);
+ rvu_write64(rvu, blkaddr, NPC_AF_MATCH_STATX(rule->cntr), req->cntr_val);
write_req.set_cntr = 1;
write_req.cntr = rule->cntr;
}
@@ -1407,12 +1433,13 @@ static int npc_delete_flow(struct rvu *rvu, struct rvu_npc_mcam_rule *rule,
int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
struct npc_delete_flow_req *req,
- struct msg_rsp *rsp)
+ struct npc_delete_flow_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_npc_mcam_rule *iter, *tmp;
u16 pcifunc = req->hdr.pcifunc;
struct list_head del_list;
+ int blkaddr;
INIT_LIST_HEAD(&del_list);
@@ -1428,6 +1455,10 @@ int rvu_mbox_handler_npc_delete_flow(struct rvu *rvu,
list_move_tail(&iter->list, &del_list);
/* single rule */
} else if (req->entry == iter->entry) {
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr)
+ rsp->cntr_val = rvu_read64(rvu, blkaddr,
+ NPC_AF_MATCH_STATX(iter->cntr));
list_move_tail(&iter->list, &del_list);
break;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
index 7e20282c12d0..d2661e7fabdb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
@@ -391,22 +391,6 @@ int rvu_mbox_handler_npc_get_field_hash_info(struct rvu *rvu,
}
/**
- * rvu_npc_exact_mac2u64 - utility function to convert mac address to u64.
- * @mac_addr: MAC address.
- * Return: mdata for exact match table.
- */
-static u64 rvu_npc_exact_mac2u64(u8 *mac_addr)
-{
- u64 mac = 0;
- int index;
-
- for (index = ETH_ALEN - 1; index >= 0; index--)
- mac |= ((u64)*mac_addr++) << (8 * index);
-
- return mac;
-}
-
-/**
* rvu_exact_prepare_mdata - Make mdata for mcam entry
* @mac: MAC address
* @chan: Channel number.
@@ -416,7 +400,7 @@ static u64 rvu_npc_exact_mac2u64(u8 *mac_addr)
*/
static u64 rvu_exact_prepare_mdata(u8 *mac, u16 chan, u16 ctype, u64 mask)
{
- u64 ldata = rvu_npc_exact_mac2u64(mac);
+ u64 ldata = ether_addr_to_u64(mac);
/* Please note that mask is 48bit which excludes chan and ctype.
* Increase mask bits if we need to include them as well.
@@ -604,7 +588,7 @@ static u64 rvu_exact_prepare_table_entry(struct rvu *rvu, bool enable,
u8 ctype, u16 chan, u8 *mac_addr)
{
- u64 ldata = rvu_npc_exact_mac2u64(mac_addr);
+ u64 ldata = ether_addr_to_u64(mac_addr);
/* Enable or disable */
u64 mdata = FIELD_PREP(GENMASK_ULL(63, 63), enable ? 1 : 0);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
index 592b317f4637..854045ed3b06 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
@@ -158,6 +158,7 @@ void rvu_switch_enable(struct rvu *rvu)
struct npc_mcam_alloc_entry_req alloc_req = { 0 };
struct npc_mcam_alloc_entry_rsp alloc_rsp = { 0 };
struct npc_delete_flow_req uninstall_req = { 0 };
+ struct npc_delete_flow_rsp uninstall_rsp = { 0 };
struct npc_mcam_free_entry_req free_req = { 0 };
struct rvu_switch *rswitch = &rvu->rswitch;
struct msg_rsp rsp;
@@ -197,7 +198,7 @@ void rvu_switch_enable(struct rvu *rvu)
uninstall_rules:
uninstall_req.start = rswitch->start_entry;
uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
- rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
+ rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
kfree(rswitch->entry2pcifunc);
free_entries:
free_req.all = 1;
@@ -209,6 +210,7 @@ exit:
void rvu_switch_disable(struct rvu *rvu)
{
struct npc_delete_flow_req uninstall_req = { 0 };
+ struct npc_delete_flow_rsp uninstall_rsp = { 0 };
struct npc_mcam_free_entry_req free_req = { 0 };
struct rvu_switch *rswitch = &rvu->rswitch;
struct rvu_hwinfo *hw = rvu->hw;
@@ -250,7 +252,7 @@ void rvu_switch_disable(struct rvu *rvu)
uninstall_req.start = rswitch->start_entry;
uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
free_req.all = 1;
- rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &rsp);
+ rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
rswitch->used_entries = 0;
kfree(rswitch->entry2pcifunc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index 77c8f650f7ac..8511906cb4e2 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -7,6 +7,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <net/page_pool/helpers.h>
#include <net/tso.h>
#include <linux/bitfield.h>
@@ -774,6 +775,7 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf)
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;
return 0;
}
@@ -804,6 +806,7 @@ void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq)
mutex_unlock(&pfvf->mbox.lock);
}
+EXPORT_SYMBOL(otx2_txschq_free_one);
void otx2_txschq_stop(struct otx2_nic *pfvf)
{
@@ -1432,7 +1435,7 @@ int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
}
pp_params.flags = PP_FLAG_PAGE_FRAG | PP_FLAG_DMA_MAP;
- pp_params.pool_size = numptrs;
+ pp_params.pool_size = min(OTX2_PAGE_POOL_SZ, numptrs);
pp_params.nid = NUMA_NO_NODE;
pp_params.dev = pfvf->dev;
pp_params.dma_dir = DMA_FROM_DEVICE;
@@ -1903,31 +1906,16 @@ int otx2_handle_ntuple_tc_features(struct net_device *netdev, netdev_features_t
}
}
- if ((changed & NETIF_F_HW_TC) && tc) {
- if (!pfvf->flow_cfg->max_flows) {
- netdev_err(netdev,
- "Can't enable TC, MCAM entries not allocated\n");
- return -EINVAL;
- }
- }
-
if ((changed & NETIF_F_HW_TC) && !tc &&
- pfvf->flow_cfg && pfvf->flow_cfg->nr_flows) {
+ otx2_tc_flower_rule_cnt(pfvf)) {
netdev_err(netdev, "Can't disable TC hardware offload while flows are active\n");
return -EBUSY;
}
if ((changed & NETIF_F_NTUPLE) && ntuple &&
- (netdev->features & NETIF_F_HW_TC) && !(changed & NETIF_F_HW_TC)) {
- netdev_err(netdev,
- "Can't enable NTUPLE when TC is active, disable TC and retry\n");
- return -EINVAL;
- }
-
- if ((changed & NETIF_F_HW_TC) && tc &&
- (netdev->features & NETIF_F_NTUPLE) && !(changed & NETIF_F_NTUPLE)) {
+ otx2_tc_flower_rule_cnt(pfvf) && !(changed & NETIF_F_HW_TC)) {
netdev_err(netdev,
- "Can't enable TC when NTUPLE is active, disable NTUPLE and retry\n");
+ "Can't enable NTUPLE when TC flower offload is active, disable TC rules and retry\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index ba8091131ec0..4c6032ee7800 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -224,6 +224,7 @@ struct otx2_hw {
/* NIX */
u8 txschq_link_cfg_lvl;
+ u8 txschq_aggr_lvl_rr_prio;
u16 txschq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
u16 matchall_ipolicer;
u32 dwrr_mtu;
@@ -325,6 +326,7 @@ struct otx2_ptp {
struct ptp_pin_desc extts_config;
u64 (*convert_rx_ptp_tstmp)(u64 timestamp);
u64 (*convert_tx_ptp_tstmp)(u64 timestamp);
+ u64 (*ptp_tstamp2nsec)(const struct timecounter *time_counter, u64 timestamp);
struct delayed_work synctstamp_work;
u64 tstamp;
u32 base_ns;
@@ -360,13 +362,8 @@ struct otx2_flow_config {
struct list_head flow_list;
u32 dmacflt_max_flows;
u16 max_flows;
-};
-
-struct otx2_tc_info {
- /* hash table to store TC offloaded flows */
- struct rhashtable flow_table;
- struct rhashtable_params flow_ht_params;
- unsigned long *tc_entries_bitmap;
+ struct list_head flow_list_tc;
+ bool ntuple;
};
struct dev_hw_ops {
@@ -491,7 +488,6 @@ struct otx2_nic {
/* NPC MCAM */
struct otx2_flow_config *flow_cfg;
struct otx2_mac_table *mac_table;
- struct otx2_tc_info tc_info;
u64 reset_count;
struct work_struct reset_task;
@@ -945,6 +941,15 @@ static inline u64 otx2_convert_rate(u64 rate)
return converted_rate;
}
+static inline int otx2_tc_flower_rule_cnt(struct otx2_nic *pfvf)
+{
+ /* return here if MCAM entries not allocated */
+ if (!pfvf->flow_cfg)
+ return 0;
+
+ return pfvf->flow_cfg->nr_flows;
+}
+
/* MSI-X APIs */
void otx2_free_cints(struct otx2_nic *pfvf, int n);
void otx2_set_cints_affinity(struct otx2_nic *pfvf);
@@ -1063,7 +1068,6 @@ int otx2_init_tc(struct otx2_nic *nic);
void otx2_shutdown_tc(struct otx2_nic *nic);
int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data);
-int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic);
/* CGX/RPM DMAC filters support */
int otx2_dmacflt_get_max_cnt(struct otx2_nic *pf);
int otx2_dmacflt_add(struct otx2_nic *pf, const u8 *mac, u32 bit_pos);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
index ccaf97bb1ce0..bfddbff7bcdf 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c
@@ -70,7 +70,7 @@ static int otx2_pfc_txschq_alloc_one(struct otx2_nic *pfvf, u8 prio)
* link config level. These rest of the scheduler can be
* same as hw.txschq_list.
*/
- for (lvl = 0; lvl < pfvf->hw.txschq_link_cfg_lvl; lvl++)
+ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++)
req->schq[lvl] = 1;
rc = otx2_sync_mbox_msg(&pfvf->mbox);
@@ -83,7 +83,7 @@ static int otx2_pfc_txschq_alloc_one(struct otx2_nic *pfvf, u8 prio)
return PTR_ERR(rsp);
/* Setup transmit scheduler list */
- for (lvl = 0; lvl < pfvf->hw.txschq_link_cfg_lvl; lvl++) {
+ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++) {
if (!rsp->schq[lvl])
return -ENOSPC;
@@ -125,19 +125,12 @@ int otx2_pfc_txschq_alloc(struct otx2_nic *pfvf)
static int otx2_pfc_txschq_stop_one(struct otx2_nic *pfvf, u8 prio)
{
- struct nix_txsch_free_req *free_req;
+ int lvl;
- mutex_lock(&pfvf->mbox.lock);
/* free PFC TLx nodes */
- free_req = otx2_mbox_alloc_msg_nix_txsch_free(&pfvf->mbox);
- if (!free_req) {
- mutex_unlock(&pfvf->mbox.lock);
- return -ENOMEM;
- }
-
- free_req->flags = TXSCHQ_FREE_ALL;
- otx2_sync_mbox_msg(&pfvf->mbox);
- mutex_unlock(&pfvf->mbox.lock);
+ for (lvl = 0; lvl <= pfvf->hw.txschq_link_cfg_lvl; lvl++)
+ otx2_txschq_free_one(pfvf, lvl,
+ pfvf->pfc_schq_list[lvl][prio]);
pfvf->pfc_alloc_status[prio] = false;
return 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
index 63ef7c41d18d..4e1130496573 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
@@ -41,7 +41,6 @@ static int otx2_dl_mcam_count_set(struct devlink *devlink, u32 id,
return 0;
otx2_alloc_mcam_entries(pfvf, ctx->val.vu16);
- otx2_tc_alloc_ent_bitmap(pfvf);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index c47d91da32dc..9efcec549834 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -764,6 +764,7 @@ static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
struct otx2_nic *pfvf = netdev_priv(dev);
int ret = -EOPNOTSUPP;
+ pfvf->flow_cfg->ntuple = ntuple;
switch (nfc->cmd) {
case ETHTOOL_SRXFH:
ret = otx2_set_rss_hash_opts(pfvf, nfc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 2d7713a1a153..4762dbea64a1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -276,6 +276,7 @@ int otx2vf_mcam_flow_init(struct otx2_nic *pfvf)
flow_cfg = pfvf->flow_cfg;
INIT_LIST_HEAD(&flow_cfg->flow_list);
+ INIT_LIST_HEAD(&flow_cfg->flow_list_tc);
flow_cfg->max_flows = 0;
return 0;
@@ -298,6 +299,7 @@ int otx2_mcam_flow_init(struct otx2_nic *pf)
return -ENOMEM;
INIT_LIST_HEAD(&pf->flow_cfg->flow_list);
+ INIT_LIST_HEAD(&pf->flow_cfg->flow_list_tc);
/* Allocate bare minimum number of MCAM entries needed for
* unicast and ntuple filters.
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 9551b422622a..70b9065f7d10 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -16,6 +16,7 @@
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/bitfield.h>
+#include <net/page_pool/types.h>
#include "otx2_reg.h"
#include "otx2_common.h"
@@ -2027,7 +2028,7 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
#endif
int txq;
- qos_enabled = (netdev->real_num_tx_queues > pf->hw.tx_queues) ? true : false;
+ qos_enabled = netdev->real_num_tx_queues > pf->hw.tx_queues;
if (unlikely(qos_enabled)) {
/* This smp_load_acquire() pairs with smp_store_release() in
* otx2_qos_root_add() called from htb offload root creation
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
index 896b2f9bac34..3a72b0793d4a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
@@ -10,6 +10,65 @@
#include "otx2_common.h"
#include "otx2_ptp.h"
+static bool is_tstmp_atomic_update_supported(struct otx2_ptp *ptp)
+{
+ struct ptp_get_cap_rsp *rsp;
+ struct msg_req *req;
+ int err;
+
+ if (!ptp->nic)
+ return false;
+
+ mutex_lock(&ptp->nic->mbox.lock);
+ req = otx2_mbox_alloc_msg_ptp_get_cap(&ptp->nic->mbox);
+ if (!req) {
+ mutex_unlock(&ptp->nic->mbox.lock);
+ return false;
+ }
+
+ err = otx2_sync_mbox_msg(&ptp->nic->mbox);
+ if (err) {
+ mutex_unlock(&ptp->nic->mbox.lock);
+ return false;
+ }
+ rsp = (struct ptp_get_cap_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
+ &req->hdr);
+ mutex_unlock(&ptp->nic->mbox.lock);
+
+ if (IS_ERR(rsp))
+ return false;
+
+ if (rsp->cap & PTP_CAP_HW_ATOMIC_UPDATE)
+ return true;
+
+ return false;
+}
+
+static int otx2_ptp_hw_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
+{
+ struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
+ ptp_info);
+ struct otx2_nic *pfvf = ptp->nic;
+ struct ptp_req *req;
+ int rc;
+
+ if (!ptp->nic)
+ return -ENODEV;
+
+ mutex_lock(&pfvf->mbox.lock);
+ req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -ENOMEM;
+ }
+ req->op = PTP_OP_ADJTIME;
+ req->delta = delta;
+ rc = otx2_sync_mbox_msg(&ptp->nic->mbox);
+ mutex_unlock(&pfvf->mbox.lock);
+
+ return rc;
+}
+
static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp)
{
struct ptp_req *req;
@@ -37,6 +96,49 @@ static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp)
return rsp->clk;
}
+static int otx2_ptp_hw_gettime(struct ptp_clock_info *ptp_info,
+ struct timespec64 *ts)
+{
+ struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
+ ptp_info);
+ u64 tstamp;
+
+ tstamp = otx2_ptp_get_clock(ptp);
+
+ *ts = ns_to_timespec64(tstamp);
+ return 0;
+}
+
+static int otx2_ptp_hw_settime(struct ptp_clock_info *ptp_info,
+ const struct timespec64 *ts)
+{
+ struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
+ ptp_info);
+ struct otx2_nic *pfvf = ptp->nic;
+ struct ptp_req *req;
+ u64 nsec;
+ int rc;
+
+ if (!ptp->nic)
+ return -ENODEV;
+
+ nsec = timespec64_to_ns(ts);
+
+ mutex_lock(&pfvf->mbox.lock);
+ req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
+ if (!req) {
+ mutex_unlock(&pfvf->mbox.lock);
+ return -ENOMEM;
+ }
+
+ req->op = PTP_OP_SET_CLOCK;
+ req->clk = nsec;
+ rc = otx2_sync_mbox_msg(&ptp->nic->mbox);
+ mutex_unlock(&pfvf->mbox.lock);
+
+ return rc;
+}
+
static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
@@ -124,16 +226,7 @@ static u64 ptp_tstmp_read(struct otx2_ptp *ptp)
return rsp->clk;
}
-static void otx2_get_ptpclock(struct otx2_ptp *ptp, u64 *tstamp)
-{
- struct otx2_nic *pfvf = ptp->nic;
-
- mutex_lock(&pfvf->mbox.lock);
- *tstamp = timecounter_read(&ptp->time_counter);
- mutex_unlock(&pfvf->mbox.lock);
-}
-
-static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
+static int otx2_ptp_tc_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
@@ -146,32 +239,33 @@ static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
return 0;
}
-static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info,
- struct timespec64 *ts)
+static int otx2_ptp_tc_gettime(struct ptp_clock_info *ptp_info,
+ struct timespec64 *ts)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
u64 tstamp;
- otx2_get_ptpclock(ptp, &tstamp);
+ mutex_lock(&ptp->nic->mbox.lock);
+ tstamp = timecounter_read(&ptp->time_counter);
+ mutex_unlock(&ptp->nic->mbox.lock);
*ts = ns_to_timespec64(tstamp);
return 0;
}
-static int otx2_ptp_settime(struct ptp_clock_info *ptp_info,
- const struct timespec64 *ts)
+static int otx2_ptp_tc_settime(struct ptp_clock_info *ptp_info,
+ const struct timespec64 *ts)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
- struct otx2_nic *pfvf = ptp->nic;
u64 nsec;
nsec = timespec64_to_ns(ts);
- mutex_lock(&pfvf->mbox.lock);
+ mutex_lock(&ptp->nic->mbox.lock);
timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);
- mutex_unlock(&pfvf->mbox.lock);
+ mutex_unlock(&ptp->nic->mbox.lock);
return 0;
}
@@ -190,6 +284,12 @@ static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
return 0;
}
+static u64 otx2_ptp_hw_tstamp2time(const struct timecounter *time_counter, u64 tstamp)
+{
+ /* On HW which supports atomic updates, timecounter is not initialized */
+ return tstamp;
+}
+
static void otx2_ptp_extts_check(struct work_struct *work)
{
struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,
@@ -204,7 +304,7 @@ static void otx2_ptp_extts_check(struct work_struct *work)
if (tstmp != ptp->last_extts) {
event.type = PTP_CLOCK_EXTTS;
event.index = 0;
- event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp);
+ event.timestamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstmp);
ptp_clock_event(ptp->ptp_clock, &event);
new_thresh = tstmp % 500000000;
if (ptp->thresh != new_thresh) {
@@ -229,7 +329,7 @@ static void otx2_sync_tstamp(struct work_struct *work)
tstamp = otx2_ptp_get_clock(ptp);
mutex_unlock(&pfvf->mbox.lock);
- ptp->tstamp = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
+ ptp->tstamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstamp);
ptp->base_ns = tstamp % NSEC_PER_SEC;
schedule_delayed_work(&ptp->synctstamp_work, msecs_to_jiffies(250));
@@ -302,15 +402,6 @@ int otx2_ptp_init(struct otx2_nic *pfvf)
ptp_ptr->nic = pfvf;
- cc = &ptp_ptr->cycle_counter;
- cc->read = ptp_cc_read;
- cc->mask = CYCLECOUNTER_MASK(64);
- cc->mult = 1;
- cc->shift = 0;
-
- timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
- ktime_to_ns(ktime_get_real()));
-
snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP");
ptp_ptr->extts_config.index = 0;
ptp_ptr->extts_config.func = PTP_PF_NONE;
@@ -324,13 +415,33 @@ int otx2_ptp_init(struct otx2_nic *pfvf)
.pps = 0,
.pin_config = &ptp_ptr->extts_config,
.adjfine = otx2_ptp_adjfine,
- .adjtime = otx2_ptp_adjtime,
- .gettime64 = otx2_ptp_gettime,
- .settime64 = otx2_ptp_settime,
.enable = otx2_ptp_enable,
.verify = otx2_ptp_verify_pin,
};
+ /* Check whether hardware supports atomic updates to timestamp */
+ if (is_tstmp_atomic_update_supported(ptp_ptr)) {
+ ptp_ptr->ptp_info.adjtime = otx2_ptp_hw_adjtime;
+ ptp_ptr->ptp_info.gettime64 = otx2_ptp_hw_gettime;
+ ptp_ptr->ptp_info.settime64 = otx2_ptp_hw_settime;
+
+ ptp_ptr->ptp_tstamp2nsec = otx2_ptp_hw_tstamp2time;
+ } else {
+ ptp_ptr->ptp_info.adjtime = otx2_ptp_tc_adjtime;
+ ptp_ptr->ptp_info.gettime64 = otx2_ptp_tc_gettime;
+ ptp_ptr->ptp_info.settime64 = otx2_ptp_tc_settime;
+
+ cc = &ptp_ptr->cycle_counter;
+ cc->read = ptp_cc_read;
+ cc->mask = CYCLECOUNTER_MASK(64);
+ cc->mult = 1;
+ cc->shift = 0;
+ ptp_ptr->ptp_tstamp2nsec = timecounter_cyc2time;
+
+ timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
+ ktime_to_ns(ktime_get_real()));
+ }
+
INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check);
ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
@@ -387,7 +498,7 @@ int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
if (!pfvf->ptp)
return -ENODEV;
- *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp);
+ *tsns = pfvf->ptp->ptp_tstamp2nsec(&pfvf->ptp->time_counter, tstamp);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index 5e56b6c3e60a..fab9d85bfb37 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -34,9 +34,8 @@ struct otx2_tc_flow_stats {
};
struct otx2_tc_flow {
- struct rhash_head node;
+ struct list_head list;
unsigned long cookie;
- unsigned int bitpos;
struct rcu_head rcu;
struct otx2_tc_flow_stats stats;
spinlock_t lock; /* lock for stats */
@@ -44,31 +43,10 @@ struct otx2_tc_flow {
u16 entry;
u16 leaf_profile;
bool is_act_police;
+ u32 prio;
+ struct npc_install_flow_req req;
};
-int otx2_tc_alloc_ent_bitmap(struct otx2_nic *nic)
-{
- struct otx2_tc_info *tc = &nic->tc_info;
-
- if (!nic->flow_cfg->max_flows)
- return 0;
-
- /* Max flows changed, free the existing bitmap */
- kfree(tc->tc_entries_bitmap);
-
- tc->tc_entries_bitmap =
- kcalloc(BITS_TO_LONGS(nic->flow_cfg->max_flows),
- sizeof(long), GFP_KERNEL);
- if (!tc->tc_entries_bitmap) {
- netdev_err(nic->netdev,
- "Unable to alloc TC flow entries bitmap\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(otx2_tc_alloc_ent_bitmap);
-
static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
u32 *burst_exp, u32 *burst_mantissa)
{
@@ -461,6 +439,62 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
return 0;
}
+static int otx2_tc_process_vlan(struct otx2_nic *nic, struct flow_msg *flow_spec,
+ struct flow_msg *flow_mask, struct flow_rule *rule,
+ struct npc_install_flow_req *req, bool is_inner)
+{
+ struct flow_match_vlan match;
+ u16 vlan_tci, vlan_tci_mask;
+
+ if (is_inner)
+ flow_rule_match_cvlan(rule, &match);
+ else
+ flow_rule_match_vlan(rule, &match);
+
+ if (!eth_type_vlan(match.key->vlan_tpid)) {
+ netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
+ ntohs(match.key->vlan_tpid));
+ return -EOPNOTSUPP;
+ }
+
+ if (!match.mask->vlan_id) {
+ struct flow_action_entry *act;
+ int i;
+
+ flow_action_for_each(i, act, &rule->action) {
+ if (act->id == FLOW_ACTION_DROP) {
+ netdev_err(nic->netdev,
+ "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
+ ntohs(match.key->vlan_tpid), match.key->vlan_id);
+ return -EOPNOTSUPP;
+ }
+ }
+ }
+
+ if (match.mask->vlan_id ||
+ match.mask->vlan_dei ||
+ match.mask->vlan_priority) {
+ vlan_tci = match.key->vlan_id |
+ match.key->vlan_dei << 12 |
+ match.key->vlan_priority << 13;
+
+ vlan_tci_mask = match.mask->vlan_id |
+ match.mask->vlan_dei << 12 |
+ match.mask->vlan_priority << 13;
+ if (is_inner) {
+ flow_spec->vlan_itci = htons(vlan_tci);
+ flow_mask->vlan_itci = htons(vlan_tci_mask);
+ req->features |= BIT_ULL(NPC_INNER_VID);
+ } else {
+ flow_spec->vlan_tci = htons(vlan_tci);
+ flow_mask->vlan_tci = htons(vlan_tci_mask);
+ req->features |= BIT_ULL(NPC_OUTER_VID);
+ }
+ }
+
+ return 0;
+}
+
static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
struct flow_cls_offload *f,
struct npc_install_flow_req *req)
@@ -476,15 +510,17 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
dissector = rule->match.dissector;
if ((dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_IP)))) {
- netdev_info(nic->netdev, "unsupported flow used key 0x%x",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT(FLOW_DISSECTOR_KEY_CVLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT(FLOW_DISSECTOR_KEY_IPSEC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP)))) {
+ netdev_info(nic->netdev, "unsupported flow used key 0x%llx",
dissector->used_keys);
return -EOPNOTSUPP;
}
@@ -504,6 +540,8 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
match.key->ip_proto != IPPROTO_UDP &&
match.key->ip_proto != IPPROTO_SCTP &&
match.key->ip_proto != IPPROTO_ICMP &&
+ match.key->ip_proto != IPPROTO_ESP &&
+ match.key->ip_proto != IPPROTO_AH &&
match.key->ip_proto != IPPROTO_ICMPV6)) {
netdev_info(nic->netdev,
"ip_proto=0x%x not supported\n",
@@ -523,6 +561,10 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
req->features |= BIT_ULL(NPC_IPPROTO_ICMP);
else if (ip_proto == IPPROTO_ICMPV6)
req->features |= BIT_ULL(NPC_IPPROTO_ICMP6);
+ else if (ip_proto == IPPROTO_ESP)
+ req->features |= BIT_ULL(NPC_IPPROTO_ESP);
+ else if (ip_proto == IPPROTO_AH)
+ req->features |= BIT_ULL(NPC_IPPROTO_AH);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
@@ -567,6 +609,26 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
}
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPSEC)) {
+ struct flow_match_ipsec match;
+
+ flow_rule_match_ipsec(rule, &match);
+ if (!match.mask->spi) {
+ NL_SET_ERR_MSG_MOD(extack, "spi index not specified");
+ return -EOPNOTSUPP;
+ }
+ if (ip_proto != IPPROTO_ESP &&
+ ip_proto != IPPROTO_AH) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "SPI index is valid only for ESP/AH proto");
+ return -EOPNOTSUPP;
+ }
+
+ flow_spec->spi = match.key->spi;
+ flow_mask->spi = match.mask->spi;
+ req->features |= BIT_ULL(NPC_IPSEC_SPI);
+ }
+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
struct flow_match_ip match;
@@ -586,47 +648,19 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
- struct flow_match_vlan match;
- u16 vlan_tci, vlan_tci_mask;
-
- flow_rule_match_vlan(rule, &match);
-
- if (ntohs(match.key->vlan_tpid) != ETH_P_8021Q) {
- netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
- ntohs(match.key->vlan_tpid));
- return -EOPNOTSUPP;
- }
+ int ret;
- if (!match.mask->vlan_id) {
- struct flow_action_entry *act;
- int i;
-
- flow_action_for_each(i, act, &rule->action) {
- if (act->id == FLOW_ACTION_DROP) {
- netdev_err(nic->netdev,
- "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
- ntohs(match.key->vlan_tpid),
- match.key->vlan_id);
- return -EOPNOTSUPP;
- }
- }
- }
-
- if (match.mask->vlan_id ||
- match.mask->vlan_dei ||
- match.mask->vlan_priority) {
- vlan_tci = match.key->vlan_id |
- match.key->vlan_dei << 12 |
- match.key->vlan_priority << 13;
+ ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, false);
+ if (ret)
+ return ret;
+ }
- vlan_tci_mask = match.mask->vlan_id |
- match.mask->vlan_dei << 12 |
- match.mask->vlan_priority << 13;
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
+ int ret;
- flow_spec->vlan_tci = htons(vlan_tci);
- flow_mask->vlan_tci = htons(vlan_tci_mask);
- req->features |= BIT_ULL(NPC_OUTER_VID);
- }
+ ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, true);
+ if (ret)
+ return ret;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
@@ -707,8 +741,117 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
}
-static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
+static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)
+{
+ struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
+ struct otx2_tc_flow *iter, *tmp;
+
+ if (!(pfvf->flags & OTX2_FLAG_MCAM_ENTRIES_ALLOC))
+ return;
+
+ list_for_each_entry_safe(iter, tmp, &flow_cfg->flow_list_tc, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ flow_cfg->nr_flows--;
+ }
+}
+
+static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg,
+ unsigned long cookie)
{
+ struct otx2_tc_flow *tmp;
+
+ list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
+ if (tmp->cookie == cookie)
+ return tmp;
+ }
+
+ return NULL;
+}
+
+static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg,
+ int index)
+{
+ struct otx2_tc_flow *tmp;
+ int i = 0;
+
+ list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
+ if (i == index)
+ return tmp;
+ i++;
+ }
+
+ return NULL;
+}
+
+static void otx2_tc_del_from_flow_list(struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node == tmp) {
+ list_del(&node->list);
+ return;
+ }
+ }
+}
+
+static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+ int index = 0;
+
+ /* If the flow list is empty then add the new node */
+ if (list_empty(&flow_cfg->flow_list_tc)) {
+ list_add(&node->list, &flow_cfg->flow_list_tc);
+ return index;
+ }
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node->prio < tmp->prio)
+ break;
+ index++;
+ }
+
+ list_add(&node->list, pos->prev);
+ return index;
+}
+
+static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_install_flow_req *req)
+{
+ struct npc_install_flow_req *tmp_req;
+ int err;
+
+ mutex_lock(&nic->mbox.lock);
+ tmp_req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
+ if (!tmp_req) {
+ mutex_unlock(&nic->mbox.lock);
+ return -ENOMEM;
+ }
+
+ memcpy(tmp_req, req, sizeof(struct npc_install_flow_req));
+ /* Send message to AF */
+ err = otx2_sync_mbox_msg(&nic->mbox);
+ if (err) {
+ netdev_err(nic->netdev, "Failed to install MCAM flow entry %d\n",
+ req->entry);
+ mutex_unlock(&nic->mbox.lock);
+ return -EFAULT;
+ }
+
+ mutex_unlock(&nic->mbox.lock);
+ return 0;
+}
+
+static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_val)
+{
+ struct npc_delete_flow_rsp *rsp;
struct npc_delete_flow_req *req;
int err;
@@ -729,22 +872,113 @@ static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry)
mutex_unlock(&nic->mbox.lock);
return -EFAULT;
}
+
+ if (cntr_val) {
+ rsp = (struct npc_delete_flow_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
+ 0, &req->hdr);
+ if (IS_ERR(rsp)) {
+ netdev_err(nic->netdev, "Failed to get MCAM delete response for entry %d\n",
+ entry);
+ mutex_unlock(&nic->mbox.lock);
+ return -EFAULT;
+ }
+
+ *cntr_val = rsp->cntr_val;
+ }
+
mutex_unlock(&nic->mbox.lock);
+ return 0;
+}
+
+static int otx2_tc_update_mcam_table_del_req(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ struct list_head *pos, *n;
+ struct otx2_tc_flow *tmp;
+ int i = 0, index = 0;
+ u16 cntr_val = 0;
+
+ /* Find and delete the entry from the list and re-install
+ * all the entries from beginning to the index of the
+ * deleted entry to higher mcam indexes.
+ */
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ if (node == tmp) {
+ list_del(&tmp->list);
+ break;
+ }
+
+ otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
+ tmp->entry++;
+ tmp->req.entry = tmp->entry;
+ tmp->req.cntr_val = cntr_val;
+ index++;
+ }
+
+ list_for_each_safe(pos, n, &flow_cfg->flow_list_tc) {
+ if (i == index)
+ break;
+
+ tmp = list_entry(pos, struct otx2_tc_flow, list);
+ otx2_add_mcam_flow_entry(nic, &tmp->req);
+ i++;
+ }
return 0;
}
+static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node)
+{
+ int mcam_idx = flow_cfg->max_flows - flow_cfg->nr_flows - 1;
+ struct otx2_tc_flow *tmp;
+ int list_idx, i;
+ u16 cntr_val = 0;
+
+ /* Find the index of the entry(list_idx) whose priority
+ * is greater than the new entry and re-install all
+ * the entries from beginning to list_idx to higher
+ * mcam indexes.
+ */
+ list_idx = otx2_tc_add_to_flow_list(flow_cfg, node);
+ for (i = 0; i < list_idx; i++) {
+ tmp = otx2_tc_get_entry_by_index(flow_cfg, i);
+ if (!tmp)
+ return -ENOMEM;
+
+ otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
+ tmp->entry = flow_cfg->flow_ent[mcam_idx];
+ tmp->req.entry = tmp->entry;
+ tmp->req.cntr_val = cntr_val;
+ otx2_add_mcam_flow_entry(nic, &tmp->req);
+ mcam_idx++;
+ }
+
+ return mcam_idx;
+}
+
+static int otx2_tc_update_mcam_table(struct otx2_nic *nic,
+ struct otx2_flow_config *flow_cfg,
+ struct otx2_tc_flow *node,
+ bool add_req)
+{
+ if (add_req)
+ return otx2_tc_update_mcam_table_add_req(nic, flow_cfg, node);
+
+ return otx2_tc_update_mcam_table_del_req(nic, flow_cfg, node);
+}
+
static int otx2_tc_del_flow(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *flow_node;
int err;
- flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ flow_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
if (!flow_node) {
netdev_err(nic->netdev, "tc flow not found for cookie 0x%lx\n",
tc_flow_cmd->cookie);
@@ -772,16 +1006,10 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
mutex_unlock(&nic->mbox.lock);
}
- otx2_del_mcam_flow_entry(nic, flow_node->entry);
-
- WARN_ON(rhashtable_remove_fast(&nic->tc_info.flow_table,
- &flow_node->node,
- nic->tc_info.flow_ht_params));
+ otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
+ otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
kfree_rcu(flow_node, rcu);
-
- clear_bit(flow_node->bitpos, tc_info->tc_entries_bitmap);
flow_cfg->nr_flows--;
-
return 0;
}
@@ -790,15 +1018,14 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
{
struct netlink_ext_ack *extack = tc_flow_cmd->common.extack;
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct otx2_tc_flow *new_node, *old_node;
struct npc_install_flow_req *req, dummy;
- int rc, err;
+ int rc, err, mcam_idx;
if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
return -ENOMEM;
- if (bitmap_full(tc_info->tc_entries_bitmap, flow_cfg->max_flows)) {
+ if (flow_cfg->nr_flows == flow_cfg->max_flows) {
NL_SET_ERR_MSG_MOD(extack,
"Free MCAM entry not available to add the flow");
return -ENOMEM;
@@ -810,6 +1037,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
return -ENOMEM;
spin_lock_init(&new_node->lock);
new_node->cookie = tc_flow_cmd->cookie;
+ new_node->prio = tc_flow_cmd->common.prio;
memset(&dummy, 0, sizeof(struct npc_install_flow_req));
@@ -820,12 +1048,11 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
}
/* If a flow exists with the same cookie, delete it */
- old_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ old_node = otx2_tc_get_entry_by_cookie(flow_cfg, tc_flow_cmd->cookie);
if (old_node)
otx2_tc_del_flow(nic, tc_flow_cmd);
+ mcam_idx = otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true);
mutex_lock(&nic->mbox.lock);
req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
if (!req) {
@@ -836,11 +1063,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
-
- new_node->bitpos = find_first_zero_bit(tc_info->tc_entries_bitmap,
- flow_cfg->max_flows);
req->channel = nic->hw.rx_chan_base;
- req->entry = flow_cfg->flow_ent[flow_cfg->max_flows - new_node->bitpos - 1];
+ req->entry = flow_cfg->flow_ent[mcam_idx];
req->intf = NIX_INTF_RX;
req->set_cntr = 1;
new_node->entry = req->entry;
@@ -850,26 +1074,18 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
if (rc) {
NL_SET_ERR_MSG_MOD(extack, "Failed to install MCAM flow entry");
mutex_unlock(&nic->mbox.lock);
- kfree_rcu(new_node, rcu);
goto free_leaf;
}
- mutex_unlock(&nic->mbox.lock);
- /* add new flow to flow-table */
- rc = rhashtable_insert_fast(&nic->tc_info.flow_table, &new_node->node,
- nic->tc_info.flow_ht_params);
- if (rc) {
- otx2_del_mcam_flow_entry(nic, req->entry);
- kfree_rcu(new_node, rcu);
- goto free_leaf;
- }
+ mutex_unlock(&nic->mbox.lock);
+ memcpy(&new_node->req, req, sizeof(struct npc_install_flow_req));
- set_bit(new_node->bitpos, tc_info->tc_entries_bitmap);
flow_cfg->nr_flows++;
-
return 0;
free_leaf:
+ otx2_tc_del_from_flow_list(flow_cfg, new_node);
+ kfree_rcu(new_node, rcu);
if (new_node->is_act_police) {
mutex_lock(&nic->mbox.lock);
@@ -896,16 +1112,13 @@ free_leaf:
static int otx2_tc_get_flow_stats(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
- struct otx2_tc_info *tc_info = &nic->tc_info;
struct npc_mcam_get_stats_req *req;
struct npc_mcam_get_stats_rsp *rsp;
struct otx2_tc_flow_stats *stats;
struct otx2_tc_flow *flow_node;
int err;
- flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
- &tc_flow_cmd->cookie,
- tc_info->flow_ht_params);
+ flow_node = otx2_tc_get_entry_by_cookie(nic->flow_cfg, tc_flow_cmd->cookie);
if (!flow_node) {
netdev_info(nic->netdev, "tc flow not found for cookie %lx",
tc_flow_cmd->cookie);
@@ -1053,12 +1266,20 @@ static int otx2_setup_tc_block_ingress_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct otx2_nic *nic = cb_priv;
+ bool ntuple;
if (!tc_cls_can_offload_and_chain0(nic->netdev, type_data))
return -EOPNOTSUPP;
+ ntuple = nic->netdev->features & NETIF_F_NTUPLE;
switch (type) {
case TC_SETUP_CLSFLOWER:
+ if (ntuple) {
+ netdev_warn(nic->netdev,
+ "Can't install TC flower offload rule when NTUPLE is active");
+ return -EOPNOTSUPP;
+ }
+
return otx2_setup_tc_cls_flower(nic, type_data);
case TC_SETUP_CLSMATCHALL:
return otx2_setup_tc_ingress_matchall(nic, type_data);
@@ -1143,18 +1364,8 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
}
EXPORT_SYMBOL(otx2_setup_tc);
-static const struct rhashtable_params tc_flow_ht_params = {
- .head_offset = offsetof(struct otx2_tc_flow, node),
- .key_offset = offsetof(struct otx2_tc_flow, cookie),
- .key_len = sizeof(((struct otx2_tc_flow *)0)->cookie),
- .automatic_shrinking = true,
-};
-
int otx2_init_tc(struct otx2_nic *nic)
{
- struct otx2_tc_info *tc = &nic->tc_info;
- int err;
-
/* Exclude receive queue 0 being used for police action */
set_bit(0, &nic->rq_bmap);
@@ -1164,25 +1375,12 @@ int otx2_init_tc(struct otx2_nic *nic)
return -EINVAL;
}
- err = otx2_tc_alloc_ent_bitmap(nic);
- if (err)
- return err;
-
- tc->flow_ht_params = tc_flow_ht_params;
- err = rhashtable_init(&tc->flow_table, &tc->flow_ht_params);
- if (err) {
- kfree(tc->tc_entries_bitmap);
- tc->tc_entries_bitmap = NULL;
- }
- return err;
+ return 0;
}
EXPORT_SYMBOL(otx2_init_tc);
void otx2_shutdown_tc(struct otx2_nic *nic)
{
- struct otx2_tc_info *tc = &nic->tc_info;
-
- kfree(tc->tc_entries_bitmap);
- rhashtable_destroy(&tc->flow_table);
+ otx2_destroy_tc_flow_list(nic);
}
EXPORT_SYMBOL(otx2_shutdown_tc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
index b5d689eeff80..9e3bfbe5c480 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
@@ -23,6 +23,8 @@
#define OTX2_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN)
#define OTX2_MIN_MTU 60
+#define OTX2_PAGE_POOL_SZ 2048
+
#define OTX2_MAX_GSO_SEGS 255
#define OTX2_MAX_FRAGS_IN_SQE 9
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
index d3a76c5ccda8..1e77bbf5d22a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
@@ -19,6 +19,9 @@
#define OTX2_QOS_CLASS_NONE 0
#define OTX2_QOS_DEFAULT_PRIO 0xF
#define OTX2_QOS_INVALID_SQ 0xFFFF
+#define OTX2_QOS_INVALID_TXSCHQ_IDX 0xFFFF
+#define CN10K_MAX_RR_WEIGHT GENMASK_ULL(13, 0)
+#define OTX2_MAX_RR_QUANTUM GENMASK_ULL(23, 0)
static void otx2_qos_update_tx_netdev_queues(struct otx2_nic *pfvf)
{
@@ -65,11 +68,24 @@ static void otx2_qos_get_regaddr(struct otx2_qos_node *node,
}
}
+static int otx2_qos_quantum_to_dwrr_weight(struct otx2_nic *pfvf, u32 quantum)
+{
+ u32 weight;
+
+ weight = quantum / pfvf->hw.dwrr_mtu;
+ if (quantum % pfvf->hw.dwrr_mtu)
+ weight += 1;
+
+ return weight;
+}
+
static void otx2_config_sched_shaping(struct otx2_nic *pfvf,
struct otx2_qos_node *node,
struct nix_txschq_config *cfg,
int *num_regs)
{
+ u32 rr_weight;
+ u32 quantum;
u64 maxrate;
otx2_qos_get_regaddr(node, cfg, *num_regs);
@@ -86,8 +102,17 @@ static void otx2_config_sched_shaping(struct otx2_nic *pfvf,
return;
}
- /* configure priority */
- cfg->regval[*num_regs] = (node->schq - node->parent->prio_anchor) << 24;
+ /* configure priority/quantum */
+ if (node->is_static) {
+ cfg->regval[*num_regs] =
+ (node->schq - node->parent->prio_anchor) << 24;
+ } else {
+ quantum = node->quantum ?
+ node->quantum : pfvf->tx_max_pktlen;
+ rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum);
+ cfg->regval[*num_regs] = node->parent->child_dwrr_prio << 24 |
+ rr_weight;
+ }
(*num_regs)++;
/* configure PIR */
@@ -195,9 +220,8 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,
cfg->reg[0] = NIX_AF_TL1X_TOPOLOGY(parent->schq);
cfg->regval[0] = (u64)parent->prio_anchor << 32;
- if (parent->level == NIX_TXSCH_LVL_TL1)
- cfg->regval[0] |= (u64)TXSCH_TL1_DFLT_RR_PRIO << 1;
-
+ cfg->regval[0] |= ((parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) ?
+ parent->child_dwrr_prio : 0) << 1;
cfg->num_regs++;
rc = otx2_sync_mbox_msg(&pfvf->mbox);
@@ -315,9 +339,14 @@ static void otx2_qos_fill_cfg_tl(struct otx2_qos_node *parent,
list_for_each_entry(node, &parent->child_list, list) {
otx2_qos_fill_cfg_tl(node, cfg);
- cfg->schq_contig[node->level]++;
otx2_qos_fill_cfg_schq(node, cfg);
}
+
+ /* Assign the required number of transmit schedular queues under the
+ * given class
+ */
+ cfg->schq_contig[parent->level - 1] += parent->child_dwrr_cnt +
+ parent->max_static_prio + 1;
}
static void otx2_qos_prepare_txschq_cfg(struct otx2_nic *pfvf,
@@ -378,10 +407,12 @@ otx2_qos_alloc_root(struct otx2_nic *pfvf)
return ERR_PTR(-ENOMEM);
node->parent = NULL;
- if (!is_otx2_vf(pfvf->pcifunc))
+ if (!is_otx2_vf(pfvf->pcifunc)) {
node->level = NIX_TXSCH_LVL_TL1;
- else
+ } else {
node->level = NIX_TXSCH_LVL_TL2;
+ node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
+ }
WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER);
node->classid = OTX2_QOS_ROOT_CLASSID;
@@ -401,9 +432,13 @@ static int otx2_qos_add_child_node(struct otx2_qos_node *parent,
struct otx2_qos_node *tmp_node;
struct list_head *tmp;
+ if (node->prio > parent->max_static_prio)
+ parent->max_static_prio = node->prio;
+
for (tmp = head->next; tmp != head; tmp = tmp->next) {
tmp_node = list_entry(tmp, struct otx2_qos_node, list);
- if (tmp_node->prio == node->prio)
+ if (tmp_node->prio == node->prio &&
+ tmp_node->is_static)
return -EEXIST;
if (tmp_node->prio > node->prio) {
list_add_tail(&node->list, tmp);
@@ -434,6 +469,10 @@ static int otx2_qos_alloc_txschq_node(struct otx2_nic *pfvf,
txschq_node->rate = 0;
txschq_node->ceil = 0;
txschq_node->prio = 0;
+ txschq_node->quantum = 0;
+ txschq_node->is_static = true;
+ txschq_node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
+ txschq_node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
mutex_lock(&pfvf->qos.qos_lock);
list_add_tail(&txschq_node->list, &node->child_schq_list);
@@ -459,7 +498,7 @@ static struct otx2_qos_node *
otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf,
struct otx2_qos_node *parent,
u16 classid, u32 prio, u64 rate, u64 ceil,
- u16 qid)
+ u32 quantum, u16 qid, bool static_cfg)
{
struct otx2_qos_node *node;
int err;
@@ -476,6 +515,10 @@ otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf,
node->rate = otx2_convert_rate(rate);
node->ceil = otx2_convert_rate(ceil);
node->prio = prio;
+ node->quantum = quantum;
+ node->is_static = static_cfg;
+ node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
+ node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
__set_bit(qid, pfvf->qos.qos_sq_bmap);
@@ -622,12 +665,28 @@ static int otx2_qos_txschq_alloc(struct otx2_nic *pfvf,
}
pfvf->qos.link_cfg_lvl = rsp->link_cfg_lvl;
+ pfvf->hw.txschq_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio;
out:
mutex_unlock(&mbox->lock);
return rc;
}
+static void otx2_qos_free_unused_txschq(struct otx2_nic *pfvf,
+ struct otx2_qos_cfg *cfg)
+{
+ int lvl, idx, schq;
+
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) {
+ if (!cfg->schq_index_used[lvl][idx]) {
+ schq = cfg->schq_contig_list[lvl][idx];
+ otx2_txschq_free_one(pfvf, lvl, schq);
+ }
+ }
+ }
+}
+
static void otx2_qos_txschq_fill_cfg_schq(struct otx2_nic *pfvf,
struct otx2_qos_node *node,
struct otx2_qos_cfg *cfg)
@@ -652,9 +711,11 @@ static void otx2_qos_txschq_fill_cfg_tl(struct otx2_nic *pfvf,
list_for_each_entry(tmp, &node->child_list, list) {
otx2_qos_txschq_fill_cfg_tl(pfvf, tmp, cfg);
cnt = cfg->static_node_pos[tmp->level];
- tmp->schq = cfg->schq_contig_list[tmp->level][cnt];
+ tmp->schq = cfg->schq_contig_list[tmp->level][tmp->txschq_idx];
+ cfg->schq_index_used[tmp->level][tmp->txschq_idx] = true;
if (cnt == 0)
- node->prio_anchor = tmp->schq;
+ node->prio_anchor =
+ cfg->schq_contig_list[tmp->level][0];
cfg->static_node_pos[tmp->level]++;
otx2_qos_txschq_fill_cfg_schq(pfvf, tmp, cfg);
}
@@ -667,9 +728,87 @@ static void otx2_qos_txschq_fill_cfg(struct otx2_nic *pfvf,
mutex_lock(&pfvf->qos.qos_lock);
otx2_qos_txschq_fill_cfg_tl(pfvf, node, cfg);
otx2_qos_txschq_fill_cfg_schq(pfvf, node, cfg);
+ otx2_qos_free_unused_txschq(pfvf, cfg);
mutex_unlock(&pfvf->qos.qos_lock);
}
+static void __otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf,
+ struct otx2_qos_node *tmp,
+ unsigned long *child_idx_bmap,
+ int child_cnt)
+{
+ int idx;
+
+ if (tmp->txschq_idx != OTX2_QOS_INVALID_TXSCHQ_IDX)
+ return;
+
+ /* assign static nodes 1:1 prio mapping first, then remaining nodes */
+ for (idx = 0; idx < child_cnt; idx++) {
+ if (tmp->is_static && tmp->prio == idx &&
+ !test_bit(idx, child_idx_bmap)) {
+ tmp->txschq_idx = idx;
+ set_bit(idx, child_idx_bmap);
+ return;
+ } else if (!tmp->is_static && idx >= tmp->prio &&
+ !test_bit(idx, child_idx_bmap)) {
+ tmp->txschq_idx = idx;
+ set_bit(idx, child_idx_bmap);
+ return;
+ }
+ }
+}
+
+static int otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf,
+ struct otx2_qos_node *node)
+{
+ unsigned long *child_idx_bmap;
+ struct otx2_qos_node *tmp;
+ int child_cnt;
+
+ list_for_each_entry(tmp, &node->child_list, list)
+ tmp->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
+
+ /* allocate child index array */
+ child_cnt = node->child_dwrr_cnt + node->max_static_prio + 1;
+ child_idx_bmap = kcalloc(BITS_TO_LONGS(child_cnt),
+ sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!child_idx_bmap)
+ return -ENOMEM;
+
+ list_for_each_entry(tmp, &node->child_list, list)
+ otx2_qos_assign_base_idx_tl(pfvf, tmp);
+
+ /* assign base index of static priority children first */
+ list_for_each_entry(tmp, &node->child_list, list) {
+ if (!tmp->is_static)
+ continue;
+ __otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap,
+ child_cnt);
+ }
+
+ /* assign base index of dwrr priority children */
+ list_for_each_entry(tmp, &node->child_list, list)
+ __otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap,
+ child_cnt);
+
+ kfree(child_idx_bmap);
+
+ return 0;
+}
+
+static int otx2_qos_assign_base_idx(struct otx2_nic *pfvf,
+ struct otx2_qos_node *node)
+{
+ int ret = 0;
+
+ mutex_lock(&pfvf->qos.qos_lock);
+ ret = otx2_qos_assign_base_idx_tl(pfvf, node);
+ mutex_unlock(&pfvf->qos.qos_lock);
+
+ return ret;
+}
+
static int otx2_qos_txschq_push_cfg_schq(struct otx2_nic *pfvf,
struct otx2_qos_node *node,
struct otx2_qos_cfg *cfg)
@@ -761,8 +900,10 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) {
- schq = cfg->schq_contig_list[lvl][idx];
- otx2_txschq_free_one(pfvf, lvl, schq);
+ if (cfg->schq_index_used[lvl][idx]) {
+ schq = cfg->schq_contig_list[lvl][idx];
+ otx2_txschq_free_one(pfvf, lvl, schq);
+ }
}
}
}
@@ -838,6 +979,10 @@ static int otx2_qos_push_txschq_cfg(struct otx2_nic *pfvf,
if (ret)
return -ENOSPC;
+ ret = otx2_qos_assign_base_idx(pfvf, node);
+ if (ret)
+ return -ENOMEM;
+
if (!(pfvf->netdev->flags & IFF_UP)) {
otx2_qos_txschq_fill_cfg(pfvf, node, cfg);
return 0;
@@ -894,6 +1039,13 @@ static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defc
goto free_root_node;
}
+ /* Update TL1 RR PRIO */
+ if (root->level == NIX_TXSCH_LVL_TL1) {
+ root->child_dwrr_prio = pfvf->hw.txschq_aggr_lvl_rr_prio;
+ netdev_dbg(pfvf->netdev,
+ "TL1 DWRR Priority %d\n", root->child_dwrr_prio);
+ }
+
if (!(pfvf->netdev->flags & IFF_UP) ||
root->level == NIX_TXSCH_LVL_TL1) {
root->schq = new_cfg->schq_list[root->level][0];
@@ -940,37 +1092,126 @@ static int otx2_qos_root_destroy(struct otx2_nic *pfvf)
return 0;
}
+static int otx2_qos_validate_quantum(struct otx2_nic *pfvf, u32 quantum)
+{
+ u32 rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum);
+ int err = 0;
+
+ /* Max Round robin weight supported by octeontx2 and CN10K
+ * is different. Validate accordingly
+ */
+ if (is_dev_otx2(pfvf->pdev))
+ err = (rr_weight > OTX2_MAX_RR_QUANTUM) ? -EINVAL : 0;
+ else if (rr_weight > CN10K_MAX_RR_WEIGHT)
+ err = -EINVAL;
+
+ return err;
+}
+
+static int otx2_qos_validate_dwrr_cfg(struct otx2_qos_node *parent,
+ struct netlink_ext_ack *extack,
+ struct otx2_nic *pfvf,
+ u64 prio, u64 quantum)
+{
+ int err;
+
+ err = otx2_qos_validate_quantum(pfvf, quantum);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported quantum value");
+ return err;
+ }
+
+ if (parent->child_dwrr_prio == OTX2_QOS_DEFAULT_PRIO) {
+ parent->child_dwrr_prio = prio;
+ } else if (prio != parent->child_dwrr_prio) {
+ NL_SET_ERR_MSG_MOD(extack, "Only one DWRR group is allowed");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static int otx2_qos_validate_configuration(struct otx2_qos_node *parent,
struct netlink_ext_ack *extack,
struct otx2_nic *pfvf,
- u64 prio)
+ u64 prio, bool static_cfg)
{
- if (test_bit(prio, parent->prio_bmap)) {
- NL_SET_ERR_MSG_MOD(extack,
- "Static priority child with same priority exists");
+ if (prio == parent->child_dwrr_prio && static_cfg) {
+ NL_SET_ERR_MSG_MOD(extack, "DWRR child group with same priority exists");
return -EEXIST;
}
- if (prio == TXSCH_TL1_DFLT_RR_PRIO) {
+ if (static_cfg && test_bit(prio, parent->prio_bmap)) {
NL_SET_ERR_MSG_MOD(extack,
- "Priority is reserved for Round Robin");
- return -EINVAL;
+ "Static priority child with same priority exists");
+ return -EEXIST;
}
return 0;
}
+static void otx2_reset_dwrr_prio(struct otx2_qos_node *parent, u64 prio)
+{
+ /* For PF, root node dwrr priority is static */
+ if (parent->level == NIX_TXSCH_LVL_TL1)
+ return;
+
+ if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) {
+ parent->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
+ clear_bit(prio, parent->prio_bmap);
+ }
+}
+
+static bool is_qos_node_dwrr(struct otx2_qos_node *parent,
+ struct otx2_nic *pfvf,
+ u64 prio)
+{
+ struct otx2_qos_node *node;
+ bool ret = false;
+
+ if (parent->child_dwrr_prio == prio)
+ return true;
+
+ mutex_lock(&pfvf->qos.qos_lock);
+ list_for_each_entry(node, &parent->child_list, list) {
+ if (prio == node->prio) {
+ if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO &&
+ parent->child_dwrr_prio != prio)
+ continue;
+
+ if (otx2_qos_validate_quantum(pfvf, node->quantum)) {
+ netdev_err(pfvf->netdev,
+ "Unsupported quantum value for existing classid=0x%x quantum=%d prio=%d",
+ node->classid, node->quantum,
+ node->prio);
+ break;
+ }
+ /* mark old node as dwrr */
+ node->is_static = false;
+ parent->child_dwrr_cnt++;
+ parent->child_static_cnt--;
+ ret = true;
+ break;
+ }
+ }
+ mutex_unlock(&pfvf->qos.qos_lock);
+
+ return ret;
+}
+
static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
u32 parent_classid, u64 rate, u64 ceil,
- u64 prio, struct netlink_ext_ack *extack)
+ u64 prio, u32 quantum,
+ struct netlink_ext_ack *extack)
{
struct otx2_qos_cfg *old_cfg, *new_cfg;
struct otx2_qos_node *node, *parent;
int qid, ret, err;
+ bool static_cfg;
netdev_dbg(pfvf->netdev,
- "TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld\n",
- classid, parent_classid, rate, ceil, prio);
+ "TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld quantum=%d\n",
+ classid, parent_classid, rate, ceil, prio, quantum);
if (prio > OTX2_QOS_MAX_PRIO) {
NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7");
@@ -978,6 +1219,12 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
goto out;
}
+ if (!quantum || quantum > INT_MAX) {
+ NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
/* get parent node */
parent = otx2_sw_node_find(pfvf, parent_classid);
if (!parent) {
@@ -991,10 +1238,24 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
goto out;
}
- ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio);
+ static_cfg = !is_qos_node_dwrr(parent, pfvf, prio);
+ ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio,
+ static_cfg);
if (ret)
goto out;
+ if (!static_cfg) {
+ ret = otx2_qos_validate_dwrr_cfg(parent, extack, pfvf, prio,
+ quantum);
+ if (ret)
+ goto out;
+ }
+
+ if (static_cfg)
+ parent->child_static_cnt++;
+ else
+ parent->child_dwrr_cnt++;
+
set_bit(prio, parent->prio_bmap);
/* read current txschq configuration */
@@ -1019,7 +1280,7 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
/* allocate and initialize a new child node */
node = otx2_qos_sw_create_leaf_node(pfvf, parent, classid, prio, rate,
- ceil, qid);
+ ceil, quantum, qid, static_cfg);
if (IS_ERR(node)) {
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node");
ret = PTR_ERR(node);
@@ -1067,6 +1328,11 @@ free_node:
free_old_cfg:
kfree(old_cfg);
reset_prio:
+ if (static_cfg)
+ parent->child_static_cnt--;
+ else
+ parent->child_dwrr_cnt--;
+
clear_bit(prio, parent->prio_bmap);
out:
return ret;
@@ -1074,10 +1340,11 @@ out:
static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
u16 child_classid, u64 rate, u64 ceil, u64 prio,
- struct netlink_ext_ack *extack)
+ u32 quantum, struct netlink_ext_ack *extack)
{
struct otx2_qos_cfg *old_cfg, *new_cfg;
struct otx2_qos_node *node, *child;
+ bool static_cfg;
int ret, err;
u16 qid;
@@ -1091,6 +1358,12 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
goto out;
}
+ if (!quantum || quantum > INT_MAX) {
+ NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes");
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
/* find node related to classid */
node = otx2_sw_node_find(pfvf, classid);
if (!node) {
@@ -1105,6 +1378,19 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
goto out;
}
+ static_cfg = !is_qos_node_dwrr(node, pfvf, prio);
+ if (!static_cfg) {
+ ret = otx2_qos_validate_dwrr_cfg(node, extack, pfvf, prio,
+ quantum);
+ if (ret)
+ goto out;
+ }
+
+ if (static_cfg)
+ node->child_static_cnt++;
+ else
+ node->child_dwrr_cnt++;
+
set_bit(prio, node->prio_bmap);
/* store the qid to assign to leaf node */
@@ -1127,7 +1413,8 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
/* allocate and initialize a new child node */
child = otx2_qos_sw_create_leaf_node(pfvf, node, child_classid,
- prio, rate, ceil, qid);
+ prio, rate, ceil, quantum,
+ qid, static_cfg);
if (IS_ERR(child)) {
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node");
ret = PTR_ERR(child);
@@ -1178,6 +1465,10 @@ free_node:
free_old_cfg:
kfree(old_cfg);
reset_prio:
+ if (static_cfg)
+ node->child_static_cnt--;
+ else
+ node->child_dwrr_cnt--;
clear_bit(prio, node->prio_bmap);
out:
return ret;
@@ -1187,6 +1478,7 @@ static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid,
struct netlink_ext_ack *extack)
{
struct otx2_qos_node *node, *parent;
+ int dwrr_del_node = false;
u64 prio;
u16 qid;
@@ -1202,12 +1494,27 @@ static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid,
prio = node->prio;
qid = node->qid;
+ if (!node->is_static)
+ dwrr_del_node = true;
+
otx2_qos_disable_sq(pfvf, node->qid);
otx2_qos_destroy_node(pfvf, node);
pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ;
- clear_bit(prio, parent->prio_bmap);
+ if (dwrr_del_node) {
+ parent->child_dwrr_cnt--;
+ } else {
+ parent->child_static_cnt--;
+ clear_bit(prio, parent->prio_bmap);
+ }
+
+ /* Reset DWRR priority if all dwrr nodes are deleted */
+ if (!parent->child_dwrr_cnt)
+ otx2_reset_dwrr_prio(parent, prio);
+
+ if (!parent->child_static_cnt)
+ parent->max_static_prio = 0;
return 0;
}
@@ -1217,6 +1524,7 @@ static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force
{
struct otx2_qos_node *node, *parent;
struct otx2_qos_cfg *new_cfg;
+ int dwrr_del_node = false;
u64 prio;
int err;
u16 qid;
@@ -1241,11 +1549,26 @@ static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force
return -ENOENT;
}
+ if (!node->is_static)
+ dwrr_del_node = true;
+
/* destroy the leaf node */
otx2_qos_destroy_node(pfvf, node);
pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ;
- clear_bit(prio, parent->prio_bmap);
+ if (dwrr_del_node) {
+ parent->child_dwrr_cnt--;
+ } else {
+ parent->child_static_cnt--;
+ clear_bit(prio, parent->prio_bmap);
+ }
+
+ /* Reset DWRR priority if all dwrr nodes are deleted */
+ if (!parent->child_dwrr_cnt)
+ otx2_reset_dwrr_prio(parent, prio);
+
+ if (!parent->child_static_cnt)
+ parent->max_static_prio = 0;
/* create downstream txschq entries to parent */
err = otx2_qos_alloc_txschq_node(pfvf, parent);
@@ -1298,10 +1621,12 @@ void otx2_qos_config_txschq(struct otx2_nic *pfvf)
if (!root)
return;
- err = otx2_qos_txschq_config(pfvf, root);
- if (err) {
- netdev_err(pfvf->netdev, "Error update txschq configuration\n");
- goto root_destroy;
+ if (root->level != NIX_TXSCH_LVL_TL1) {
+ err = otx2_qos_txschq_config(pfvf, root);
+ if (err) {
+ netdev_err(pfvf->netdev, "Error update txschq configuration\n");
+ goto root_destroy;
+ }
}
err = otx2_qos_txschq_push_cfg_tl(pfvf, root, NULL);
@@ -1334,7 +1659,8 @@ int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb)
res = otx2_qos_leaf_alloc_queue(pfvf, htb->classid,
htb->parent_classid,
htb->rate, htb->ceil,
- htb->prio, htb->extack);
+ htb->prio, htb->quantum,
+ htb->extack);
if (res < 0)
return res;
htb->qid = res;
@@ -1343,7 +1669,7 @@ int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb)
return otx2_qos_leaf_to_inner(pfvf, htb->parent_classid,
htb->classid, htb->rate,
htb->ceil, htb->prio,
- htb->extack);
+ htb->quantum, htb->extack);
case TC_HTB_LEAF_DEL:
return otx2_qos_leaf_del(pfvf, &htb->classid, htb->extack);
case TC_HTB_LEAF_DEL_LAST:
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.h b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h
index 19773284be27..221bd0438f60 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h
@@ -35,6 +35,7 @@ struct otx2_qos_cfg {
int dwrr_node_pos[NIX_TXSCH_LVL_CNT];
u16 schq_contig_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
u16 schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
+ bool schq_index_used[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
};
struct otx2_qos {
@@ -59,10 +60,18 @@ struct otx2_qos_node {
u64 ceil;
u32 classid;
u32 prio;
- u16 schq; /* hw txschq */
+ u32 quantum;
+ /* hw txschq */
+ u16 schq;
u16 qid;
u16 prio_anchor;
+ u16 max_static_prio;
+ u16 child_dwrr_cnt;
+ u16 child_static_cnt;
+ u16 child_dwrr_prio;
+ u16 txschq_idx; /* txschq allocation index */
u8 level;
+ bool is_static;
};
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.c b/drivers/net/ethernet/marvell/prestera/prestera_flower.c
index 3e20e71b0f81..8b9455d8a4f7 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_flower.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.c
@@ -202,16 +202,16 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
int err;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_META) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ICMP) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
- BIT(FLOW_DISSECTOR_KEY_VLAN))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_META) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ICMP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {
NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
index 9277a8fd1339..cc2a9ae794be 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
@@ -5,9 +5,6 @@
#include <linux/dmapool.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
#include <linux/platform_device.h>
#include "prestera_dsa.h"
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 7c487f9b36ec..07720841a8d7 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -32,7 +32,6 @@
#include <linux/prefetch.h>
#include <linux/debugfs.h>
#include <linux/mii.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/dmi.h>
@@ -4529,7 +4528,7 @@ static __init void sky2_debug_init(void)
struct dentry *ent;
ent = debugfs_create_dir("sky2", NULL);
- if (!ent || IS_ERR(ent))
+ if (IS_ERR(ent))
return;
sky2_debug = ent;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c
index 317e447f4991..7c27a19c4d8f 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c
@@ -15,10 +15,10 @@
struct mtk_eth_muxc {
const char *name;
int cap_bit;
- int (*set_path)(struct mtk_eth *eth, int path);
+ int (*set_path)(struct mtk_eth *eth, u64 path);
};
-static const char *mtk_eth_path_name(int path)
+static const char *mtk_eth_path_name(u64 path)
{
switch (path) {
case MTK_ETH_PATH_GMAC1_RGMII:
@@ -40,10 +40,10 @@ static const char *mtk_eth_path_name(int path)
}
}
-static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
+static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)
{
bool updated = true;
- u32 val, mask, set;
+ u32 mask, set, reg;
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
@@ -59,11 +59,13 @@ static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
break;
}
- if (updated) {
- val = mtk_r32(eth, MTK_MAC_MISC);
- val = (val & mask) | set;
- mtk_w32(eth, val, MTK_MAC_MISC);
- }
+ if (mtk_is_netsys_v3_or_greater(eth))
+ reg = MTK_MAC_MISC_V3;
+ else
+ reg = MTK_MAC_MISC;
+
+ if (updated)
+ mtk_m32(eth, mask, set, reg);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
@@ -71,7 +73,7 @@ static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
return 0;
}
-static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
+static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
@@ -94,7 +96,7 @@ static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
return 0;
}
-static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
+static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0, mask = 0, reg = 0;
bool updated = true;
@@ -125,7 +127,7 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
return 0;
}
-static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
+static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
@@ -163,7 +165,7 @@ static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
return 0;
}
-static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
+static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
@@ -218,7 +220,7 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = {
},
};
-static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
+static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)
{
int i, err = 0;
@@ -249,7 +251,7 @@ out:
int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
- int path;
+ u64 path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
MTK_ETH_PATH_GMAC2_SGMII;
@@ -260,7 +262,7 @@ int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
{
- int path = 0;
+ u64 path = 0;
if (mac_id == 1)
path = MTK_ETH_PATH_GMAC2_GEPHY;
@@ -274,7 +276,7 @@ int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
- int path;
+ u64 path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
MTK_ETH_PATH_GMAC2_RGMII;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 2d15342c260a..6ad42e3b488f 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -6,11 +6,12 @@
* Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
*/
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_address.h>
#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
@@ -25,6 +26,7 @@
#include <linux/bitfield.h>
#include <net/dsa.h>
#include <net/dst_metadata.h>
+#include <net/page_pool/helpers.h>
#include "mtk_eth_soc.h"
#include "mtk_wed.h"
@@ -152,6 +154,54 @@ static const struct mtk_reg_map mt7986_reg_map = {
.pse_oq_sta = 0x01a0,
};
+static const struct mtk_reg_map mt7988_reg_map = {
+ .tx_irq_mask = 0x461c,
+ .tx_irq_status = 0x4618,
+ .pdma = {
+ .rx_ptr = 0x6900,
+ .rx_cnt_cfg = 0x6904,
+ .pcrx_ptr = 0x6908,
+ .glo_cfg = 0x6a04,
+ .rst_idx = 0x6a08,
+ .delay_irq = 0x6a0c,
+ .irq_status = 0x6a20,
+ .irq_mask = 0x6a28,
+ .adma_rx_dbg0 = 0x6a38,
+ .int_grp = 0x6a50,
+ },
+ .qdma = {
+ .qtx_cfg = 0x4400,
+ .qtx_sch = 0x4404,
+ .rx_ptr = 0x4500,
+ .rx_cnt_cfg = 0x4504,
+ .qcrx_ptr = 0x4508,
+ .glo_cfg = 0x4604,
+ .rst_idx = 0x4608,
+ .delay_irq = 0x460c,
+ .fc_th = 0x4610,
+ .int_grp = 0x4620,
+ .hred = 0x4644,
+ .ctx_ptr = 0x4700,
+ .dtx_ptr = 0x4704,
+ .crx_ptr = 0x4710,
+ .drx_ptr = 0x4714,
+ .fq_head = 0x4720,
+ .fq_tail = 0x4724,
+ .fq_count = 0x4728,
+ .fq_blen = 0x472c,
+ .tx_sch_rate = 0x4798,
+ },
+ .gdm1_cnt = 0x1c00,
+ .gdma_to_ppe = 0x3333,
+ .ppe_base = 0x2000,
+ .wdma_base = {
+ [0] = 0x4800,
+ [1] = 0x4c00,
+ },
+ .pse_iq_sta = 0x0180,
+ .pse_oq_sta = 0x01a0,
+};
+
/* strings used by ethtool */
static const struct mtk_ethtool_stats {
char str[ETH_GSTRING_LEN];
@@ -179,10 +229,54 @@ static const struct mtk_ethtool_stats {
};
static const char * const mtk_clks_source_name[] = {
- "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll",
- "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb",
- "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb",
- "sgmii_ck", "eth2pll", "wocpu0", "wocpu1", "netsys0", "netsys1"
+ "ethif",
+ "sgmiitop",
+ "esw",
+ "gp0",
+ "gp1",
+ "gp2",
+ "gp3",
+ "xgp1",
+ "xgp2",
+ "xgp3",
+ "crypto",
+ "fe",
+ "trgpll",
+ "sgmii_tx250m",
+ "sgmii_rx250m",
+ "sgmii_cdr_ref",
+ "sgmii_cdr_fb",
+ "sgmii2_tx250m",
+ "sgmii2_rx250m",
+ "sgmii2_cdr_ref",
+ "sgmii2_cdr_fb",
+ "sgmii_ck",
+ "eth2pll",
+ "wocpu0",
+ "wocpu1",
+ "netsys0",
+ "netsys1",
+ "ethwarp_wocpu2",
+ "ethwarp_wocpu1",
+ "ethwarp_wocpu0",
+ "top_usxgmii0_sel",
+ "top_usxgmii1_sel",
+ "top_sgm0_sel",
+ "top_sgm1_sel",
+ "top_xfi_phy0_xtal_sel",
+ "top_xfi_phy1_xtal_sel",
+ "top_eth_gmii_sel",
+ "top_eth_refck_50m_sel",
+ "top_eth_sys_200m_sel",
+ "top_eth_sys_sel",
+ "top_eth_xgmii_sel",
+ "top_eth_mii_sel",
+ "top_netsys_sel",
+ "top_netsys_500m_sel",
+ "top_netsys_pao_2x_sel",
+ "top_netsys_sync_250m_sel",
+ "top_netsys_ppefb_250m_sel",
+ "top_netsys_warp_sel",
};
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
@@ -195,7 +289,7 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg)
return __raw_readl(eth->base + reg);
}
-static u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned reg)
+u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg)
{
u32 val;
@@ -385,10 +479,8 @@ static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
}
static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth,
- phy_interface_t interface, int speed)
+ phy_interface_t interface)
{
- unsigned long rate;
- u32 tck, rck, intf;
int ret;
if (interface == PHY_INTERFACE_MODE_TRGMII) {
@@ -399,30 +491,20 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth,
return;
}
- if (speed == SPEED_1000) {
- intf = INTF_MODE_RGMII_1000;
- rate = 250000000;
- rck = RCK_CTRL_RGMII_1000;
- tck = TCK_CTRL_RGMII_1000;
- } else {
- intf = INTF_MODE_RGMII_10_100;
- rate = 500000000;
- rck = RCK_CTRL_RGMII_10_100;
- tck = TCK_CTRL_RGMII_10_100;
- }
-
- mtk_w32(eth, intf, INTF_MODE);
-
- regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0,
- ETHSYS_TRGMII_CLK_SEL362_5,
- ETHSYS_TRGMII_CLK_SEL362_5);
+ dev_err(eth->dev, "Missing PLL configuration, ethernet may not work\n");
+}
- ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], rate);
- if (ret)
- dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret);
+static void mtk_setup_bridge_switch(struct mtk_eth *eth)
+{
+ /* Force Port1 XGMAC Link Up */
+ mtk_m32(eth, 0, MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID),
+ MTK_XGMAC_STS(MTK_GMAC1_ID));
- mtk_w32(eth, rck, TRGMII_RCK_CTRL);
- mtk_w32(eth, tck, TRGMII_TCK_CTRL);
+ /* Adjust GSW bridge IPG to 11 */
+ mtk_m32(eth, GSWTX_IPG_MASK | GSWRX_IPG_MASK,
+ (GSW_IPG_11 << GSWTX_IPG_SHIFT) |
+ (GSW_IPG_11 << GSWRX_IPG_SHIFT),
+ MTK_GSW_CFG);
}
static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
@@ -484,6 +566,8 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
goto init_err;
}
break;
+ case PHY_INTERFACE_MODE_INTERNAL:
+ break;
default:
goto err_phy;
}
@@ -498,17 +582,8 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
state->interface))
goto err_phy;
} else {
- /* FIXME: this is incorrect. Not only does it
- * use state->speed (which is not guaranteed
- * to be correct) but it also makes use of it
- * in a code path that will only be reachable
- * when the PHY interface mode changes, not
- * when the speed changes. Consequently, RGMII
- * is probably broken.
- */
mtk_gmac0_rgmii_adjust(mac->hw,
- state->interface,
- state->speed);
+ state->interface);
/* mt7623_pad_clk_setup */
for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
@@ -562,6 +637,15 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
return;
}
+ /* Setup gmac */
+ if (mtk_is_netsys_v3_or_greater(eth) &&
+ mac->interface == PHY_INTERFACE_MODE_INTERNAL) {
+ mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id));
+ mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id));
+
+ mtk_setup_bridge_switch(eth);
+ }
+
return;
err_phy:
@@ -602,38 +686,6 @@ static int mtk_mac_finish(struct phylink_config *config, unsigned int mode,
return 0;
}
-static void mtk_mac_pcs_get_state(struct phylink_config *config,
- struct phylink_link_state *state)
-{
- struct mtk_mac *mac = container_of(config, struct mtk_mac,
- phylink_config);
- u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
-
- state->link = (pmsr & MAC_MSR_LINK);
- state->duplex = (pmsr & MAC_MSR_DPX) >> 1;
-
- switch (pmsr & (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)) {
- case 0:
- state->speed = SPEED_10;
- break;
- case MAC_MSR_SPEED_100:
- state->speed = SPEED_100;
- break;
- case MAC_MSR_SPEED_1000:
- state->speed = SPEED_1000;
- break;
- default:
- state->speed = SPEED_UNKNOWN;
- break;
- }
-
- state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
- if (pmsr & MAC_MSR_RX_FC)
- state->pause |= MLO_PAUSE_RX;
- if (pmsr & MAC_MSR_TX_FC)
- state->pause |= MLO_PAUSE_TX;
-}
-
static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
@@ -659,7 +711,7 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v1(eth))
val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
if (IS_ENABLED(CONFIG_SOC_MT7621)) {
@@ -756,7 +808,6 @@ static void mtk_mac_link_up(struct phylink_config *config,
static const struct phylink_mac_ops mtk_phylink_ops = {
.mac_select_pcs = mtk_mac_select_pcs,
- .mac_pcs_get_state = mtk_mac_pcs_get_state,
.mac_config = mtk_mac_config,
.mac_finish = mtk_mac_finish,
.mac_link_down = mtk_mac_link_down,
@@ -807,11 +858,15 @@ static int mtk_mdio_init(struct mtk_eth *eth)
}
divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63);
+ /* Configure MDC Turbo Mode */
+ if (mtk_is_netsys_v3_or_greater(eth))
+ mtk_m32(eth, 0, MISC_MDC_TURBO, MTK_MAC_MISC_V3);
+
/* Configure MDC Divider */
- val = mtk_r32(eth, MTK_PPSC);
- val &= ~PPSC_MDC_CFG;
- val |= FIELD_PREP(PPSC_MDC_CFG, divider) | PPSC_MDC_TURBO;
- mtk_w32(eth, val, MTK_PPSC);
+ val = FIELD_PREP(PPSC_MDC_CFG, divider);
+ if (!mtk_is_netsys_v3_or_greater(eth))
+ val |= PPSC_MDC_TURBO;
+ mtk_m32(eth, PPSC_MDC_CFG, val, MTK_PPSC);
dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider);
@@ -943,17 +998,32 @@ void mtk_stats_update_mac(struct mtk_mac *mac)
mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x20 + offs);
hw_stats->rx_flow_control_packets +=
mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x24 + offs);
- hw_stats->tx_skip +=
- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs);
- hw_stats->tx_collisions +=
- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs);
- hw_stats->tx_bytes +=
- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs);
- stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs);
- if (stats)
- hw_stats->tx_bytes += (stats << 32);
- hw_stats->tx_packets +=
- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs);
+
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ hw_stats->tx_skip +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x50 + offs);
+ hw_stats->tx_collisions +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x54 + offs);
+ hw_stats->tx_bytes +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x40 + offs);
+ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x44 + offs);
+ if (stats)
+ hw_stats->tx_bytes += (stats << 32);
+ hw_stats->tx_packets +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x48 + offs);
+ } else {
+ hw_stats->tx_skip +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs);
+ hw_stats->tx_collisions +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs);
+ hw_stats->tx_bytes +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs);
+ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs);
+ if (stats)
+ hw_stats->tx_bytes += (stats << 32);
+ hw_stats->tx_packets +=
+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs);
+ }
}
u64_stats_update_end(&hw_stats->syncp);
@@ -963,7 +1033,7 @@ static void mtk_stats_update(struct mtk_eth *eth)
{
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->mac[i] || !eth->mac[i]->hw_stats)
continue;
if (spin_trylock(&eth->mac[i]->hw_stats->stats_lock)) {
@@ -1037,7 +1107,7 @@ static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd,
rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
}
@@ -1065,10 +1135,13 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
dma_addr_t dma_addr;
int i;
- eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
- cnt * soc->txrx.txd_size,
- &eth->phy_scratch_ring,
- GFP_KERNEL);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM))
+ eth->scratch_ring = eth->sram_base;
+ else
+ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
+ cnt * soc->txrx.txd_size,
+ &eth->phy_scratch_ring,
+ GFP_KERNEL);
if (unlikely(!eth->scratch_ring))
return -ENOMEM;
@@ -1095,7 +1168,7 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
txd->txd4 = 0;
- if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
txd->txd5 = 0;
txd->txd6 = 0;
txd->txd7 = 0;
@@ -1255,9 +1328,25 @@ static void mtk_tx_set_dma_desc_v2(struct net_device *dev, void *txd,
data = TX_DMA_PLEN0(info->size);
if (info->last)
data |= TX_DMA_LS0;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA))
+ data |= TX_DMA_PREP_ADDR64(info->addr);
+
WRITE_ONCE(desc->txd3, data);
- data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */
+ /* set forward port */
+ switch (mac->id) {
+ case MTK_GMAC1_ID:
+ data = PSE_GDM1_PORT << TX_DMA_FPORT_SHIFT_V2;
+ break;
+ case MTK_GMAC2_ID:
+ data = PSE_GDM2_PORT << TX_DMA_FPORT_SHIFT_V2;
+ break;
+ case MTK_GMAC3_ID:
+ data = PSE_GDM3_PORT << TX_DMA_FPORT_SHIFT_V2;
+ break;
+ }
+
data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);
WRITE_ONCE(desc->txd4, data);
@@ -1268,6 +1357,8 @@ static void mtk_tx_set_dma_desc_v2(struct net_device *dev, void *txd,
/* tx checksum offload */
if (info->csum)
data |= TX_DMA_CHKSUM_V2;
+ if (mtk_is_netsys_v3_or_greater(eth) && netdev_uses_dsa(dev))
+ data |= TX_DMA_SPTAG_V3;
}
WRITE_ONCE(desc->txd5, data);
@@ -1286,7 +1377,7 @@ static void mtk_tx_set_dma_desc(struct net_device *dev, void *txd,
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
mtk_tx_set_dma_desc_v2(dev, txd, info);
else
mtk_tx_set_dma_desc_v1(dev, txd, info);
@@ -1333,8 +1424,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
mtk_tx_set_dma_desc(dev, itxd, &txd_info);
itx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
- itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
- MTK_TX_FLAGS_FPORT1;
+ itx_buf->mac_id = mac->id;
setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size,
k++);
@@ -1382,8 +1472,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
memset(tx_buf, 0, sizeof(*tx_buf));
tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
- tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
- MTK_TX_FLAGS_FPORT1;
+ tx_buf->mac_id = mac->id;
setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr,
txd_info.size, k++);
@@ -1468,7 +1557,7 @@ static int mtk_queue_stopped(struct mtk_eth *eth)
{
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->netdev[i])
continue;
if (netif_queue_stopped(eth->netdev[i]))
@@ -1482,7 +1571,7 @@ static void mtk_wake_queue(struct mtk_eth *eth)
{
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->netdev[i])
continue;
netif_tx_wake_all_queues(eth->netdev[i]);
@@ -1593,7 +1682,7 @@ static void mtk_update_rx_cpu_idx(struct mtk_eth *eth)
static bool mtk_page_pool_enabled(struct mtk_eth *eth)
{
- return MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2);
+ return mtk_is_netsys_v2_or_greater(eth);
}
static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
@@ -1685,7 +1774,7 @@ static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev,
}
mtk_tx_set_dma_desc(dev, txd, txd_info);
- tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1;
+ tx_buf->mac_id = mac->id;
tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX;
tx_buf->data = (void *)MTK_DMA_DUMMY_DESC;
@@ -1912,6 +2001,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
bool xdp_flush = false;
int idx;
struct sk_buff *skb;
+ u64 addr64 = 0;
u8 *data, *new_data;
struct mtk_rx_dma_v2 *rxd, trxd;
int done = 0, bytes = 0;
@@ -1935,13 +2025,26 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
break;
/* find out which mac the packet come from. values start at 1 */
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
- mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1;
- else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
- !(trxd.rxd4 & RX_DMA_SPECIAL_TAG))
+ if (mtk_is_netsys_v2_or_greater(eth)) {
+ u32 val = RX_DMA_GET_SPORT_V2(trxd.rxd5);
+
+ switch (val) {
+ case PSE_GDM1_PORT:
+ case PSE_GDM2_PORT:
+ mac = val - 1;
+ break;
+ case PSE_GDM3_PORT:
+ mac = MTK_GMAC3_ID;
+ break;
+ default:
+ break;
+ }
+ } else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
+ !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) {
mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1;
+ }
- if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
+ if (unlikely(mac < 0 || mac >= MTK_MAX_DEVS ||
!eth->netdev[mac]))
goto release_desc;
@@ -2014,7 +2117,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
goto release_desc;
}
- dma_unmap_single(eth->dma_dev, trxd.rxd1,
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA))
+ addr64 = RX_DMA_GET_ADDR64(trxd.rxd2);
+
+ dma_unmap_single(eth->dma_dev, ((u64)trxd.rxd1 | addr64),
ring->buf_size, DMA_FROM_DEVICE);
skb = build_skb(data, ring->frag_size);
@@ -2031,7 +2137,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
skb->dev = netdev;
bytes += skb->len;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5);
hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY;
if (hash != MTK_RXD5_FOE_ENTRY)
@@ -2056,8 +2162,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
/* When using VLAN untagging in combination with DSA, the
* hardware treats the MTK special tag as a VLAN and untags it.
*/
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
- (trxd.rxd2 & RX_DMA_VTAG) && netdev_uses_dsa(netdev)) {
+ if (mtk_is_netsys_v1(eth) && (trxd.rxd2 & RX_DMA_VTAG) &&
+ netdev_uses_dsa(netdev)) {
unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0);
if (port < ARRAY_SIZE(eth->dsa_meta) &&
@@ -2080,6 +2186,9 @@ release_desc:
else
rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA))
+ rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr);
+
ring->calc_idx = idx;
done++;
}
@@ -2161,7 +2270,6 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,
while ((cpu != dma) && budget) {
u32 next_cpu = desc->txd2;
- int mac = 0;
desc = mtk_qdma_phys_to_virt(ring, desc->txd2);
if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0)
@@ -2169,15 +2277,13 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,
tx_buf = mtk_desc_to_tx_buf(ring, desc,
eth->soc->txrx.txd_size);
- if (tx_buf->flags & MTK_TX_FLAGS_FPORT1)
- mac = 1;
-
if (!tx_buf->data)
break;
if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
if (tx_buf->type == MTK_TYPE_SKB)
- mtk_poll_tx_done(eth, state, mac, tx_buf->data);
+ mtk_poll_tx_done(eth, state, tx_buf->mac_id,
+ tx_buf->data);
budget--;
}
@@ -2354,8 +2460,14 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
if (!ring->buf)
goto no_tx_mem;
- ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
- &ring->phys, GFP_KERNEL);
+ if (MTK_HAS_CAPS(soc->caps, MTK_SRAM)) {
+ ring->dma = eth->sram_base + ring_size * sz;
+ ring->phys = eth->phy_scratch_ring + ring_size * (dma_addr_t)sz;
+ } else {
+ ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
+ &ring->phys, GFP_KERNEL);
+ }
+
if (!ring->dma)
goto no_tx_mem;
@@ -2367,7 +2479,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
txd->txd2 = next_ptr;
txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
txd->txd4 = 0;
- if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
txd->txd5 = 0;
txd->txd6 = 0;
txd->txd7 = 0;
@@ -2420,14 +2532,14 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v1(eth))
val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
ofs += MTK_QTX_OFFSET;
}
val = MTK_QDMA_TX_SCH_MAX_WFQ | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4);
} else {
mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
@@ -2454,8 +2566,7 @@ static void mtk_tx_clean(struct mtk_eth *eth)
kfree(ring->buf);
ring->buf = NULL;
}
-
- if (ring->dma) {
+ if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) {
dma_free_coherent(eth->dma_dev,
ring->dma_size * soc->txrx.txd_size,
ring->dma, ring->phys);
@@ -2474,9 +2585,14 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
{
const struct mtk_reg_map *reg_map = eth->soc->reg_map;
struct mtk_rx_ring *ring;
- int rx_data_len, rx_dma_size;
+ int rx_data_len, rx_dma_size, tx_ring_size;
int i;
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+ tx_ring_size = MTK_QDMA_RING_SIZE;
+ else
+ tx_ring_size = MTK_DMA_SIZE;
+
if (rx_flag == MTK_RX_FLAGS_QDMA) {
if (ring_no)
return -EINVAL;
@@ -2511,9 +2627,20 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
ring->page_pool = pp;
}
- ring->dma = dma_alloc_coherent(eth->dma_dev,
- rx_dma_size * eth->soc->txrx.rxd_size,
- &ring->phys, GFP_KERNEL);
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
+ rx_flag != MTK_RX_FLAGS_NORMAL) {
+ ring->dma = dma_alloc_coherent(eth->dma_dev,
+ rx_dma_size * eth->soc->txrx.rxd_size,
+ &ring->phys, GFP_KERNEL);
+ } else {
+ struct mtk_tx_ring *tx_ring = &eth->tx_ring;
+
+ ring->dma = tx_ring->dma + tx_ring_size *
+ eth->soc->txrx.txd_size * (ring_no + 1);
+ ring->phys = tx_ring->phys + tx_ring_size *
+ eth->soc->txrx.txd_size * (ring_no + 1);
+ }
+
if (!ring->dma)
return -ENOMEM;
@@ -2554,9 +2681,12 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
else
rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA))
+ rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr);
+
rxd->rxd3 = 0;
rxd->rxd4 = 0;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
rxd->rxd5 = 0;
rxd->rxd6 = 0;
rxd->rxd7 = 0;
@@ -2598,8 +2728,9 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
return 0;
}
-static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring)
+static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_sram)
{
+ u64 addr64 = 0;
int i;
if (ring->data && ring->dma) {
@@ -2613,7 +2744,10 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring)
if (!rxd->rxd1)
continue;
- dma_unmap_single(eth->dma_dev, rxd->rxd1,
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA))
+ addr64 = RX_DMA_GET_ADDR64(rxd->rxd2);
+
+ dma_unmap_single(eth->dma_dev, ((u64)rxd->rxd1 | addr64),
ring->buf_size, DMA_FROM_DEVICE);
mtk_rx_put_buff(ring, ring->data[i], false);
}
@@ -2621,7 +2755,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring)
ring->data = NULL;
}
- if (ring->dma) {
+ if (!in_sram && ring->dma) {
dma_free_coherent(eth->dma_dev,
ring->dma_size * eth->soc->txrx.rxd_size,
ring->dma, ring->phys);
@@ -2978,10 +3112,10 @@ static void mtk_dma_free(struct mtk_eth *eth)
const struct mtk_soc_data *soc = eth->soc;
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++)
+ for (i = 0; i < MTK_MAX_DEVS; i++)
if (eth->netdev[i])
netdev_reset_queue(eth->netdev[i]);
- if (eth->scratch_ring) {
+ if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) {
dma_free_coherent(eth->dma_dev,
MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
eth->scratch_ring, eth->phy_scratch_ring);
@@ -2989,13 +3123,13 @@ static void mtk_dma_free(struct mtk_eth *eth)
eth->phy_scratch_ring = 0;
}
mtk_tx_clean(eth);
- mtk_rx_clean(eth, &eth->rx_ring[0]);
- mtk_rx_clean(eth, &eth->rx_ring_qdma);
+ mtk_rx_clean(eth, &eth->rx_ring[0], MTK_HAS_CAPS(soc->caps, MTK_SRAM));
+ mtk_rx_clean(eth, &eth->rx_ring_qdma, false);
if (eth->hwlro) {
mtk_hwlro_rx_uninit(eth);
for (i = 1; i < MTK_MAX_RX_RING_NUM; i++)
- mtk_rx_clean(eth, &eth->rx_ring[i]);
+ mtk_rx_clean(eth, &eth->rx_ring[i], false);
}
kfree(eth->scratch_head);
@@ -3104,7 +3238,7 @@ static int mtk_start_dma(struct mtk_eth *eth)
MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO |
MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
val |= MTK_MUTLI_CNT | MTK_RESV_BUF |
MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |
MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN;
@@ -3132,8 +3266,13 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
return;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
+ u32 val;
+
+ if (!eth->netdev[i])
+ continue;
+
+ val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
/* default setup the forward port to send frame to PDMA */
val &= ~0xffff;
@@ -3143,7 +3282,7 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
val |= config;
- if (eth->netdev[i] && netdev_uses_dsa(eth->netdev[i]))
+ if (netdev_uses_dsa(eth->netdev[i]))
val |= MTK_GDMA_SPECIAL_TAG;
mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
@@ -3250,7 +3389,7 @@ static int mtk_open(struct net_device *dev)
phylink_start(mac->phylink);
netif_tx_start_all_queues(dev);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return 0;
if (mtk_uses_dsa(dev) && !eth->prog) {
@@ -3516,19 +3655,34 @@ static void mtk_hw_reset(struct mtk_eth *eth)
{
u32 val;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth))
regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0);
+
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ val = RSTCTRL_PPE0_V3;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ val |= RSTCTRL_PPE1_V3;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE2))
+ val |= RSTCTRL_PPE2;
+
+ val |= RSTCTRL_WDMA0 | RSTCTRL_WDMA1 | RSTCTRL_WDMA2;
+ } else if (mtk_is_netsys_v2_or_greater(eth)) {
val = RSTCTRL_PPE0_V2;
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ val |= RSTCTRL_PPE1;
} else {
val = RSTCTRL_PPE0;
}
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
- val |= RSTCTRL_PPE1;
-
ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v3_or_greater(eth))
+ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN,
+ 0x6f8ff);
+ else if (mtk_is_netsys_v2_or_greater(eth))
regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN,
0x3ffffff);
}
@@ -3554,13 +3708,21 @@ static void mtk_hw_warm_reset(struct mtk_eth *eth)
return;
}
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0_V3;
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ rst_mask |= RSTCTRL_PPE1_V3;
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE2))
+ rst_mask |= RSTCTRL_PPE2;
+
+ rst_mask |= RSTCTRL_WDMA0 | RSTCTRL_WDMA1 | RSTCTRL_WDMA2;
+ } else if (mtk_is_netsys_v2_or_greater(eth)) {
rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0_V2;
- else
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ rst_mask |= RSTCTRL_PPE1;
+ } else {
rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0;
-
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
- rst_mask |= RSTCTRL_PPE1;
+ }
regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, rst_mask, rst_mask);
@@ -3724,7 +3886,7 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
else
mtk_hw_reset(eth);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
/* Set FE to PDMAv2 if necessary */
val = mtk_r32(eth, MTK_FE_GLO_MISC);
mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC);
@@ -3745,15 +3907,15 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
* up with the more appropriate value when mtk_mac_config call is being
* invoked.
*/
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
struct net_device *dev = eth->netdev[i];
- mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i));
- if (dev) {
- struct mtk_mac *mac = netdev_priv(dev);
+ if (!dev)
+ continue;
- mtk_set_mcr_max_rx(mac, dev->mtu + MTK_RX_ETH_HLEN);
- }
+ mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i));
+ mtk_set_mcr_max_rx(netdev_priv(dev),
+ dev->mtu + MTK_RX_ETH_HLEN);
}
/* Indicates CDM to parse the MTK special tag from CPU
@@ -3761,7 +3923,7 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
*/
val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v1(eth)) {
val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
@@ -3783,7 +3945,24 @@ static int mtk_hw_init(struct mtk_eth *eth, bool reset)
mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4);
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ /* PSE should not drop port1, port8 and port9 packets */
+ mtk_w32(eth, 0x00000302, PSE_DROP_CFG);
+
+ /* GDM and CDM Threshold */
+ mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES);
+ mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
+
+ /* Disable GDM1 RX CRC stripping */
+ mtk_m32(eth, MTK_GDMA_STRP_CRC, 0, MTK_GDMA_FWD_CFG(0));
+
+ /* PSE GDM3 MIB counter has incorrect hw default values,
+ * so the driver ought to read clear the values beforehand
+ * in case ethtool retrieve wrong mib values.
+ */
+ for (i = 0; i < 0x80; i += 0x4)
+ mtk_r32(eth, reg_map->gdm1_cnt + 0x100 + i);
+ } else if (!mtk_is_netsys_v1(eth)) {
/* PSE should not drop port8 and port9 packets from WDMA Tx */
mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
@@ -3895,11 +4074,17 @@ static void mtk_prepare_for_reset(struct mtk_eth *eth)
u32 val;
int i;
- /* disabe FE P3 and P4 */
- val = mtk_r32(eth, MTK_FE_GLO_CFG) | MTK_FE_LINK_DOWN_P3;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
- val |= MTK_FE_LINK_DOWN_P4;
- mtk_w32(eth, val, MTK_FE_GLO_CFG);
+ /* set FE PPE ports link down */
+ for (i = MTK_GMAC1_ID;
+ i <= (mtk_is_netsys_v3_or_greater(eth) ? MTK_GMAC3_ID : MTK_GMAC2_ID);
+ i += 2) {
+ val = mtk_r32(eth, MTK_FE_GLO_CFG(i)) | MTK_FE_LINK_DOWN_P(PSE_PPE0_PORT);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ val |= MTK_FE_LINK_DOWN_P(PSE_PPE1_PORT);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE2))
+ val |= MTK_FE_LINK_DOWN_P(PSE_PPE2_PORT);
+ mtk_w32(eth, val, MTK_FE_GLO_CFG(i));
+ }
/* adjust PPE configurations to prepare for reset */
for (i = 0; i < ARRAY_SIZE(eth->ppe); i++)
@@ -3933,7 +4118,7 @@ static void mtk_pending_work(struct work_struct *work)
mtk_prepare_for_reset(eth);
/* stop all devices to make sure that dma is properly shut down */
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->netdev[i] || !netif_running(eth->netdev[i]))
continue;
@@ -3949,8 +4134,8 @@ static void mtk_pending_work(struct work_struct *work)
mtk_hw_init(eth, true);
/* restart DMA and enable IRQs */
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- if (!test_bit(i, &restart))
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
+ if (!eth->netdev[i] || !test_bit(i, &restart))
continue;
if (mtk_open(eth->netdev[i])) {
@@ -3960,11 +4145,18 @@ static void mtk_pending_work(struct work_struct *work)
}
}
- /* enabe FE P3 and P4 */
- val = mtk_r32(eth, MTK_FE_GLO_CFG) & ~MTK_FE_LINK_DOWN_P3;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
- val &= ~MTK_FE_LINK_DOWN_P4;
- mtk_w32(eth, val, MTK_FE_GLO_CFG);
+ /* set FE PPE ports link up */
+ for (i = MTK_GMAC1_ID;
+ i <= (mtk_is_netsys_v3_or_greater(eth) ? MTK_GMAC3_ID : MTK_GMAC2_ID);
+ i += 2) {
+ val = mtk_r32(eth, MTK_FE_GLO_CFG(i)) & ~MTK_FE_LINK_DOWN_P(PSE_PPE0_PORT);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+ val &= ~MTK_FE_LINK_DOWN_P(PSE_PPE1_PORT);
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE2))
+ val &= ~MTK_FE_LINK_DOWN_P(PSE_PPE2_PORT);
+
+ mtk_w32(eth, val, MTK_FE_GLO_CFG(i));
+ }
clear_bit(MTK_RESETTING, &eth->state);
@@ -3977,7 +4169,7 @@ static int mtk_free_dev(struct mtk_eth *eth)
{
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->netdev[i])
continue;
free_netdev(eth->netdev[i]);
@@ -3996,7 +4188,7 @@ static int mtk_unreg_dev(struct mtk_eth *eth)
{
int i;
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
struct mtk_mac *mac;
if (!eth->netdev[i])
continue;
@@ -4298,7 +4490,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
}
id = be32_to_cpup(_id);
- if (id >= MTK_MAC_COUNT) {
+ if (id >= MTK_MAX_DEVS) {
dev_err(eth->dev, "%d is not a valid mac id\n", id);
return -EINVAL;
}
@@ -4346,7 +4538,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
}
spin_lock_init(&mac->hw_stats->stats_lock);
u64_stats_init(&mac->hw_stats->syncp);
- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ if (mtk_is_netsys_v3_or_greater(eth))
+ mac->hw_stats->reg_offset = id * 0x80;
+ else
+ mac->hw_stats->reg_offset = id * 0x40;
/* phylink create */
err = of_get_phy_mode(np, &phy_mode);
@@ -4361,18 +4557,22 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
mac->phylink_config.dev = &eth->netdev[id]->dev;
mac->phylink_config.type = PHYLINK_NETDEV;
- /* This driver makes use of state->speed in mac_config */
- mac->phylink_config.legacy_pre_march2020 = true;
mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
- __set_bit(PHY_INTERFACE_MODE_MII,
- mac->phylink_config.supported_interfaces);
- __set_bit(PHY_INTERFACE_MODE_GMII,
- mac->phylink_config.supported_interfaces);
+ /* MT7623 gmac0 is now missing its speed-specific PLL configuration
+ * in its .mac_config method (since state->speed is not valid there.
+ * Disable support for MII, GMII and RGMII.
+ */
+ if (!mac->hw->soc->disable_pll_modes || mac->id != 0) {
+ __set_bit(PHY_INTERFACE_MODE_MII,
+ mac->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_GMII,
+ mac->phylink_config.supported_interfaces);
- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII))
- phy_interface_set_rgmii(mac->phylink_config.supported_interfaces);
+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII))
+ phy_interface_set_rgmii(mac->phylink_config.supported_interfaces);
+ }
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && !mac->id)
__set_bit(PHY_INTERFACE_MODE_TRGMII,
@@ -4396,6 +4596,17 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
mac->phylink_config.supported_interfaces);
}
+ if (mtk_is_netsys_v3_or_greater(mac->hw) &&
+ MTK_HAS_CAPS(mac->hw->soc->caps, MTK_ESW_BIT) &&
+ id == MTK_GMAC1_ID) {
+ mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
+ MAC_SYM_PAUSE |
+ MAC_10000FD;
+ phy_interface_zero(mac->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ mac->phylink_config.supported_interfaces);
+ }
+
phylink = phylink_create(&mac->phylink_config,
of_fwnode_handle(mac->of_node),
phy_mode, &mtk_phylink_ops);
@@ -4454,7 +4665,7 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
rtnl_lock();
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
dev = eth->netdev[i];
if (!dev || !(dev->flags & IFF_UP))
@@ -4507,7 +4718,7 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
static int mtk_probe(struct platform_device *pdev)
{
- struct resource *res = NULL;
+ struct resource *res = NULL, *res_sram;
struct device_node *mac_np;
struct mtk_eth *eth;
int err, i;
@@ -4527,6 +4738,28 @@ static int mtk_probe(struct platform_device *pdev)
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
eth->ip_align = NET_IP_ALIGN;
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) {
+ /* SRAM is actual memory and supports transparent access just like DRAM.
+ * Hence we don't require __iomem being set and don't need to use accessor
+ * functions to read from or write to SRAM.
+ */
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ eth->sram_base = (void __force *)devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(eth->sram_base))
+ return PTR_ERR(eth->sram_base);
+ } else {
+ eth->sram_base = (void __force *)eth->base + MTK_ETH_SRAM_OFFSET;
+ }
+ }
+
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) {
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
+ if (err) {
+ dev_err(&pdev->dev, "Wrong DMA config\n");
+ return -EINVAL;
+ }
+ }
+
spin_lock_init(&eth->page_lock);
spin_lock_init(&eth->tx_irq_lock);
spin_lock_init(&eth->rx_irq_lock);
@@ -4584,12 +4817,24 @@ static int mtk_probe(struct platform_device *pdev)
}
}
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
err = -EINVAL;
goto err_destroy_sgmii;
}
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) {
+ if (mtk_is_netsys_v3_or_greater(eth)) {
+ res_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_sram) {
+ err = -EINVAL;
+ goto err_destroy_sgmii;
+ }
+ eth->phy_scratch_ring = res_sram->start;
+ } else {
+ eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET;
+ }
+ }
}
if (eth->soc->offload_version) {
@@ -4692,9 +4937,8 @@ static int mtk_probe(struct platform_device *pdev)
}
if (eth->soc->offload_version) {
- u32 num_ppe;
+ u32 num_ppe = mtk_is_netsys_v2_or_greater(eth) ? 2 : 1;
- num_ppe = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe);
for (i = 0; i < num_ppe; i++) {
u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
@@ -4761,7 +5005,7 @@ static int mtk_remove(struct platform_device *pdev)
int i;
/* stop all devices to make sure that dma is properly shut down */
- for (i = 0; i < MTK_MAC_COUNT; i++) {
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
if (!eth->netdev[i])
continue;
mtk_stop(eth->netdev[i]);
@@ -4786,6 +5030,7 @@ static const struct mtk_soc_data mt2701_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
+ .version = 1,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4802,9 +5047,10 @@ static const struct mtk_soc_data mt7621_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7621_CLKS_BITMAP,
.required_pctl = false,
+ .version = 1,
.offload_version = 1,
.hash_offset = 2,
- .foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4822,10 +5068,11 @@ static const struct mtk_soc_data mt7622_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7622_CLKS_BITMAP,
.required_pctl = false,
+ .version = 1,
.offload_version = 2,
.hash_offset = 2,
.has_accounting = true,
- .foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4842,9 +5089,11 @@ static const struct mtk_soc_data mt7623_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
+ .version = 1,
.offload_version = 1,
.hash_offset = 2,
- .foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
+ .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE,
+ .disable_pll_modes = true,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4863,6 +5112,7 @@ static const struct mtk_soc_data mt7629_data = {
.required_clks = MT7629_CLKS_BITMAP,
.required_pctl = false,
.has_accounting = true,
+ .version = 1,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4880,10 +5130,11 @@ static const struct mtk_soc_data mt7981_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
+ .version = 2,
.offload_version = 2,
.hash_offset = 4,
- .foe_entry_size = sizeof(struct mtk_foe_entry),
.has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
.rxd_size = sizeof(struct mtk_rx_dma_v2),
@@ -4901,10 +5152,33 @@ static const struct mtk_soc_data mt7986_data = {
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
+ .version = 2,
+ .offload_version = 2,
+ .hash_offset = 4,
+ .has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE,
+ .txrx = {
+ .txd_size = sizeof(struct mtk_tx_dma_v2),
+ .rxd_size = sizeof(struct mtk_rx_dma_v2),
+ .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
+ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
+ .dma_len_offset = 8,
+ },
+};
+
+static const struct mtk_soc_data mt7988_data = {
+ .reg_map = &mt7988_reg_map,
+ .ana_rgc3 = 0x128,
+ .caps = MT7988_CAPS,
+ .hw_features = MTK_HW_FEATURES,
+ .required_clks = MT7988_CLKS_BITMAP,
+ .required_pctl = false,
+ .version = 3,
.offload_version = 2,
.hash_offset = 4,
- .foe_entry_size = sizeof(struct mtk_foe_entry),
.has_accounting = true,
+ .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
.rxd_size = sizeof(struct mtk_rx_dma_v2),
@@ -4921,6 +5195,7 @@ static const struct mtk_soc_data rt5350_data = {
.hw_features = MTK_HW_FEATURES_MT7628,
.required_clks = MT7628_CLKS_BITMAP,
.required_pctl = false,
+ .version = 1,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma),
@@ -4932,14 +5207,15 @@ static const struct mtk_soc_data rt5350_data = {
};
const struct of_device_id of_mtk_match[] = {
- { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
- { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data},
- { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
- { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
- { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
- { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data},
- { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data},
- { .compatible = "ralink,rt5350-eth", .data = &rt5350_data},
+ { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data },
+ { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data },
+ { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data },
+ { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data },
+ { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data },
+ { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data },
+ { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data },
+ { .compatible = "mediatek,mt7988-eth", .data = &mt7988_data },
+ { .compatible = "ralink,rt5350-eth", .data = &rt5350_data },
{},
};
MODULE_DEVICE_TABLE(of, of_mtk_match);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 707445f6bcb1..403219d987ef 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -18,7 +18,7 @@
#include <linux/rhashtable.h>
#include <linux/dim.h>
#include <linux/bitfield.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <linux/bpf_trace.h>
#include "mtk_ppe.h"
@@ -33,7 +33,6 @@
#define MTK_TX_DMA_BUF_LEN_V2 0xffff
#define MTK_QDMA_RING_SIZE 2048
#define MTK_DMA_SIZE 512
-#define MTK_MAC_COUNT 2
#define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN)
#define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
#define MTK_DMA_DUMMY_DESC 0xffffffff
@@ -77,9 +76,8 @@
#define MTK_HW_LRO_SDL_REMAIN_ROOM 1522
/* Frame Engine Global Configuration */
-#define MTK_FE_GLO_CFG 0x00
-#define MTK_FE_LINK_DOWN_P3 BIT(11)
-#define MTK_FE_LINK_DOWN_P4 BIT(12)
+#define MTK_FE_GLO_CFG(x) (((x) == MTK_GMAC3_ID) ? 0x24 : 0x00)
+#define MTK_FE_LINK_DOWN_P(x) BIT(((x) + 8) % 16)
/* Frame Engine Global Reset Register */
#define MTK_RST_GL 0x04
@@ -118,19 +116,31 @@
#define MTK_CDMP_EG_CTRL 0x404
/* GDM Exgress Control Register */
-#define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000))
+#define MTK_GDMA_FWD_CFG(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \
+ 0x540 : 0x500 + (_x * 0x1000); })
#define MTK_GDMA_SPECIAL_TAG BIT(24)
#define MTK_GDMA_ICS_EN BIT(22)
#define MTK_GDMA_TCS_EN BIT(21)
#define MTK_GDMA_UCS_EN BIT(20)
+#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
#define MTK_GDMA_DROP_ALL 0x7777
+/* GDM Egress Control Register */
+#define MTK_GDMA_EG_CTRL(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \
+ 0x544 : 0x504 + (_x * 0x1000); })
+#define MTK_GDMA_XGDM_SEL BIT(31)
+
/* Unicast Filter MAC Address Register - Low */
-#define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000))
+#define MTK_GDMA_MAC_ADRL(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \
+ 0x548 : 0x508 + (_x * 0x1000); })
/* Unicast Filter MAC Address Register - High */
-#define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000))
+#define MTK_GDMA_MAC_ADRH(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \
+ 0x54C : 0x50C + (_x * 0x1000); })
+
+/* Internal SRAM offset */
+#define MTK_ETH_SRAM_OFFSET 0x40000
/* FE global misc reg*/
#define MTK_FE_GLO_MISC 0x124
@@ -288,8 +298,6 @@
/* QDMA Interrupt grouping registers */
#define MTK_RLS_DONE_INT BIT(0)
-#define MTK_STAT_OFFSET 0x40
-
/* QDMA TX NUM */
#define QID_BITS_V2(x) (((x) & 0x3f) << 16)
#define MTK_QDMA_GMAC2_QID 8
@@ -302,6 +310,8 @@
#define TX_DMA_CHKSUM_V2 (0x7 << 28)
#define TX_DMA_TSO_V2 BIT(31)
+#define TX_DMA_SPTAG_V3 BIT(27)
+
/* QDMA V2 descriptor txd4 */
#define TX_DMA_FPORT_SHIFT_V2 8
#define TX_DMA_FPORT_MASK_V2 0xf
@@ -321,6 +331,14 @@
#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len)
#define TX_DMA_SWC BIT(14)
#define TX_DMA_PQID GENMASK(3, 0)
+#define TX_DMA_ADDR64_MASK GENMASK(3, 0)
+#if IS_ENABLED(CONFIG_64BIT)
+# define TX_DMA_GET_ADDR64(x) (((u64)FIELD_GET(TX_DMA_ADDR64_MASK, (x))) << 32)
+# define TX_DMA_PREP_ADDR64(x) FIELD_PREP(TX_DMA_ADDR64_MASK, ((x) >> 32))
+#else
+# define TX_DMA_GET_ADDR64(x) (0)
+# define TX_DMA_PREP_ADDR64(x) (0)
+#endif
/* PDMA on MT7628 */
#define TX_DMA_DONE BIT(31)
@@ -333,6 +351,14 @@
#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->txrx.dma_len_offset) & eth->soc->txrx.dma_max_len)
#define RX_DMA_VTAG BIT(15)
+#define RX_DMA_ADDR64_MASK GENMASK(3, 0)
+#if IS_ENABLED(CONFIG_64BIT)
+# define RX_DMA_GET_ADDR64(x) (((u64)FIELD_GET(RX_DMA_ADDR64_MASK, (x))) << 32)
+# define RX_DMA_PREP_ADDR64(x) FIELD_PREP(RX_DMA_ADDR64_MASK, ((x) >> 32))
+#else
+# define RX_DMA_GET_ADDR64(x) (0)
+# define RX_DMA_PREP_ADDR64(x) (0)
+#endif
/* QDMA descriptor rxd3 */
#define RX_DMA_VID(x) ((x) & VLAN_VID_MASK)
@@ -389,7 +415,26 @@
#define PHY_IAC_TIMEOUT HZ
#define MTK_MAC_MISC 0x1000c
+#define MTK_MAC_MISC_V3 0x10010
#define MTK_MUX_TO_ESW BIT(0)
+#define MISC_MDC_TURBO BIT(4)
+
+/* XMAC status registers */
+#define MTK_XGMAC_STS(x) (((x) == MTK_GMAC3_ID) ? 0x1001C : 0x1000C)
+#define MTK_XGMAC_FORCE_LINK(x) (((x) == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
+#define MTK_USXGMII_PCS_LINK BIT(8)
+#define MTK_XGMAC_RX_FC BIT(5)
+#define MTK_XGMAC_TX_FC BIT(4)
+#define MTK_USXGMII_PCS_MODE GENMASK(3, 1)
+#define MTK_XGMAC_LINK_STS BIT(0)
+
+/* GSW bridge registers */
+#define MTK_GSW_CFG (0x10080)
+#define GSWTX_IPG_MASK GENMASK(19, 16)
+#define GSWTX_IPG_SHIFT 16
+#define GSWRX_IPG_MASK GENMASK(3, 0)
+#define GSWRX_IPG_SHIFT 0
+#define GSW_IPG_11 11
/* Mac control registers */
#define MTK_MAC_MCR(x) (0x10100 + (x * 0x100))
@@ -478,7 +523,7 @@
#define ETHSYS_SYSCFG0 0x14
#define SYSCFG0_GE_MASK 0x3
#define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2)))
-#define SYSCFG0_SGMII_MASK GENMASK(9, 8)
+#define SYSCFG0_SGMII_MASK GENMASK(9, 7)
#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & SYSCFG0_SGMII_MASK)
#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK)
#define SYSCFG0_SGMII_GMAC1_V2 BIT(9)
@@ -495,9 +540,15 @@
/* ethernet reset control register */
#define ETHSYS_RSTCTRL 0x34
#define RSTCTRL_FE BIT(6)
+#define RSTCTRL_WDMA0 BIT(24)
+#define RSTCTRL_WDMA1 BIT(25)
+#define RSTCTRL_WDMA2 BIT(26)
#define RSTCTRL_PPE0 BIT(31)
#define RSTCTRL_PPE0_V2 BIT(30)
#define RSTCTRL_PPE1 BIT(31)
+#define RSTCTRL_PPE0_V3 BIT(29)
+#define RSTCTRL_PPE1_V3 BIT(30)
+#define RSTCTRL_PPE2 BIT(31)
#define RSTCTRL_ETH BIT(23)
/* ethernet reset check idle register */
@@ -635,12 +686,6 @@ enum mtk_tx_flags {
*/
MTK_TX_FLAGS_SINGLE0 = 0x01,
MTK_TX_FLAGS_PAGE0 = 0x02,
-
- /* MTK_TX_FLAGS_FPORTx allows tracking which port the transmitted
- * SKB out instead of looking up through hardware TX descriptor.
- */
- MTK_TX_FLAGS_FPORT0 = 0x04,
- MTK_TX_FLAGS_FPORT1 = 0x08,
};
/* This enum allows us to identify how the clock is defined on the array of the
@@ -653,6 +698,11 @@ enum mtk_clks_map {
MTK_CLK_GP0,
MTK_CLK_GP1,
MTK_CLK_GP2,
+ MTK_CLK_GP3,
+ MTK_CLK_XGP1,
+ MTK_CLK_XGP2,
+ MTK_CLK_XGP3,
+ MTK_CLK_CRYPTO,
MTK_CLK_FE,
MTK_CLK_TRGPLL,
MTK_CLK_SGMII_TX_250M,
@@ -669,63 +719,145 @@ enum mtk_clks_map {
MTK_CLK_WOCPU1,
MTK_CLK_NETSYS0,
MTK_CLK_NETSYS1,
+ MTK_CLK_ETHWARP_WOCPU2,
+ MTK_CLK_ETHWARP_WOCPU1,
+ MTK_CLK_ETHWARP_WOCPU0,
+ MTK_CLK_TOP_USXGMII_SBUS_0_SEL,
+ MTK_CLK_TOP_USXGMII_SBUS_1_SEL,
+ MTK_CLK_TOP_SGM_0_SEL,
+ MTK_CLK_TOP_SGM_1_SEL,
+ MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL,
+ MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL,
+ MTK_CLK_TOP_ETH_GMII_SEL,
+ MTK_CLK_TOP_ETH_REFCK_50M_SEL,
+ MTK_CLK_TOP_ETH_SYS_200M_SEL,
+ MTK_CLK_TOP_ETH_SYS_SEL,
+ MTK_CLK_TOP_ETH_XGMII_SEL,
+ MTK_CLK_TOP_ETH_MII_SEL,
+ MTK_CLK_TOP_NETSYS_SEL,
+ MTK_CLK_TOP_NETSYS_500M_SEL,
+ MTK_CLK_TOP_NETSYS_PAO_2X_SEL,
+ MTK_CLK_TOP_NETSYS_SYNC_250M_SEL,
+ MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL,
+ MTK_CLK_TOP_NETSYS_WARP_SEL,
MTK_CLK_MAX
};
-#define MT7623_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \
- BIT(MTK_CLK_GP1) | BIT(MTK_CLK_GP2) | \
- BIT(MTK_CLK_TRGPLL))
-#define MT7622_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \
- BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
- BIT(MTK_CLK_GP2) | \
- BIT(MTK_CLK_SGMII_TX_250M) | \
- BIT(MTK_CLK_SGMII_RX_250M) | \
- BIT(MTK_CLK_SGMII_CDR_REF) | \
- BIT(MTK_CLK_SGMII_CDR_FB) | \
- BIT(MTK_CLK_SGMII_CK) | \
- BIT(MTK_CLK_ETH2PLL))
+#define MT7623_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \
+ BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \
+ BIT_ULL(MTK_CLK_TRGPLL))
+#define MT7622_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \
+ BIT_ULL(MTK_CLK_GP0) | BIT_ULL(MTK_CLK_GP1) | \
+ BIT_ULL(MTK_CLK_GP2) | \
+ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII_CK) | \
+ BIT_ULL(MTK_CLK_ETH2PLL))
#define MT7621_CLKS_BITMAP (0)
#define MT7628_CLKS_BITMAP (0)
-#define MT7629_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \
- BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
- BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \
- BIT(MTK_CLK_SGMII_TX_250M) | \
- BIT(MTK_CLK_SGMII_RX_250M) | \
- BIT(MTK_CLK_SGMII_CDR_REF) | \
- BIT(MTK_CLK_SGMII_CDR_FB) | \
- BIT(MTK_CLK_SGMII2_TX_250M) | \
- BIT(MTK_CLK_SGMII2_RX_250M) | \
- BIT(MTK_CLK_SGMII2_CDR_REF) | \
- BIT(MTK_CLK_SGMII2_CDR_FB) | \
- BIT(MTK_CLK_SGMII_CK) | \
- BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
-#define MT7981_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
- BIT(MTK_CLK_WOCPU0) | \
- BIT(MTK_CLK_SGMII_TX_250M) | \
- BIT(MTK_CLK_SGMII_RX_250M) | \
- BIT(MTK_CLK_SGMII_CDR_REF) | \
- BIT(MTK_CLK_SGMII_CDR_FB) | \
- BIT(MTK_CLK_SGMII2_TX_250M) | \
- BIT(MTK_CLK_SGMII2_RX_250M) | \
- BIT(MTK_CLK_SGMII2_CDR_REF) | \
- BIT(MTK_CLK_SGMII2_CDR_FB) | \
- BIT(MTK_CLK_SGMII_CK))
-#define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
- BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \
- BIT(MTK_CLK_SGMII_TX_250M) | \
- BIT(MTK_CLK_SGMII_RX_250M) | \
- BIT(MTK_CLK_SGMII_CDR_REF) | \
- BIT(MTK_CLK_SGMII_CDR_FB) | \
- BIT(MTK_CLK_SGMII2_TX_250M) | \
- BIT(MTK_CLK_SGMII2_RX_250M) | \
- BIT(MTK_CLK_SGMII2_CDR_REF) | \
- BIT(MTK_CLK_SGMII2_CDR_FB))
+#define MT7629_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \
+ BIT_ULL(MTK_CLK_GP0) | BIT_ULL(MTK_CLK_GP1) | \
+ BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_FE) | \
+ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII_CK) | \
+ BIT_ULL(MTK_CLK_ETH2PLL) | BIT_ULL(MTK_CLK_SGMIITOP))
+#define MT7981_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_GP2) | \
+ BIT_ULL(MTK_CLK_GP1) | \
+ BIT_ULL(MTK_CLK_WOCPU0) | \
+ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII_CK))
+#define MT7986_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_GP2) | \
+ BIT_ULL(MTK_CLK_GP1) | \
+ BIT_ULL(MTK_CLK_WOCPU1) | BIT_ULL(MTK_CLK_WOCPU0) | \
+ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \
+ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \
+ BIT_ULL(MTK_CLK_SGMII2_CDR_FB))
+#define MT7988_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_ESW) | \
+ BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \
+ BIT_ULL(MTK_CLK_GP3) | BIT_ULL(MTK_CLK_XGP1) | \
+ BIT_ULL(MTK_CLK_XGP2) | BIT_ULL(MTK_CLK_XGP3) | \
+ BIT_ULL(MTK_CLK_CRYPTO) | \
+ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \
+ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \
+ BIT_ULL(MTK_CLK_ETHWARP_WOCPU2) | \
+ BIT_ULL(MTK_CLK_ETHWARP_WOCPU1) | \
+ BIT_ULL(MTK_CLK_ETHWARP_WOCPU0) | \
+ BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_0_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_1_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_SGM_0_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_SGM_1_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_GMII_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_REFCK_50M_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_SYS_200M_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_SYS_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_XGMII_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_ETH_MII_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_500M_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_PAO_2X_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_SYNC_250M_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL) | \
+ BIT_ULL(MTK_CLK_TOP_NETSYS_WARP_SEL))
enum mtk_dev_state {
MTK_HW_INIT,
MTK_RESETTING
};
+/* PSE Port Definition */
+enum mtk_pse_port {
+ PSE_ADMA_PORT = 0,
+ PSE_GDM1_PORT,
+ PSE_GDM2_PORT,
+ PSE_PPE0_PORT,
+ PSE_PPE1_PORT,
+ PSE_QDMA_TX_PORT,
+ PSE_QDMA_RX_PORT,
+ PSE_DROP_PORT,
+ PSE_WDMA0_PORT,
+ PSE_WDMA1_PORT,
+ PSE_TDMA_PORT,
+ PSE_NONE_PORT,
+ PSE_PPE2_PORT,
+ PSE_WDMA2_PORT,
+ PSE_EIP197_PORT,
+ PSE_GDM3_PORT,
+ PSE_PORT_MAX
+};
+
+/* GMAC Identifier */
+enum mtk_gmac_id {
+ MTK_GMAC1_ID = 0,
+ MTK_GMAC2_ID,
+ MTK_GMAC3_ID,
+ MTK_GMAC_ID_MAX
+};
+
enum mtk_tx_buf_type {
MTK_TYPE_SKB,
MTK_TYPE_XDP_TX,
@@ -744,7 +876,8 @@ struct mtk_tx_buf {
enum mtk_tx_buf_type type;
void *data;
- u32 flags;
+ u16 mac_id;
+ u16 flags;
DEFINE_DMA_UNMAP_ADDR(dma_addr0);
DEFINE_DMA_UNMAP_LEN(dma_len0);
DEFINE_DMA_UNMAP_ADDR(dma_addr1);
@@ -820,10 +953,12 @@ enum mkt_eth_capabilities {
MTK_SHARED_INT_BIT,
MTK_TRGMII_MT7621_CLK_BIT,
MTK_QDMA_BIT,
- MTK_NETSYS_V2_BIT,
MTK_SOC_MT7628_BIT,
MTK_RSTCTRL_PPE1_BIT,
+ MTK_RSTCTRL_PPE2_BIT,
MTK_U3_COPHY_V2_BIT,
+ MTK_SRAM_BIT,
+ MTK_36BIT_DMA_BIT,
/* MUX BITS*/
MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
@@ -843,42 +978,44 @@ enum mkt_eth_capabilities {
};
/* Supported hardware group on SoCs */
-#define MTK_RGMII BIT(MTK_RGMII_BIT)
-#define MTK_TRGMII BIT(MTK_TRGMII_BIT)
-#define MTK_SGMII BIT(MTK_SGMII_BIT)
-#define MTK_ESW BIT(MTK_ESW_BIT)
-#define MTK_GEPHY BIT(MTK_GEPHY_BIT)
-#define MTK_MUX BIT(MTK_MUX_BIT)
-#define MTK_INFRA BIT(MTK_INFRA_BIT)
-#define MTK_SHARED_SGMII BIT(MTK_SHARED_SGMII_BIT)
-#define MTK_HWLRO BIT(MTK_HWLRO_BIT)
-#define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT)
-#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT)
-#define MTK_QDMA BIT(MTK_QDMA_BIT)
-#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT)
-#define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT)
-#define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT)
-#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT)
+#define MTK_RGMII BIT_ULL(MTK_RGMII_BIT)
+#define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT)
+#define MTK_SGMII BIT_ULL(MTK_SGMII_BIT)
+#define MTK_ESW BIT_ULL(MTK_ESW_BIT)
+#define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT)
+#define MTK_MUX BIT_ULL(MTK_MUX_BIT)
+#define MTK_INFRA BIT_ULL(MTK_INFRA_BIT)
+#define MTK_SHARED_SGMII BIT_ULL(MTK_SHARED_SGMII_BIT)
+#define MTK_HWLRO BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_SHARED_INT BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_TRGMII_MT7621_CLK BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
+#define MTK_QDMA BIT_ULL(MTK_QDMA_BIT)
+#define MTK_SOC_MT7628 BIT_ULL(MTK_SOC_MT7628_BIT)
+#define MTK_RSTCTRL_PPE1 BIT_ULL(MTK_RSTCTRL_PPE1_BIT)
+#define MTK_RSTCTRL_PPE2 BIT_ULL(MTK_RSTCTRL_PPE2_BIT)
+#define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT)
+#define MTK_SRAM BIT_ULL(MTK_SRAM_BIT)
+#define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT)
#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \
- BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
+ BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
#define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY \
- BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
+ BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \
- BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
+ BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
#define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \
- BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
+ BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
#define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \
- BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
+ BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
/* Supported path present on SoCs */
-#define MTK_ETH_PATH_GMAC1_RGMII BIT(MTK_ETH_PATH_GMAC1_RGMII_BIT)
-#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
-#define MTK_ETH_PATH_GMAC1_SGMII BIT(MTK_ETH_PATH_GMAC1_SGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_RGMII BIT(MTK_ETH_PATH_GMAC2_RGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_GEPHY BIT(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
-#define MTK_ETH_PATH_GDM1_ESW BIT(MTK_ETH_PATH_GDM1_ESW_BIT)
+#define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_TRGMII BIT_ULL(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
+#define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT)
#define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII)
#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
@@ -934,11 +1071,14 @@ enum mkt_eth_capabilities {
#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
- MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
+ MTK_RSTCTRL_PPE1 | MTK_SRAM)
#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
- MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
+ MTK_RSTCTRL_PPE1 | MTK_SRAM)
+
+#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \
+ MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM)
struct mtk_tx_dma_desc_info {
dma_addr_t addr;
@@ -1009,6 +1149,7 @@ struct mtk_reg_map {
* @required_pctl A bool value to show whether the SoC requires
* the extra setup for those pins used by GMAC.
* @hash_offset Flow table hash offset.
+ * @version SoC version.
* @foe_entry_size Foe table entry size.
* @has_accounting Bool indicating support for accounting of
* offloaded flows.
@@ -1022,14 +1163,16 @@ struct mtk_reg_map {
struct mtk_soc_data {
const struct mtk_reg_map *reg_map;
u32 ana_rgc3;
- u32 caps;
- u32 required_clks;
+ u64 caps;
+ u64 required_clks;
bool required_pctl;
u8 offload_version;
u8 hash_offset;
+ u8 version;
u16 foe_entry_size;
netdev_features_t hw_features;
bool has_accounting;
+ bool disable_pll_modes;
struct {
u32 txd_size;
u32 rxd_size;
@@ -1042,8 +1185,8 @@ struct mtk_soc_data {
#define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000)
-/* currently no SoC has more than 2 macs */
-#define MTK_MAX_DEVS 2
+/* currently no SoC has more than 3 macs */
+#define MTK_MAX_DEVS 3
/* struct mtk_eth - This is the main datasructure for holding the state
* of the driver
@@ -1095,6 +1238,7 @@ struct mtk_eth {
struct device *dev;
struct device *dma_dev;
void __iomem *base;
+ void *sram_base;
spinlock_t page_lock;
spinlock_t tx_irq_lock;
spinlock_t rx_irq_lock;
@@ -1182,6 +1326,21 @@ struct mtk_mac {
/* the struct describing the SoC. these are declared in the soc_xyz.c files */
extern const struct of_device_id of_mtk_match[];
+static inline bool mtk_is_netsys_v1(struct mtk_eth *eth)
+{
+ return eth->soc->version == 1;
+}
+
+static inline bool mtk_is_netsys_v2_or_greater(struct mtk_eth *eth)
+{
+ return eth->soc->version > 1;
+}
+
+static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth)
+{
+ return eth->soc->version > 2;
+}
+
static inline struct mtk_foe_entry *
mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash)
{
@@ -1192,7 +1351,7 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash)
static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB1_BIND_TIMESTAMP_V2;
return MTK_FOE_IB1_BIND_TIMESTAMP;
@@ -1200,7 +1359,7 @@ static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth)
static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB1_BIND_PPPOE_V2;
return MTK_FOE_IB1_BIND_PPPOE;
@@ -1208,7 +1367,7 @@ static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth)
static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB1_BIND_VLAN_TAG_V2;
return MTK_FOE_IB1_BIND_VLAN_TAG;
@@ -1216,7 +1375,7 @@ static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth)
static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB1_BIND_VLAN_LAYER_V2;
return MTK_FOE_IB1_BIND_VLAN_LAYER;
@@ -1224,7 +1383,7 @@ static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth)
static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val);
return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, val);
@@ -1232,7 +1391,7 @@ static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val);
return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, val);
@@ -1240,7 +1399,7 @@ static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val)
static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB1_PACKET_TYPE_V2;
return MTK_FOE_IB1_PACKET_TYPE;
@@ -1248,7 +1407,7 @@ static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth)
static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE_V2, val);
return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, val);
@@ -1256,7 +1415,7 @@ static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val)
static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth)
{
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
return MTK_FOE_IB2_MULTICAST_V2;
return MTK_FOE_IB2_MULTICAST;
@@ -1267,6 +1426,7 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg);
int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 9129821f3ab8..86f32f486043 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -92,7 +92,6 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
{
- u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
u32 val, cnt_r0, cnt_r1, cnt_r2;
int ret;
@@ -107,12 +106,20 @@ static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *p
cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
- byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
- byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
- pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
- pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
- *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
- *packets = (pkt_cnt_high << 16) | pkt_cnt_low;
+ if (mtk_is_netsys_v3_or_greater(ppe->eth)) {
+ /* 64 bit for each counter */
+ u32 cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3);
+ *bytes = ((u64)cnt_r1 << 32) | cnt_r0;
+ *packets = ((u64)cnt_r3 << 32) | cnt_r2;
+ } else {
+ /* 48 bit byte counter, 40 bit packet counter */
+ u32 byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
+ u32 byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
+ u32 pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
+ u32 pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
+ *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
+ *packets = ((u64)pkt_cnt_high << 16) | pkt_cnt_low;
+ }
return 0;
}
@@ -208,7 +215,7 @@ int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry,
memset(entry, 0, sizeof(*entry));
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE_V2, type) |
FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
@@ -272,7 +279,7 @@ int mtk_foe_entry_set_pse_port(struct mtk_eth *eth,
u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
u32 val = *ib2;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
val &= ~MTK_FOE_IB2_DEST_PORT_V2;
val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, port);
} else {
@@ -423,13 +430,22 @@ int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry);
u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ switch (eth->soc->version) {
+ case 3:
+ *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) |
+ MTK_FOE_IB2_WDMA_WINFO_V2;
+ l2->w3info = FIELD_PREP(MTK_FOE_WINFO_WCID_V3, wcid) |
+ FIELD_PREP(MTK_FOE_WINFO_BSS_V3, bss);
+ break;
+ case 2:
*ib2 &= ~MTK_FOE_IB2_PORT_MG_V2;
*ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) |
MTK_FOE_IB2_WDMA_WINFO_V2;
l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
- } else {
+ break;
+ default:
*ib2 &= ~MTK_FOE_IB2_PORT_MG;
*ib2 |= MTK_FOE_IB2_WDMA_WINFO;
if (wdma_idx)
@@ -437,6 +453,7 @@ int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) |
FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) |
FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq);
+ break;
}
return 0;
@@ -447,7 +464,7 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
{
u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
*ib2 &= ~MTK_FOE_IB2_QID_V2;
*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID_V2, queue);
*ib2 |= MTK_FOE_IB2_PSE_QOS_V2;
@@ -603,7 +620,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
struct mtk_foe_entry *hwe;
u32 val;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2;
entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP_V2,
timestamp);
@@ -619,7 +636,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
hwe->ib1 = entry->ib1;
if (ppe->accounting) {
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
val = MTK_FOE_IB2_MIB_CNT_V2;
else
val = MTK_FOE_IB2_MIB_CNT;
@@ -964,8 +981,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
mtk_ppe_init_foe_table(ppe);
ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
- val = MTK_PPE_TB_CFG_ENTRY_80B |
- MTK_PPE_TB_CFG_AGE_NON_L4 |
+ val = MTK_PPE_TB_CFG_AGE_NON_L4 |
MTK_PPE_TB_CFG_AGE_UNBIND |
MTK_PPE_TB_CFG_AGE_TCP |
MTK_PPE_TB_CFG_AGE_UDP |
@@ -979,8 +995,10 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) |
FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
MTK_PPE_ENTRIES_SHIFT);
- if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(ppe->eth))
val |= MTK_PPE_TB_CFG_INFO_SEL;
+ if (!mtk_is_netsys_v3_or_greater(ppe->eth))
+ val |= MTK_PPE_TB_CFG_ENTRY_80B;
ppe_w32(ppe, MTK_PPE_TB_CFG, val);
ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK,
@@ -995,7 +1013,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
MTK_PPE_FLOW_CFG_IP4_NAPT |
MTK_PPE_FLOW_CFG_IP4_DSLITE |
MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
- if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(ppe->eth))
val |= MTK_PPE_MD_TOAP_BYP_CRSN0 |
MTK_PPE_MD_TOAP_BYP_CRSN1 |
MTK_PPE_MD_TOAP_BYP_CRSN2 |
@@ -1037,7 +1055,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
- if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(ppe->eth)) {
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index e51de31a52ec..e3d0ec72bc69 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -85,6 +85,17 @@ enum {
#define MTK_FOE_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_WINFO_WCID GENMASK(15, 6)
+#define MTK_FOE_WINFO_BSS_V3 GENMASK(23, 16)
+#define MTK_FOE_WINFO_WCID_V3 GENMASK(15, 0)
+
+#define MTK_FOE_WINFO_PAO_USR_INFO GENMASK(15, 0)
+#define MTK_FOE_WINFO_PAO_TID GENMASK(19, 16)
+#define MTK_FOE_WINFO_PAO_IS_FIXEDRATE BIT(20)
+#define MTK_FOE_WINFO_PAO_IS_PRIOR BIT(21)
+#define MTK_FOE_WINFO_PAO_IS_SP BIT(22)
+#define MTK_FOE_WINFO_PAO_HF BIT(23)
+#define MTK_FOE_WINFO_PAO_AMSDU_EN BIT(24)
+
enum {
MTK_FOE_STATE_INVALID,
MTK_FOE_STATE_UNBIND,
@@ -106,8 +117,13 @@ struct mtk_foe_mac_info {
u16 pppoe_id;
u16 src_mac_lo;
+ /* netsys_v2 */
u16 minfo;
u16 winfo;
+
+ /* netsys_v3 */
+ u32 w3info;
+ u32 wpao;
};
/* software-only entry type */
@@ -216,6 +232,10 @@ struct mtk_foe_ipv6_6rd {
struct mtk_foe_mac_info l2;
};
+#define MTK_FOE_ENTRY_V1_SIZE 80
+#define MTK_FOE_ENTRY_V2_SIZE 96
+#define MTK_FOE_ENTRY_V3_SIZE 128
+
struct mtk_foe_entry {
u32 ib1;
@@ -225,7 +245,7 @@ struct mtk_foe_entry {
struct mtk_foe_ipv4_dslite dslite;
struct mtk_foe_ipv6 ipv6;
struct mtk_foe_ipv6_6rd ipv6_6rd;
- u32 data[23];
+ u32 data[31];
};
};
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 02eebff02d45..a70a5417c173 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -193,7 +193,7 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue,
info.bss, info.wcid);
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+ if (mtk_is_netsys_v2_or_greater(eth)) {
switch (info.wdma_idx) {
case 0:
pse_port = 8;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
index a2e61b3eb006..3ce088eef0ef 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
@@ -163,6 +163,8 @@ enum {
#define MTK_PPE_MIB_SER_R2 0x348
#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
+#define MTK_PPE_MIB_SER_R3 0x34c
+
#define MTK_PPE_MIB_CACHE_CTL 0x350
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c
index 02c03325911f..31aebeb2e285 100644
--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c
+++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 985cff910f30..94376aa2b34c 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/bitfield.h>
@@ -221,9 +222,13 @@ void mtk_wed_fe_reset(void)
for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
struct mtk_wed_hw *hw = hw_list[i];
- struct mtk_wed_device *dev = hw->wed_dev;
+ struct mtk_wed_device *dev;
int err;
+ if (!hw)
+ break;
+
+ dev = hw->wed_dev;
if (!dev || !dev->wlan.reset)
continue;
@@ -244,8 +249,12 @@ void mtk_wed_fe_reset_complete(void)
for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
struct mtk_wed_hw *hw = hw_list[i];
- struct mtk_wed_device *dev = hw->wed_dev;
+ struct mtk_wed_device *dev;
+
+ if (!hw)
+ break;
+ dev = hw->wed_dev;
if (!dev || !dev->wlan.reset_complete)
continue;
@@ -1091,7 +1100,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
} else {
struct mtk_eth *eth = dev->hw->eth;
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ if (mtk_is_netsys_v2_or_greater(eth))
wed_set(dev, MTK_WED_RESET_IDX,
MTK_WED_RESET_IDX_RX_V2);
else
@@ -1907,7 +1916,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
hw->wdma = wdma;
hw->index = index;
hw->irq = irq;
- hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1;
+ hw->version = mtk_is_netsys_v1(eth) ? 1 : 2;
if (hw->version == 1) {
hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
index b244c02c5b51..e24afeaea0da 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
@@ -84,7 +84,6 @@ dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
}
}
-
static int
wed_txinfo_show(struct seq_file *s, void *data)
{
@@ -127,16 +126,23 @@ wed_txinfo_show(struct seq_file *s, void *data)
DUMP_WDMA_RING(WDMA_RING_RX(0)),
DUMP_WDMA_RING(WDMA_RING_RX(1)),
- DUMP_STR("TX FREE"),
+ DUMP_STR("WED TX FREE"),
DUMP_WED(WED_RX_MIB(0)),
+ DUMP_WED_RING(WED_RING_RX(0)),
+ DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(0)),
+ DUMP_WED(WED_RX_MIB(1)),
+ DUMP_WED_RING(WED_RING_RX(1)),
+ DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(1)),
+
+ DUMP_STR("WED WPDMA TX FREE"),
+ DUMP_WED_RING(WED_WPDMA_RING_RX(0)),
+ DUMP_WED_RING(WED_WPDMA_RING_RX(1)),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
- if (!dev)
- return 0;
-
- dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
+ if (dev)
+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
@@ -208,10 +214,8 @@ wed_rxinfo_show(struct seq_file *s, void *data)
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
- if (!dev)
- return 0;
-
- dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
+ if (dev)
+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
index 0a50bb98c5ea..47ea69feb3b2 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
@@ -266,6 +266,8 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4)
#define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4)
+#define MTK_WED_WPDMA_RX_MIB(_n) (0x5e0 + (_n) * 4)
+#define MTK_WED_WPDMA_RX_COHERENT_MIB(_n) (0x5f0 + (_n) * 4)
#define MTK_WED_WPDMA_RING_TX(_n) (0x600 + (_n) * 0x10)
#define MTK_WED_WPDMA_RING_RX(_n) (0x700 + (_n) * 0x10)
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
index 69fba29055e9..3bd51a3d6650 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
@@ -7,10 +7,9 @@
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
-#include <linux/of_platform.h>
#include <linux/interrupt.h>
-#include <linux/of_address.h>
#include <linux/mfd/syscon.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/bitfield.h>
diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig
index 1b4b1f642317..825e05fb8607 100644
--- a/drivers/net/ethernet/mellanox/mlx4/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig
@@ -27,6 +27,7 @@ config MLX4_EN_DCB
config MLX4_CORE
tristate
depends on PCI
+ select AUXILIARY_BUS
select NET_DEVLINK
default n
diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c
index 0eb7b83637d8..0d8a362c2673 100644
--- a/drivers/net/ethernet/mellanox/mlx4/catas.c
+++ b/drivers/net/ethernet/mellanox/mlx4/catas.c
@@ -194,7 +194,7 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
mutex_unlock(&persist->device_state_mutex);
/* At that step HW was already reset, now notify clients */
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
+ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, NULL);
mlx4_cmd_wake_completions(dev);
return;
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index c56d2194cbfc..f5b1f8c7834f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -2113,7 +2113,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
goto inform_slave_state;
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave);
+ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, &slave);
/* write the version in the event field */
reply |= mlx4_comm_get_version();
@@ -2152,7 +2152,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (mlx4_master_activate_admin_state(priv, slave))
goto reset_slave;
slave_state[slave].active = true;
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
+ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, &slave);
break;
case MLX4_COMM_CMD_VHCR_POST:
if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 7d45f1d55f79..164a13272faa 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1467,8 +1467,8 @@ static int add_ip_rule(struct mlx4_en_priv *priv,
struct list_head *list_h)
{
int err;
- struct mlx4_spec_list *spec_l2 = NULL;
- struct mlx4_spec_list *spec_l3 = NULL;
+ struct mlx4_spec_list *spec_l2;
+ struct mlx4_spec_list *spec_l3;
struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;
spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
@@ -1505,9 +1505,9 @@ static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
struct list_head *list_h, int proto)
{
int err;
- struct mlx4_spec_list *spec_l2 = NULL;
- struct mlx4_spec_list *spec_l3 = NULL;
- struct mlx4_spec_list *spec_l4 = NULL;
+ struct mlx4_spec_list *spec_l2;
+ struct mlx4_spec_list *spec_l3;
+ struct mlx4_spec_list *spec_l4;
struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec;
spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index f1259bdb1a29..d8f4d00ad26b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -183,24 +183,31 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
}
}
-static void *mlx4_en_get_netdev(struct mlx4_dev *dev, void *ctx, u8 port)
+static int mlx4_en_event(struct notifier_block *this, unsigned long event,
+ void *param)
{
- struct mlx4_en_dev *endev = ctx;
-
- return endev->pndev[port];
-}
-
-static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
- enum mlx4_dev_event event, unsigned long port)
-{
- struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr;
+ struct mlx4_en_dev *mdev =
+ container_of(this, struct mlx4_en_dev, mlx_nb);
+ struct mlx4_dev *dev = mdev->dev;
struct mlx4_en_priv *priv;
+ int port;
+
+ switch (event) {
+ case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
+ case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
+ case MLX4_DEV_EVENT_SLAVE_INIT:
+ case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
+ break;
+ default:
+ port = *(int *)param;
+ break;
+ }
switch (event) {
case MLX4_DEV_EVENT_PORT_UP:
case MLX4_DEV_EVENT_PORT_DOWN:
if (!mdev->pndev[port])
- return;
+ return NOTIFY_DONE;
priv = netdev_priv(mdev->pndev[port]);
/* To prevent races, we poll the link state in a separate
task rather than changing it here */
@@ -212,23 +219,30 @@ static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
mlx4_err(mdev, "Internal error detected, restarting device\n");
break;
+ case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
case MLX4_DEV_EVENT_SLAVE_INIT:
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
break;
default:
if (port < 1 || port > dev->caps.num_ports ||
!mdev->pndev[port])
- return;
- mlx4_warn(mdev, "Unhandled event %d for port %d\n", event,
- (int) port);
+ return NOTIFY_DONE;
+ mlx4_warn(mdev, "Unhandled event %d for port %d\n", (int)event,
+ port);
}
+
+ return NOTIFY_DONE;
}
-static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
+static void mlx4_en_remove(struct auxiliary_device *adev)
{
- struct mlx4_en_dev *mdev = endev_ptr;
+ struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
+ struct mlx4_dev *dev = madev->mdev;
+ struct mlx4_en_dev *mdev = auxiliary_get_drvdata(adev);
int i;
+ mlx4_unregister_event_notifier(dev, &mdev->mlx_nb);
+
mutex_lock(&mdev->state_lock);
mdev->device_up = false;
mutex_unlock(&mdev->state_lock);
@@ -242,52 +256,41 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
iounmap(mdev->uar_map);
mlx4_uar_free(dev, &mdev->priv_uar);
mlx4_pd_free(dev, mdev->priv_pdn);
- if (mdev->nb.notifier_call)
- unregister_netdevice_notifier(&mdev->nb);
+ if (mdev->netdev_nb.notifier_call)
+ unregister_netdevice_notifier(&mdev->netdev_nb);
kfree(mdev);
}
-static void mlx4_en_activate(struct mlx4_dev *dev, void *ctx)
-{
- int i;
- struct mlx4_en_dev *mdev = ctx;
-
- /* Create a netdev for each port */
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
- mlx4_info(mdev, "Activating port:%d\n", i);
- if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
- mdev->pndev[i] = NULL;
- }
-
- /* register notifier */
- mdev->nb.notifier_call = mlx4_en_netdev_event;
- if (register_netdevice_notifier(&mdev->nb)) {
- mdev->nb.notifier_call = NULL;
- mlx4_err(mdev, "Failed to create notifier\n");
- }
-}
-
-static void *mlx4_en_add(struct mlx4_dev *dev)
+static int mlx4_en_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
+ struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
+ struct mlx4_dev *dev = madev->mdev;
struct mlx4_en_dev *mdev;
- int i;
+ int err, i;
printk_once(KERN_INFO "%s", mlx4_en_version);
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
- if (!mdev)
+ if (!mdev) {
+ err = -ENOMEM;
goto err_free_res;
+ }
- if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
+ err = mlx4_pd_alloc(dev, &mdev->priv_pdn);
+ if (err)
goto err_free_dev;
- if (mlx4_uar_alloc(dev, &mdev->priv_uar))
+ err = mlx4_uar_alloc(dev, &mdev->priv_uar);
+ if (err)
goto err_pd;
mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT,
PAGE_SIZE);
- if (!mdev->uar_map)
+ if (!mdev->uar_map) {
+ err = -ENOMEM;
goto err_uar;
+ }
spin_lock_init(&mdev->uar_lock);
mdev->dev = dev;
@@ -299,13 +302,15 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (!mdev->LSO_support)
mlx4_warn(mdev, "LSO not supported, please upgrade to later FW version to enable LSO\n");
- if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
- MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
- 0, 0, &mdev->mr)) {
+ err = mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
+ MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, 0, 0,
+ &mdev->mr);
+ if (err) {
mlx4_err(mdev, "Failed allocating memory region\n");
goto err_map;
}
- if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
+ err = mlx4_mr_enable(mdev->dev, &mdev->mr);
+ if (err) {
mlx4_err(mdev, "Failed enabling memory region\n");
goto err_mr;
}
@@ -325,15 +330,39 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
* Note: we cannot use the shared workqueue because of deadlocks caused
* by the rtnl lock */
mdev->workqueue = create_singlethread_workqueue("mlx4_en");
- if (!mdev->workqueue)
+ if (!mdev->workqueue) {
+ err = -ENOMEM;
goto err_mr;
+ }
/* At this stage all non-port specific tasks are complete:
* mark the card state as up */
mutex_init(&mdev->state_lock);
mdev->device_up = true;
- return mdev;
+ /* register mlx4 core notifier */
+ mdev->mlx_nb.notifier_call = mlx4_en_event;
+ err = mlx4_register_event_notifier(dev, &mdev->mlx_nb);
+ WARN(err, "failed to register mlx4 event notifier (%d)", err);
+
+ /* Setup ports */
+
+ /* Create a netdev for each port */
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ mlx4_info(mdev, "Activating port:%d\n", i);
+ if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
+ mdev->pndev[i] = NULL;
+ }
+
+ /* register netdev notifier */
+ mdev->netdev_nb.notifier_call = mlx4_en_netdev_event;
+ if (register_netdevice_notifier(&mdev->netdev_nb)) {
+ mdev->netdev_nb.notifier_call = NULL;
+ mlx4_err(mdev, "Failed to create netdev notifier\n");
+ }
+
+ auxiliary_set_drvdata(adev, mdev);
+ return 0;
err_mr:
(void) mlx4_mr_free(dev, &mdev->mr);
@@ -347,16 +376,24 @@ err_pd:
err_free_dev:
kfree(mdev);
err_free_res:
- return NULL;
+ return err;
}
-static struct mlx4_interface mlx4_en_interface = {
- .add = mlx4_en_add,
- .remove = mlx4_en_remove,
- .event = mlx4_en_event,
- .get_dev = mlx4_en_get_netdev,
+static const struct auxiliary_device_id mlx4_en_id_table[] = {
+ { .name = MLX4_ADEV_NAME ".eth" },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, mlx4_en_id_table);
+
+static struct mlx4_adrv mlx4_en_adrv = {
+ .adrv = {
+ .name = "eth",
+ .probe = mlx4_en_probe,
+ .remove = mlx4_en_remove,
+ .id_table = mlx4_en_id_table,
+ },
.protocol = MLX4_PROT_ETH,
- .activate = mlx4_en_activate,
};
static void mlx4_en_verify_params(void)
@@ -385,12 +422,12 @@ static int __init mlx4_en_init(void)
mlx4_en_verify_params();
mlx4_en_init_ptys2ethtool_map();
- return mlx4_register_interface(&mlx4_en_interface);
+ return mlx4_register_auxiliary_driver(&mlx4_en_adrv);
}
static void __exit mlx4_en_cleanup(void)
{
- mlx4_unregister_interface(&mlx4_en_interface);
+ mlx4_unregister_auxiliary_driver(&mlx4_en_adrv);
}
module_init(mlx4_en_init);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index e11bc0ac880e..33bbcced8105 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -291,7 +291,7 @@ mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip,
__be32 dst_ip, u8 ip_proto, __be16 src_port,
__be16 dst_port, u32 flow_id)
{
- struct mlx4_en_filter *filter = NULL;
+ struct mlx4_en_filter *filter;
filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC);
if (!filter)
@@ -2894,63 +2894,6 @@ static const struct xdp_metadata_ops mlx4_xdp_metadata_ops = {
.xmo_rx_hash = mlx4_en_xdp_rx_hash,
};
-struct mlx4_en_bond {
- struct work_struct work;
- struct mlx4_en_priv *priv;
- int is_bonded;
- struct mlx4_port_map port_map;
-};
-
-static void mlx4_en_bond_work(struct work_struct *work)
-{
- struct mlx4_en_bond *bond = container_of(work,
- struct mlx4_en_bond,
- work);
- int err = 0;
- struct mlx4_dev *dev = bond->priv->mdev->dev;
-
- if (bond->is_bonded) {
- if (!mlx4_is_bonded(dev)) {
- err = mlx4_bond(dev);
- if (err)
- en_err(bond->priv, "Fail to bond device\n");
- }
- if (!err) {
- err = mlx4_port_map_set(dev, &bond->port_map);
- if (err)
- en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n",
- bond->port_map.port1,
- bond->port_map.port2,
- err);
- }
- } else if (mlx4_is_bonded(dev)) {
- err = mlx4_unbond(dev);
- if (err)
- en_err(bond->priv, "Fail to unbond device\n");
- }
- dev_put(bond->priv->dev);
- kfree(bond);
-}
-
-static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded,
- u8 v2p_p1, u8 v2p_p2)
-{
- struct mlx4_en_bond *bond = NULL;
-
- bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
- if (!bond)
- return -ENOMEM;
-
- INIT_WORK(&bond->work, mlx4_en_bond_work);
- bond->priv = priv;
- bond->is_bonded = is_bonded;
- bond->port_map.port1 = v2p_p1;
- bond->port_map.port2 = v2p_p2;
- dev_hold(priv->dev);
- queue_work(priv->mdev->workqueue, &bond->work);
- return 0;
-}
-
int mlx4_en_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -2960,14 +2903,13 @@ int mlx4_en_netdev_event(struct notifier_block *this,
struct mlx4_dev *dev;
int i, num_eth_ports = 0;
bool do_bond = true;
- struct mlx4_en_priv *priv;
u8 v2p_port1 = 0;
u8 v2p_port2 = 0;
if (!net_eq(dev_net(ndev), &init_net))
return NOTIFY_DONE;
- mdev = container_of(this, struct mlx4_en_dev, nb);
+ mdev = container_of(this, struct mlx4_en_dev, netdev_nb);
dev = mdev->dev;
/* Go into this mode only when two network devices set on two ports
@@ -2995,7 +2937,6 @@ int mlx4_en_netdev_event(struct notifier_block *this,
if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port)
return NOTIFY_DONE;
- priv = netdev_priv(ndev);
if (do_bond) {
struct netdev_notifier_bonding_info *notifier_info = ptr;
struct netdev_bonding_info *bonding_info =
@@ -3062,8 +3003,7 @@ int mlx4_en_netdev_event(struct notifier_block *this,
}
}
- mlx4_en_queue_bond_work(priv, do_bond,
- v2p_port1, v2p_port2);
+ mlx4_queue_bond_work(dev, do_bond, v2p_port1, v2p_port2);
return NOTIFY_DONE;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 414e390e6b48..6598b10a9ff4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -501,7 +501,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
int port;
int slave = 0;
int ret;
- u32 flr_slave;
+ int flr_slave;
u8 update_slave_state;
int i;
enum slave_port_gen_event gen_event;
@@ -606,8 +606,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
port = be32_to_cpu(eqe->event.port_change.port) >> 28;
slaves_port = mlx4_phys_to_slaves_pport(dev, port);
if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
- port);
+ mlx4_dispatch_event(
+ dev, MLX4_DEV_EVENT_PORT_DOWN, &port);
mlx4_priv(dev)->sense.do_sense_port[port] = 1;
if (!mlx4_is_master(dev))
break;
@@ -647,7 +647,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
}
}
} else {
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port);
+ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP,
+ &port);
mlx4_priv(dev)->sense.do_sense_port[port] = 0;
@@ -758,7 +759,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
}
spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN,
- flr_slave);
+ &flr_slave);
queue_work(priv->mfunc.master.comm_wq,
&priv->mfunc.master.slave_flr_event_work);
break;
@@ -787,8 +788,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
break;
case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT:
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE,
- (unsigned long) eqe);
+ mlx4_dispatch_event(
+ dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, eqe);
break;
case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT:
diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c
index 65482f004e50..a371b970ac1e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/intf.c
+++ b/drivers/net/ethernet/mellanox/mlx4/intf.c
@@ -38,102 +38,131 @@
#include "mlx4.h"
-struct mlx4_device_context {
- struct list_head list;
- struct list_head bond_list;
- struct mlx4_interface *intf;
- void *context;
-};
-
-static LIST_HEAD(intf_list);
-static LIST_HEAD(dev_list);
static DEFINE_MUTEX(intf_mutex);
+static DEFINE_IDA(mlx4_adev_ida);
-static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
+static bool is_eth_supported(struct mlx4_dev *dev)
{
- struct mlx4_device_context *dev_ctx;
+ for (int port = 1; port <= dev->caps.num_ports; port++)
+ if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
+ return true;
- dev_ctx = kmalloc(sizeof(*dev_ctx), GFP_KERNEL);
- if (!dev_ctx)
- return;
+ return false;
+}
- dev_ctx->intf = intf;
- dev_ctx->context = intf->add(&priv->dev);
+static bool is_ib_supported(struct mlx4_dev *dev)
+{
+ for (int port = 1; port <= dev->caps.num_ports; port++)
+ if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)
+ return true;
- if (dev_ctx->context) {
- spin_lock_irq(&priv->ctx_lock);
- list_add_tail(&dev_ctx->list, &priv->ctx_list);
- spin_unlock_irq(&priv->ctx_lock);
- if (intf->activate)
- intf->activate(&priv->dev, dev_ctx->context);
- } else
- kfree(dev_ctx);
+ if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)
+ return true;
+ return false;
}
-static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
+static const struct mlx4_adev_device {
+ const char *suffix;
+ bool (*is_supported)(struct mlx4_dev *dev);
+} mlx4_adev_devices[] = {
+ { "eth", is_eth_supported },
+ { "ib", is_ib_supported },
+};
+
+int mlx4_adev_init(struct mlx4_dev *dev)
{
- struct mlx4_device_context *dev_ctx;
+ struct mlx4_priv *priv = mlx4_priv(dev);
- list_for_each_entry(dev_ctx, &priv->ctx_list, list)
- if (dev_ctx->intf == intf) {
- spin_lock_irq(&priv->ctx_lock);
- list_del(&dev_ctx->list);
- spin_unlock_irq(&priv->ctx_lock);
+ priv->adev_idx = ida_alloc(&mlx4_adev_ida, GFP_KERNEL);
+ if (priv->adev_idx < 0)
+ return priv->adev_idx;
- intf->remove(&priv->dev, dev_ctx->context);
- kfree(dev_ctx);
- return;
- }
+ priv->adev = kcalloc(ARRAY_SIZE(mlx4_adev_devices),
+ sizeof(struct mlx4_adev *), GFP_KERNEL);
+ if (!priv->adev) {
+ ida_free(&mlx4_adev_ida, priv->adev_idx);
+ return -ENOMEM;
+ }
+
+ return 0;
}
-int mlx4_register_interface(struct mlx4_interface *intf)
+void mlx4_adev_cleanup(struct mlx4_dev *dev)
{
- struct mlx4_priv *priv;
-
- if (!intf->add || !intf->remove)
- return -EINVAL;
-
- mutex_lock(&intf_mutex);
+ struct mlx4_priv *priv = mlx4_priv(dev);
- list_add_tail(&intf->list, &intf_list);
- list_for_each_entry(priv, &dev_list, dev_list) {
- if (mlx4_is_mfunc(&priv->dev) && (intf->flags & MLX4_INTFF_BONDING)) {
- mlx4_dbg(&priv->dev,
- "SRIOV, disabling HA mode for intf proto %d\n", intf->protocol);
- intf->flags &= ~MLX4_INTFF_BONDING;
- }
- mlx4_add_device(intf, priv);
- }
+ kfree(priv->adev);
+ ida_free(&mlx4_adev_ida, priv->adev_idx);
+}
- mutex_unlock(&intf_mutex);
+static void adev_release(struct device *dev)
+{
+ struct mlx4_adev *mlx4_adev =
+ container_of(dev, struct mlx4_adev, adev.dev);
+ struct mlx4_priv *priv = mlx4_priv(mlx4_adev->mdev);
+ int idx = mlx4_adev->idx;
- return 0;
+ kfree(mlx4_adev);
+ priv->adev[idx] = NULL;
}
-EXPORT_SYMBOL_GPL(mlx4_register_interface);
-void mlx4_unregister_interface(struct mlx4_interface *intf)
+static struct mlx4_adev *add_adev(struct mlx4_dev *dev, int idx)
{
- struct mlx4_priv *priv;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ const char *suffix = mlx4_adev_devices[idx].suffix;
+ struct auxiliary_device *adev;
+ struct mlx4_adev *madev;
+ int ret;
- mutex_lock(&intf_mutex);
+ madev = kzalloc(sizeof(*madev), GFP_KERNEL);
+ if (!madev)
+ return ERR_PTR(-ENOMEM);
- list_for_each_entry(priv, &dev_list, dev_list)
- mlx4_remove_device(intf, priv);
+ adev = &madev->adev;
+ adev->id = priv->adev_idx;
+ adev->name = suffix;
+ adev->dev.parent = &dev->persist->pdev->dev;
+ adev->dev.release = adev_release;
+ madev->mdev = dev;
+ madev->idx = idx;
- list_del(&intf->list);
+ ret = auxiliary_device_init(adev);
+ if (ret) {
+ kfree(madev);
+ return ERR_PTR(ret);
+ }
- mutex_unlock(&intf_mutex);
+ ret = auxiliary_device_add(adev);
+ if (ret) {
+ auxiliary_device_uninit(adev);
+ return ERR_PTR(ret);
+ }
+ return madev;
+}
+
+static void del_adev(struct auxiliary_device *adev)
+{
+ auxiliary_device_delete(adev);
+ auxiliary_device_uninit(adev);
+}
+
+int mlx4_register_auxiliary_driver(struct mlx4_adrv *madrv)
+{
+ return auxiliary_driver_register(&madrv->adrv);
+}
+EXPORT_SYMBOL_GPL(mlx4_register_auxiliary_driver);
+
+void mlx4_unregister_auxiliary_driver(struct mlx4_adrv *madrv)
+{
+ auxiliary_driver_unregister(&madrv->adrv);
}
-EXPORT_SYMBOL_GPL(mlx4_unregister_interface);
+EXPORT_SYMBOL_GPL(mlx4_unregister_auxiliary_driver);
int mlx4_do_bond(struct mlx4_dev *dev, bool enable)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_device_context *dev_ctx = NULL, *temp_dev_ctx;
- unsigned long flags;
- int ret;
- LIST_HEAD(bond_list);
+ int i, ret;
if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP))
return -EOPNOTSUPP;
@@ -155,69 +184,178 @@ int mlx4_do_bond(struct mlx4_dev *dev, bool enable)
dev->flags &= ~MLX4_FLAG_BONDED;
}
- spin_lock_irqsave(&priv->ctx_lock, flags);
- list_for_each_entry_safe(dev_ctx, temp_dev_ctx, &priv->ctx_list, list) {
- if (dev_ctx->intf->flags & MLX4_INTFF_BONDING) {
- list_add_tail(&dev_ctx->bond_list, &bond_list);
- list_del(&dev_ctx->list);
+ mutex_lock(&intf_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {
+ struct mlx4_adev *madev = priv->adev[i];
+ struct mlx4_adrv *madrv;
+ enum mlx4_protocol protocol;
+
+ if (!madev)
+ continue;
+
+ device_lock(&madev->adev.dev);
+ if (!madev->adev.dev.driver) {
+ device_unlock(&madev->adev.dev);
+ continue;
+ }
+
+ madrv = container_of(madev->adev.dev.driver, struct mlx4_adrv,
+ adrv.driver);
+ if (!(madrv->flags & MLX4_INTFF_BONDING)) {
+ device_unlock(&madev->adev.dev);
+ continue;
+ }
+
+ if (mlx4_is_mfunc(dev)) {
+ mlx4_dbg(dev,
+ "SRIOV, disabled HA mode for intf proto %d\n",
+ madrv->protocol);
+ device_unlock(&madev->adev.dev);
+ continue;
}
- }
- spin_unlock_irqrestore(&priv->ctx_lock, flags);
- list_for_each_entry(dev_ctx, &bond_list, bond_list) {
- dev_ctx->intf->remove(dev, dev_ctx->context);
- dev_ctx->context = dev_ctx->intf->add(dev);
+ protocol = madrv->protocol;
+ device_unlock(&madev->adev.dev);
- spin_lock_irqsave(&priv->ctx_lock, flags);
- list_add_tail(&dev_ctx->list, &priv->ctx_list);
- spin_unlock_irqrestore(&priv->ctx_lock, flags);
+ del_adev(&madev->adev);
+ priv->adev[i] = add_adev(dev, i);
+ if (IS_ERR(priv->adev[i])) {
+ mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,
+ mlx4_adev_devices[i].suffix);
+ priv->adev[i] = NULL;
+ continue;
+ }
- mlx4_dbg(dev, "Interface for protocol %d restarted with bonded mode %s\n",
- dev_ctx->intf->protocol, enable ?
- "enabled" : "disabled");
+ mlx4_dbg(dev,
+ "Interface for protocol %d restarted with bonded mode %s\n",
+ protocol, enable ? "enabled" : "disabled");
}
+
+ mutex_unlock(&intf_mutex);
+
return 0;
}
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
- unsigned long param)
+ void *param)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ atomic_notifier_call_chain(&priv->event_nh, type, param);
+}
+
+int mlx4_register_event_notifier(struct mlx4_dev *dev,
+ struct notifier_block *nb)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_device_context *dev_ctx;
- unsigned long flags;
- spin_lock_irqsave(&priv->ctx_lock, flags);
+ return atomic_notifier_chain_register(&priv->event_nh, nb);
+}
+EXPORT_SYMBOL(mlx4_register_event_notifier);
- list_for_each_entry(dev_ctx, &priv->ctx_list, list)
- if (dev_ctx->intf->event)
- dev_ctx->intf->event(dev, dev_ctx->context, type, param);
+int mlx4_unregister_event_notifier(struct mlx4_dev *dev,
+ struct notifier_block *nb)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
- spin_unlock_irqrestore(&priv->ctx_lock, flags);
+ return atomic_notifier_chain_unregister(&priv->event_nh, nb);
}
+EXPORT_SYMBOL(mlx4_unregister_event_notifier);
-int mlx4_register_device(struct mlx4_dev *dev)
+static int add_drivers(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mlx4_adev_devices); i++) {
+ bool is_supported = false;
+
+ if (priv->adev[i])
+ continue;
+
+ if (mlx4_adev_devices[i].is_supported)
+ is_supported = mlx4_adev_devices[i].is_supported(dev);
+
+ if (!is_supported)
+ continue;
+
+ priv->adev[i] = add_adev(dev, i);
+ if (IS_ERR(priv->adev[i])) {
+ mlx4_warn(dev, "Device[%d] (%s) failed to load\n", i,
+ mlx4_adev_devices[i].suffix);
+ /* We continue to rescan drivers and leave to the caller
+ * to make decision if to release everything or
+ * continue. */
+ ret = PTR_ERR(priv->adev[i]);
+ priv->adev[i] = NULL;
+ }
+ }
+ return ret;
+}
+
+static void delete_drivers(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_interface *intf;
+ bool delete_all;
+ int i;
+
+ delete_all = !(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP);
+
+ for (i = ARRAY_SIZE(mlx4_adev_devices) - 1; i >= 0; i--) {
+ bool is_supported = false;
+
+ if (!priv->adev[i])
+ continue;
+
+ if (mlx4_adev_devices[i].is_supported && !delete_all)
+ is_supported = mlx4_adev_devices[i].is_supported(dev);
+
+ if (is_supported)
+ continue;
+
+ del_adev(&priv->adev[i]->adev);
+ priv->adev[i] = NULL;
+ }
+}
+
+/* This function is used after mlx4_dev is reconfigured.
+ */
+static int rescan_drivers_locked(struct mlx4_dev *dev)
+{
+ lockdep_assert_held(&intf_mutex);
+
+ delete_drivers(dev);
+ if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))
+ return 0;
+
+ return add_drivers(dev);
+}
+
+int mlx4_register_device(struct mlx4_dev *dev)
+{
+ int ret;
mutex_lock(&intf_mutex);
dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP;
- list_add_tail(&priv->dev_list, &dev_list);
- list_for_each_entry(intf, &intf_list, list)
- mlx4_add_device(intf, priv);
+
+ ret = rescan_drivers_locked(dev);
mutex_unlock(&intf_mutex);
+
+ if (ret) {
+ mlx4_unregister_device(dev);
+ return ret;
+ }
+
mlx4_start_catas_poll(dev);
- return 0;
+ return ret;
}
void mlx4_unregister_device(struct mlx4_dev *dev)
{
- struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_interface *intf;
-
if (!(dev->persist->interface_state & MLX4_INTERFACE_STATE_UP))
return;
@@ -236,35 +374,12 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
}
mutex_lock(&intf_mutex);
- list_for_each_entry(intf, &intf_list, list)
- mlx4_remove_device(intf, priv);
-
- list_del(&priv->dev_list);
dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP;
- mutex_unlock(&intf_mutex);
-}
-
-void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port)
-{
- struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_device_context *dev_ctx;
- unsigned long flags;
- void *result = NULL;
+ rescan_drivers_locked(dev);
- spin_lock_irqsave(&priv->ctx_lock, flags);
-
- list_for_each_entry(dev_ctx, &priv->ctx_list, list)
- if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_dev) {
- result = dev_ctx->intf->get_dev(dev, dev_ctx->context, port);
- break;
- }
-
- spin_unlock_irqrestore(&priv->ctx_lock, flags);
-
- return result;
+ mutex_unlock(&intf_mutex);
}
-EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port)
{
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 61286b0d9b0c..2581226836b5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -42,7 +42,6 @@
#include <linux/slab.h>
#include <linux/io-mapping.h>
#include <linux/delay.h>
-#include <linux/kmod.h>
#include <linux/etherdevice.h>
#include <net/devlink.h>
@@ -864,7 +863,7 @@ static void mlx4_slave_destroy_special_qp_cap(struct mlx4_dev *dev)
static int mlx4_slave_special_qp_cap(struct mlx4_dev *dev)
{
- struct mlx4_func_cap *func_cap = NULL;
+ struct mlx4_func_cap *func_cap;
struct mlx4_caps *caps = &dev->caps;
int i, err = 0;
@@ -908,9 +907,9 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
{
int err;
u32 page_size;
- struct mlx4_dev_cap *dev_cap = NULL;
- struct mlx4_func_cap *func_cap = NULL;
- struct mlx4_init_hca_param *hca_param = NULL;
+ struct mlx4_dev_cap *dev_cap;
+ struct mlx4_func_cap *func_cap;
+ struct mlx4_init_hca_param *hca_param;
hca_param = kzalloc(sizeof(*hca_param), GFP_KERNEL);
func_cap = kzalloc(sizeof(*func_cap), GFP_KERNEL);
@@ -1091,27 +1090,6 @@ free_mem:
return err;
}
-static void mlx4_request_modules(struct mlx4_dev *dev)
-{
- int port;
- int has_ib_port = false;
- int has_eth_port = false;
-#define EN_DRV_NAME "mlx4_en"
-#define IB_DRV_NAME "mlx4_ib"
-
- for (port = 1; port <= dev->caps.num_ports; port++) {
- if (dev->caps.port_type[port] == MLX4_PORT_TYPE_IB)
- has_ib_port = true;
- else if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
- has_eth_port = true;
- }
-
- if (has_eth_port)
- request_module_nowait(EN_DRV_NAME);
- if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
- request_module_nowait(IB_DRV_NAME);
-}
-
/*
* Change the port configuration of the device.
* Every user of this function must hold the port mutex.
@@ -1147,7 +1125,6 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
mlx4_err(dev, "Failed to register device\n");
goto out;
}
- mlx4_request_modules(dev);
}
out:
@@ -1441,7 +1418,7 @@ static int mlx4_mf_unbond(struct mlx4_dev *dev)
return ret;
}
-int mlx4_bond(struct mlx4_dev *dev)
+static int mlx4_bond(struct mlx4_dev *dev)
{
int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -1467,9 +1444,8 @@ int mlx4_bond(struct mlx4_dev *dev)
return ret;
}
-EXPORT_SYMBOL_GPL(mlx4_bond);
-int mlx4_unbond(struct mlx4_dev *dev)
+static int mlx4_unbond(struct mlx4_dev *dev)
{
int ret = 0;
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -1496,10 +1472,8 @@ int mlx4_unbond(struct mlx4_dev *dev)
return ret;
}
-EXPORT_SYMBOL_GPL(mlx4_unbond);
-
-int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
+static int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
{
u8 port1 = v2p->port1;
u8 port2 = v2p->port2;
@@ -1541,7 +1515,61 @@ int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
mutex_unlock(&priv->bond_mutex);
return err;
}
-EXPORT_SYMBOL_GPL(mlx4_port_map_set);
+
+struct mlx4_bond {
+ struct work_struct work;
+ struct mlx4_dev *dev;
+ int is_bonded;
+ struct mlx4_port_map port_map;
+};
+
+static void mlx4_bond_work(struct work_struct *work)
+{
+ struct mlx4_bond *bond = container_of(work, struct mlx4_bond, work);
+ int err = 0;
+
+ if (bond->is_bonded) {
+ if (!mlx4_is_bonded(bond->dev)) {
+ err = mlx4_bond(bond->dev);
+ if (err)
+ mlx4_err(bond->dev, "Fail to bond device\n");
+ }
+ if (!err) {
+ err = mlx4_port_map_set(bond->dev, &bond->port_map);
+ if (err)
+ mlx4_err(bond->dev,
+ "Fail to set port map [%d][%d]: %d\n",
+ bond->port_map.port1,
+ bond->port_map.port2, err);
+ }
+ } else if (mlx4_is_bonded(bond->dev)) {
+ err = mlx4_unbond(bond->dev);
+ if (err)
+ mlx4_err(bond->dev, "Fail to unbond device\n");
+ }
+ put_device(&bond->dev->persist->pdev->dev);
+ kfree(bond);
+}
+
+int mlx4_queue_bond_work(struct mlx4_dev *dev, int is_bonded, u8 v2p_p1,
+ u8 v2p_p2)
+{
+ struct mlx4_bond *bond;
+
+ bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
+ if (!bond)
+ return -ENOMEM;
+
+ INIT_WORK(&bond->work, mlx4_bond_work);
+ get_device(&dev->persist->pdev->dev);
+ bond->dev = dev;
+ bond->is_bonded = is_bonded;
+ bond->port_map.port1 = v2p_p1;
+ bond->port_map.port2 = v2p_p2;
+ queue_work(mlx4_wq, &bond->work);
+ return 0;
+}
+EXPORT_SYMBOL(mlx4_queue_bond_work);
static int mlx4_load_fw(struct mlx4_dev *dev)
{
@@ -3375,8 +3403,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
devl_assert_locked(devlink);
dev = &priv->dev;
- INIT_LIST_HEAD(&priv->ctx_list);
- spin_lock_init(&priv->ctx_lock);
+ err = mlx4_adev_init(dev);
+ if (err)
+ return err;
+
+ ATOMIC_INIT_NOTIFIER_HEAD(&priv->event_nh);
mutex_init(&priv->port_mutex);
mutex_init(&priv->bond_mutex);
@@ -3402,10 +3433,11 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
err = mlx4_get_ownership(dev);
if (err) {
if (err < 0)
- return err;
+ goto err_adev;
else {
mlx4_warn(dev, "Multiple PFs not yet supported - Skipping PF\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto err_adev;
}
}
@@ -3674,8 +3706,6 @@ slave_start:
if (err)
goto err_port;
- mlx4_request_modules(dev);
-
mlx4_sense_init(dev);
mlx4_start_sense(dev);
@@ -3753,6 +3783,9 @@ err_sriov:
mlx4_free_ownership(dev);
kfree(dev_cap);
+
+err_adev:
+ mlx4_adev_cleanup(dev);
return err;
}
@@ -4133,6 +4166,8 @@ static void mlx4_unload_one(struct pci_dev *pdev)
mlx4_slave_destroy_special_qp_cap(dev);
kfree(dev->dev_vfs);
+ mlx4_adev_cleanup(dev);
+
mlx4_clean_dev(dev);
priv->pci_dev_data = pci_dev_data;
priv->removed = 1;
@@ -4520,6 +4555,9 @@ static int __init mlx4_init(void)
{
int ret;
+ WARN_ONCE(strcmp(MLX4_ADEV_NAME, KBUILD_MODNAME),
+ "mlx4_core name not in sync with kernel module name");
+
if (mlx4_verify_params())
return -EINVAL;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index f1716a83a4d3..24d0c7c46878 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -294,7 +294,7 @@ static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
struct mlx4_promisc_qp *dqp, *tmp_dqp;
if (port < 1 || port > dev->caps.num_ports)
- return NULL;
+ return false;
s_steer = &mlx4_priv(dev)->steer[port - 1];
@@ -375,7 +375,7 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
bool ret = false;
if (port < 1 || port > dev->caps.num_ports)
- return NULL;
+ return false;
s_steer = &mlx4_priv(dev)->steer[port - 1];
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 6ccf340660d9..d7d856d1758a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -47,6 +47,8 @@
#include <linux/spinlock.h>
#include <net/devlink.h>
#include <linux/rwsem.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/notifier.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h>
@@ -862,6 +864,11 @@ struct mlx4_steer {
struct list_head steer_entries[MLX4_NUM_STEERS];
};
+struct mlx4_port_map {
+ u8 port1;
+ u8 port2;
+};
+
enum {
MLX4_PCI_DEV_IS_VF = 1 << 0,
MLX4_PCI_DEV_FORCE_SENSE_PORT = 1 << 1,
@@ -875,9 +882,9 @@ enum {
struct mlx4_priv {
struct mlx4_dev dev;
- struct list_head dev_list;
- struct list_head ctx_list;
- spinlock_t ctx_lock;
+ struct mlx4_adev **adev;
+ int adev_idx;
+ struct atomic_notifier_head event_nh;
int pci_dev_data;
int removed;
@@ -1045,10 +1052,13 @@ void mlx4_catas_end(struct mlx4_dev *dev);
int mlx4_crdump_init(struct mlx4_dev *dev);
void mlx4_crdump_end(struct mlx4_dev *dev);
int mlx4_restart_one(struct pci_dev *pdev);
+
+int mlx4_adev_init(struct mlx4_dev *dev);
+void mlx4_adev_cleanup(struct mlx4_dev *dev);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
- unsigned long param);
+ void *param);
struct mlx4_dev_cap;
struct mlx4_init_hca_param;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 321f801c1d7c..efe3f97b874f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -49,6 +49,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/irq.h>
#include <net/xdp.h>
+#include <linux/notifier.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/qp.h>
@@ -432,7 +433,8 @@ struct mlx4_en_dev {
unsigned long last_overflow_check;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
- struct notifier_block nb;
+ struct notifier_block netdev_nb;
+ struct notifier_block mlx_nb;
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index bb1d7b039a7e..c4f4de82e29e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -12,6 +12,7 @@ config MLX5_CORE
depends on MLXFW || !MLXFW
depends on PTP_1588_CLOCK_OPTIONAL
depends on PCI_HYPERV_INTERFACE || !PCI_HYPERV_INTERFACE
+ depends on HWMON || !HWMON
help
Core driver for low level functionality of the ConnectX-4 and
Connect-IB cards by Mellanox Technologies.
@@ -139,7 +140,7 @@ config MLX5_CORE_IPOIB
help
MLX5 IPoIB offloads & acceleration support.
-config MLX5_EN_MACSEC
+config MLX5_MACSEC
bool "Connect-X support for MACSec offload"
depends on MLX5_CORE_EN
depends on MACSEC
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 35f00700a4d6..7e94caca4888 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -69,16 +69,20 @@ mlx5_core-$(CONFIG_MLX5_TC_SAMPLE) += en/tc/sample.o
#
mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o eswitch_offloads_termtbl.o \
ecpf.o rdma.o esw/legacy.o \
- esw/devlink_port.o esw/vporttbl.o esw/qos.o
+ esw/devlink_port.o esw/vporttbl.o esw/qos.o esw/ipsec.o
mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \
esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o
+ifneq ($(CONFIG_MLX5_EN_IPSEC),)
+ mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/ipsec_fs.o
+endif
+
mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \
en/rep/bridge.o
-mlx5_core-$(CONFIG_THERMAL) += thermal.o
+mlx5_core-$(CONFIG_HWMON) += hwmon.o
mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
mlx5_core-$(CONFIG_VXLAN) += lib/vxlan.o
mlx5_core-$(CONFIG_PTP_1588_CLOCK) += lib/clock.o
@@ -94,7 +98,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib
#
mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o
-mlx5_core-$(CONFIG_MLX5_EN_MACSEC) += en_accel/macsec.o en_accel/macsec_fs.o \
+mlx5_core-$(CONFIG_MLX5_MACSEC) += en_accel/macsec.o lib/macsec_fs.o \
en_accel/macsec_stats.o
mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index d532883b42d7..afb348579577 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -162,18 +162,18 @@ static int cmd_alloc_index(struct mlx5_cmd *cmd)
int ret;
spin_lock_irqsave(&cmd->alloc_lock, flags);
- ret = find_first_bit(&cmd->bitmask, cmd->max_reg_cmds);
- if (ret < cmd->max_reg_cmds)
- clear_bit(ret, &cmd->bitmask);
+ ret = find_first_bit(&cmd->vars.bitmask, cmd->vars.max_reg_cmds);
+ if (ret < cmd->vars.max_reg_cmds)
+ clear_bit(ret, &cmd->vars.bitmask);
spin_unlock_irqrestore(&cmd->alloc_lock, flags);
- return ret < cmd->max_reg_cmds ? ret : -ENOMEM;
+ return ret < cmd->vars.max_reg_cmds ? ret : -ENOMEM;
}
static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
{
lockdep_assert_held(&cmd->alloc_lock);
- set_bit(idx, &cmd->bitmask);
+ set_bit(idx, &cmd->vars.bitmask);
}
static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
@@ -192,7 +192,7 @@ static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
if (ent->idx >= 0) {
cmd_free_index(cmd, ent->idx);
- up(ent->page_queue ? &cmd->pages_sem : &cmd->sem);
+ up(ent->page_queue ? &cmd->vars.pages_sem : &cmd->vars.sem);
}
cmd_free_ent(ent);
@@ -202,7 +202,7 @@ out:
static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
{
- return cmd->cmd_buf + (idx << cmd->log_stride);
+ return cmd->cmd_buf + (idx << cmd->vars.log_stride);
}
static int mlx5_calc_cmd_blocks(struct mlx5_cmd_msg *msg)
@@ -974,7 +974,7 @@ static void cmd_work_handler(struct work_struct *work)
cb_timeout = msecs_to_jiffies(mlx5_tout_ms(dev, CMD));
complete(&ent->handling);
- sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
+ sem = ent->page_queue ? &cmd->vars.pages_sem : &cmd->vars.sem;
down(sem);
if (!ent->page_queue) {
alloc_ret = cmd_alloc_index(cmd);
@@ -994,9 +994,9 @@ static void cmd_work_handler(struct work_struct *work)
}
ent->idx = alloc_ret;
} else {
- ent->idx = cmd->max_reg_cmds;
+ ent->idx = cmd->vars.max_reg_cmds;
spin_lock_irqsave(&cmd->alloc_lock, flags);
- clear_bit(ent->idx, &cmd->bitmask);
+ clear_bit(ent->idx, &cmd->vars.bitmask);
spin_unlock_irqrestore(&cmd->alloc_lock, flags);
}
@@ -1225,8 +1225,8 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
goto out_free;
ds = ent->ts2 - ent->ts1;
- if (ent->op < MLX5_CMD_OP_MAX) {
- stats = &cmd->stats[ent->op];
+ stats = xa_load(&cmd->stats, ent->op);
+ if (stats) {
spin_lock_irq(&stats->lock);
stats->sum += ds;
++stats->n;
@@ -1548,7 +1548,6 @@ static void clean_debug_files(struct mlx5_core_dev *dev)
if (!mlx5_debugfs_root)
return;
- mlx5_cmdif_debugfs_cleanup(dev);
debugfs_remove_recursive(dbg->dbg_root);
}
@@ -1563,8 +1562,6 @@ static void create_debugfs_files(struct mlx5_core_dev *dev)
debugfs_create_file("out_len", 0600, dbg->dbg_root, dev, &olfops);
debugfs_create_u8("status", 0600, dbg->dbg_root, &dbg->status);
debugfs_create_file("run", 0200, dbg->dbg_root, dev, &fops);
-
- mlx5_cmdif_debugfs_init(dev);
}
void mlx5_cmd_allowed_opcode(struct mlx5_core_dev *dev, u16 opcode)
@@ -1572,15 +1569,15 @@ void mlx5_cmd_allowed_opcode(struct mlx5_core_dev *dev, u16 opcode)
struct mlx5_cmd *cmd = &dev->cmd;
int i;
- for (i = 0; i < cmd->max_reg_cmds; i++)
- down(&cmd->sem);
- down(&cmd->pages_sem);
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++)
+ down(&cmd->vars.sem);
+ down(&cmd->vars.pages_sem);
cmd->allowed_opcode = opcode;
- up(&cmd->pages_sem);
- for (i = 0; i < cmd->max_reg_cmds; i++)
- up(&cmd->sem);
+ up(&cmd->vars.pages_sem);
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++)
+ up(&cmd->vars.sem);
}
static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
@@ -1588,15 +1585,15 @@ static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
struct mlx5_cmd *cmd = &dev->cmd;
int i;
- for (i = 0; i < cmd->max_reg_cmds; i++)
- down(&cmd->sem);
- down(&cmd->pages_sem);
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++)
+ down(&cmd->vars.sem);
+ down(&cmd->vars.pages_sem);
cmd->mode = mode;
- up(&cmd->pages_sem);
- for (i = 0; i < cmd->max_reg_cmds; i++)
- up(&cmd->sem);
+ up(&cmd->vars.pages_sem);
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++)
+ up(&cmd->vars.sem);
}
static int cmd_comp_notifier(struct notifier_block *nb,
@@ -1655,7 +1652,7 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
/* there can be at most 32 command queues */
vector = vec & 0xffffffff;
- for (i = 0; i < (1 << cmd->log_sz); i++) {
+ for (i = 0; i < (1 << cmd->vars.log_sz); i++) {
if (test_bit(i, &vector)) {
ent = cmd->ent_arr[i];
@@ -1698,8 +1695,8 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
if (ent->callback) {
ds = ent->ts2 - ent->ts1;
- if (ent->op < MLX5_CMD_OP_MAX) {
- stats = &cmd->stats[ent->op];
+ stats = xa_load(&cmd->stats, ent->op);
+ if (stats) {
spin_lock_irqsave(&stats->lock, flags);
stats->sum += ds;
++stats->n;
@@ -1744,7 +1741,7 @@ static void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
/* wait for pending handlers to complete */
mlx5_eq_synchronize_cmd_irq(dev);
spin_lock_irqsave(&dev->cmd.alloc_lock, flags);
- vector = ~dev->cmd.bitmask & ((1ul << (1 << dev->cmd.log_sz)) - 1);
+ vector = ~dev->cmd.vars.bitmask & ((1ul << (1 << dev->cmd.vars.log_sz)) - 1);
if (!vector)
goto no_trig;
@@ -1753,14 +1750,14 @@ static void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
* to guarantee pending commands will not get freed in the meanwhile.
* For that reason, it also has to be done inside the alloc_lock.
*/
- for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+ for_each_set_bit(i, &bitmask, (1 << cmd->vars.log_sz))
cmd_ent_get(cmd->ent_arr[i]);
vector |= MLX5_TRIGGERED_CMD_COMP;
spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
mlx5_cmd_comp_handler(dev, vector, true);
- for_each_set_bit(i, &bitmask, (1 << cmd->log_sz))
+ for_each_set_bit(i, &bitmask, (1 << cmd->vars.log_sz))
cmd_ent_put(cmd->ent_arr[i]);
return;
@@ -1773,22 +1770,22 @@ void mlx5_cmd_flush(struct mlx5_core_dev *dev)
struct mlx5_cmd *cmd = &dev->cmd;
int i;
- for (i = 0; i < cmd->max_reg_cmds; i++) {
- while (down_trylock(&cmd->sem)) {
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++) {
+ while (down_trylock(&cmd->vars.sem)) {
mlx5_cmd_trigger_completions(dev);
cond_resched();
}
}
- while (down_trylock(&cmd->pages_sem)) {
+ while (down_trylock(&cmd->vars.pages_sem)) {
mlx5_cmd_trigger_completions(dev);
cond_resched();
}
/* Unlock cmdif */
- up(&cmd->pages_sem);
- for (i = 0; i < cmd->max_reg_cmds; i++)
- up(&cmd->sem);
+ up(&cmd->vars.pages_sem);
+ for (i = 0; i < cmd->vars.max_reg_cmds; i++)
+ up(&cmd->vars.sem);
}
static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
@@ -1858,7 +1855,7 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
/* atomic context may not sleep */
if (callback)
return -EINVAL;
- down(&dev->cmd.throttle_sem);
+ down(&dev->cmd.vars.throttle_sem);
}
pages_queue = is_manage_pages(in);
@@ -1903,7 +1900,7 @@ out_in:
free_msg(dev, inb);
out_up:
if (throttle_op)
- up(&dev->cmd.throttle_sem);
+ up(&dev->cmd.vars.throttle_sem);
return err;
}
@@ -1926,7 +1923,9 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
if (!err || !(strcmp(namep, "unknown command opcode")))
return;
- stats = &dev->cmd.stats[opcode];
+ stats = xa_load(&dev->cmd.stats, opcode);
+ if (!stats)
+ return;
spin_lock_irq(&stats->lock);
stats->failed++;
if (err < 0)
@@ -2190,19 +2189,8 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
int size = sizeof(struct mlx5_cmd_prot_block);
int align = roundup_pow_of_two(size);
struct mlx5_cmd *cmd = &dev->cmd;
- u32 cmd_h, cmd_l;
- u16 cmd_if_rev;
+ u32 cmd_l;
int err;
- int i;
-
- memset(cmd, 0, sizeof(*cmd));
- cmd_if_rev = cmdif_rev(dev);
- if (cmd_if_rev != CMD_IF_REV) {
- mlx5_core_err(dev,
- "Driver cmdif rev(%d) differs from firmware's(%d)\n",
- CMD_IF_REV, cmd_if_rev);
- return -EINVAL;
- }
cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
if (!cmd->pool)
@@ -2212,62 +2200,16 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
if (err)
goto err_free_pool;
- cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff;
- cmd->log_sz = cmd_l >> 4 & 0xf;
- cmd->log_stride = cmd_l & 0xf;
- if (1 << cmd->log_sz > MLX5_MAX_COMMANDS) {
- mlx5_core_err(dev, "firmware reports too many outstanding commands %d\n",
- 1 << cmd->log_sz);
- err = -EINVAL;
- goto err_free_page;
- }
-
- if (cmd->log_sz + cmd->log_stride > MLX5_ADAPTER_PAGE_SHIFT) {
- mlx5_core_err(dev, "command queue size overflow\n");
- err = -EINVAL;
- goto err_free_page;
- }
-
- cmd->state = MLX5_CMDIF_STATE_DOWN;
- cmd->checksum_disabled = 1;
- cmd->max_reg_cmds = (1 << cmd->log_sz) - 1;
- cmd->bitmask = (1UL << cmd->max_reg_cmds) - 1;
-
- cmd->cmdif_rev = ioread32be(&dev->iseg->cmdif_rev_fw_sub) >> 16;
- if (cmd->cmdif_rev > CMD_IF_REV) {
- mlx5_core_err(dev, "driver does not support command interface version. driver %d, firmware %d\n",
- CMD_IF_REV, cmd->cmdif_rev);
- err = -EOPNOTSUPP;
- goto err_free_page;
- }
-
- spin_lock_init(&cmd->alloc_lock);
- spin_lock_init(&cmd->token_lock);
- for (i = 0; i < MLX5_CMD_OP_MAX; i++)
- spin_lock_init(&cmd->stats[i].lock);
-
- sema_init(&cmd->sem, cmd->max_reg_cmds);
- sema_init(&cmd->pages_sem, 1);
- sema_init(&cmd->throttle_sem, DIV_ROUND_UP(cmd->max_reg_cmds, 2));
-
- cmd_h = (u32)((u64)(cmd->dma) >> 32);
cmd_l = (u32)(cmd->dma);
if (cmd_l & 0xfff) {
mlx5_core_err(dev, "invalid command queue address\n");
err = -ENOMEM;
- goto err_free_page;
+ goto err_cmd_page;
}
+ cmd->checksum_disabled = 1;
- iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h);
- iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz);
-
- /* Make sure firmware sees the complete address before we proceed */
- wmb();
-
- mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
-
- cmd->mode = CMD_MODE_POLLING;
- cmd->allowed_opcode = CMD_ALLOWED_OPCODE_ALL;
+ spin_lock_init(&cmd->alloc_lock);
+ spin_lock_init(&cmd->token_lock);
create_msg_cache(dev);
@@ -2279,16 +2221,14 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
goto err_cache;
}
- create_debugfs_files(dev);
+ mlx5_cmdif_debugfs_init(dev);
return 0;
err_cache:
destroy_msg_cache(dev);
-
-err_free_page:
+err_cmd_page:
free_cmd_page(dev, cmd);
-
err_free_pool:
dma_pool_destroy(cmd->pool);
return err;
@@ -2298,13 +2238,78 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
{
struct mlx5_cmd *cmd = &dev->cmd;
- clean_debug_files(dev);
+ mlx5_cmdif_debugfs_cleanup(dev);
destroy_workqueue(cmd->wq);
destroy_msg_cache(dev);
free_cmd_page(dev, cmd);
dma_pool_destroy(cmd->pool);
}
+int mlx5_cmd_enable(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+ u32 cmd_h, cmd_l;
+
+ memset(&cmd->vars, 0, sizeof(cmd->vars));
+ cmd->vars.cmdif_rev = cmdif_rev(dev);
+ if (cmd->vars.cmdif_rev != CMD_IF_REV) {
+ mlx5_core_err(dev,
+ "Driver cmdif rev(%d) differs from firmware's(%d)\n",
+ CMD_IF_REV, cmd->vars.cmdif_rev);
+ return -EINVAL;
+ }
+
+ cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff;
+ cmd->vars.log_sz = cmd_l >> 4 & 0xf;
+ cmd->vars.log_stride = cmd_l & 0xf;
+ if (1 << cmd->vars.log_sz > MLX5_MAX_COMMANDS) {
+ mlx5_core_err(dev, "firmware reports too many outstanding commands %d\n",
+ 1 << cmd->vars.log_sz);
+ return -EINVAL;
+ }
+
+ if (cmd->vars.log_sz + cmd->vars.log_stride > MLX5_ADAPTER_PAGE_SHIFT) {
+ mlx5_core_err(dev, "command queue size overflow\n");
+ return -EINVAL;
+ }
+
+ cmd->state = MLX5_CMDIF_STATE_DOWN;
+ cmd->vars.max_reg_cmds = (1 << cmd->vars.log_sz) - 1;
+ cmd->vars.bitmask = (1UL << cmd->vars.max_reg_cmds) - 1;
+
+ sema_init(&cmd->vars.sem, cmd->vars.max_reg_cmds);
+ sema_init(&cmd->vars.pages_sem, 1);
+ sema_init(&cmd->vars.throttle_sem, DIV_ROUND_UP(cmd->vars.max_reg_cmds, 2));
+
+ cmd_h = (u32)((u64)(cmd->dma) >> 32);
+ cmd_l = (u32)(cmd->dma);
+ if (WARN_ON(cmd_l & 0xfff))
+ return -EINVAL;
+
+ iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h);
+ iowrite32be(cmd_l, &dev->iseg->cmdq_addr_l_sz);
+
+ /* Make sure firmware sees the complete address before we proceed */
+ wmb();
+
+ mlx5_core_dbg(dev, "descriptor at dma 0x%llx\n", (unsigned long long)(cmd->dma));
+
+ cmd->mode = CMD_MODE_POLLING;
+ cmd->allowed_opcode = CMD_ALLOWED_OPCODE_ALL;
+
+ create_debugfs_files(dev);
+
+ return 0;
+}
+
+void mlx5_cmd_disable(struct mlx5_core_dev *dev)
+{
+ struct mlx5_cmd *cmd = &dev->cmd;
+
+ clean_debug_files(dev);
+ flush_workqueue(cmd->wq);
+}
+
void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
enum mlx5_cmdif_state cmdif_state)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
index 2138f28a2931..09652dc89115 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
@@ -176,8 +176,8 @@ static ssize_t slots_read(struct file *filp, char __user *buf, size_t count,
int ret;
cmd = filp->private_data;
- weight = bitmap_weight(&cmd->bitmask, cmd->max_reg_cmds);
- field = cmd->max_reg_cmds - weight;
+ weight = bitmap_weight(&cmd->vars.bitmask, cmd->vars.max_reg_cmds);
+ field = cmd->vars.max_reg_cmds - weight;
ret = snprintf(tbuf, sizeof(tbuf), "%d\n", field);
return simple_read_from_buffer(buf, count, pos, tbuf, ret);
}
@@ -188,6 +188,24 @@ static const struct file_operations slots_fops = {
.read = slots_read,
};
+static struct mlx5_cmd_stats *
+mlx5_cmdif_alloc_stats(struct xarray *stats_xa, int opcode)
+{
+ struct mlx5_cmd_stats *stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ int err;
+
+ if (!stats)
+ return NULL;
+
+ err = xa_insert(stats_xa, opcode, stats, GFP_KERNEL);
+ if (err) {
+ kfree(stats);
+ return NULL;
+ }
+ spin_lock_init(&stats->lock);
+ return stats;
+}
+
void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
{
struct mlx5_cmd_stats *stats;
@@ -200,10 +218,14 @@ void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
debugfs_create_file("slots_inuse", 0400, *cmd, &dev->cmd, &slots_fops);
+ xa_init(&dev->cmd.stats);
+
for (i = 0; i < MLX5_CMD_OP_MAX; i++) {
- stats = &dev->cmd.stats[i];
namep = mlx5_command_str(i);
if (strcmp(namep, "unknown command opcode")) {
+ stats = mlx5_cmdif_alloc_stats(&dev->cmd.stats, i);
+ if (!stats)
+ continue;
stats->root = debugfs_create_dir(namep, *cmd);
debugfs_create_file("average", 0400, stats->root, stats,
@@ -224,7 +246,13 @@ void mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev)
void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev)
{
+ struct mlx5_cmd_stats *stats;
+ unsigned long i;
+
debugfs_remove_recursive(dev->priv.dbg.cmdif_debugfs);
+ xa_for_each(&dev->cmd.stats, i, stats)
+ kfree(stats);
+ xa_destroy(&dev->cmd.stats);
}
void mlx5_cq_debugfs_init(struct mlx5_core_dev *dev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
index edb06fb9bbc5..7909f378dc93 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
@@ -36,6 +36,7 @@
#include <linux/mlx5/vport.h>
#include "mlx5_core.h"
#include "devlink.h"
+#include "lag/lag.h"
/* intf dev list mutex */
static DEFINE_MUTEX(mlx5_intf_mutex);
@@ -587,10 +588,7 @@ static int next_phys_dev_lag(struct device *dev, const void *data)
if (!mdev)
return 0;
- if (!MLX5_CAP_GEN(mdev, vport_group_manager) ||
- !MLX5_CAP_GEN(mdev, lag_master) ||
- (MLX5_CAP_GEN(mdev, num_lag_ports) > MLX5_MAX_PORTS ||
- MLX5_CAP_GEN(mdev, num_lag_ports) <= 1))
+ if (!mlx5_lag_is_supported(mdev))
return 0;
return _next_phys_dev(mdev, data);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 3d82ec890666..af8460bb257b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -212,6 +212,9 @@ static int mlx5_devlink_reload_up(struct devlink *devlink, enum devlink_reload_a
/* On fw_activate action, also driver is reloaded and reinit performed */
*actions_performed |= BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
ret = mlx5_load_one_devl_locked(dev, true);
+ if (ret)
+ return ret;
+ ret = mlx5_fw_reset_verify_fw_complete(dev, extack);
break;
default:
/* Unsupported action should not get to this function */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
index defba5bd91d9..961f75da6227 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.h
@@ -6,6 +6,14 @@
#include <net/devlink.h>
+enum mlx5_devlink_resource_id {
+ MLX5_DL_RES_MAX_LOCAL_SFS = 1,
+ MLX5_DL_RES_MAX_EXTERNAL_SFS,
+
+ __MLX5_ID_RES_MAX,
+ MLX5_ID_RES_MAX = __MLX5_ID_RES_MAX - 1,
+};
+
enum mlx5_devlink_param_id {
MLX5_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index b1807bfb815f..86f2690c5e01 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -193,7 +193,7 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
{
return is_kdump_kernel() ?
MLX5E_MIN_NUM_CHANNELS :
- min_t(int, mlx5_comp_vectors_count(mdev), MLX5E_MAX_NUM_CHANNELS);
+ min_t(int, mlx5_comp_vectors_max(mdev), MLX5E_MAX_NUM_CHANNELS);
}
/* The maximum WQE size can be retrieved by max_wqe_sz_sq in
@@ -917,7 +917,7 @@ struct mlx5e_priv {
const struct mlx5e_profile *profile;
void *ppriv;
-#ifdef CONFIG_MLX5_EN_MACSEC
+#ifdef CONFIG_MLX5_MACSEC
struct mlx5e_macsec *macsec;
#endif
#ifdef CONFIG_MLX5_EN_IPSEC
@@ -1167,9 +1167,6 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc);
int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
const u8 hfunc);
-int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
- u32 *rule_locs);
-int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/health.h b/drivers/net/ethernet/mellanox/mlx5/core/en/health.h
index 0107e4e73bb0..415840c3ef84 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/health.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/health.h
@@ -18,6 +18,7 @@ void mlx5e_reporter_tx_create(struct mlx5e_priv *priv);
void mlx5e_reporter_tx_destroy(struct mlx5e_priv *priv);
void mlx5e_reporter_tx_err_cqe(struct mlx5e_txqsq *sq);
int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq);
+void mlx5e_reporter_tx_ptpsq_unhealthy(struct mlx5e_ptpsq *ptpsq);
int mlx5e_health_cq_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg);
int mlx5e_health_cq_common_diag_fmsg(struct mlx5e_cq *cq, struct devlink_fmsg *fmsg);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
index 5ce28ff7685f..e097f336e1c4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
@@ -6,6 +6,7 @@
#include "en/port.h"
#include "en_accel/en_accel.h"
#include "en_accel/ipsec.h"
+#include <net/page_pool/types.h>
#include <net/xdp_sock_drv.h>
static u8 mlx5e_mpwrq_min_page_shift(struct mlx5_core_dev *mdev)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
index b0b429a0321e..bb11e644d24f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
@@ -2,9 +2,12 @@
// Copyright (c) 2020 Mellanox Technologies
#include "en/ptp.h"
+#include "en/health.h"
#include "en/txrx.h"
#include "en/params.h"
#include "en/fs_tt_redirect.h"
+#include <linux/list.h>
+#include <linux/spinlock.h>
struct mlx5e_ptp_fs {
struct mlx5_flow_handle *l2_rule;
@@ -19,6 +22,48 @@ struct mlx5e_ptp_params {
struct mlx5e_rq_param rq_param;
};
+struct mlx5e_ptp_port_ts_cqe_tracker {
+ u8 metadata_id;
+ bool inuse : 1;
+ struct list_head entry;
+};
+
+struct mlx5e_ptp_port_ts_cqe_list {
+ struct mlx5e_ptp_port_ts_cqe_tracker *nodes;
+ struct list_head tracker_list_head;
+ /* Sync list operations in xmit and napi_poll contexts */
+ spinlock_t tracker_list_lock;
+};
+
+static inline void
+mlx5e_ptp_port_ts_cqe_list_add(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metadata)
+{
+ struct mlx5e_ptp_port_ts_cqe_tracker *tracker = &list->nodes[metadata];
+
+ WARN_ON_ONCE(tracker->inuse);
+ tracker->inuse = true;
+ spin_lock(&list->tracker_list_lock);
+ list_add_tail(&tracker->entry, &list->tracker_list_head);
+ spin_unlock(&list->tracker_list_lock);
+}
+
+static void
+mlx5e_ptp_port_ts_cqe_list_remove(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metadata)
+{
+ struct mlx5e_ptp_port_ts_cqe_tracker *tracker = &list->nodes[metadata];
+
+ WARN_ON_ONCE(!tracker->inuse);
+ tracker->inuse = false;
+ spin_lock(&list->tracker_list_lock);
+ list_del(&tracker->entry);
+ spin_unlock(&list->tracker_list_lock);
+}
+
+void mlx5e_ptpsq_track_metadata(struct mlx5e_ptpsq *ptpsq, u8 metadata)
+{
+ mlx5e_ptp_port_ts_cqe_list_add(ptpsq->ts_cqe_pending_list, metadata);
+}
+
struct mlx5e_skb_cb_hwtstamp {
ktime_t cqe_hwtstamp;
ktime_t port_hwtstamp;
@@ -79,75 +124,97 @@ void mlx5e_skb_cb_hwtstamp_handler(struct sk_buff *skb, int hwtstamp_type,
memset(skb->cb, 0, sizeof(struct mlx5e_skb_cb_hwtstamp));
}
-#define PTP_WQE_CTR2IDX(val) ((val) & ptpsq->ts_cqe_ctr_mask)
-
-static bool mlx5e_ptp_ts_cqe_drop(struct mlx5e_ptpsq *ptpsq, u16 skb_ci, u16 skb_id)
+static struct sk_buff *
+mlx5e_ptp_metadata_map_lookup(struct mlx5e_ptp_metadata_map *map, u16 metadata)
{
- return (ptpsq->ts_cqe_ctr_mask && (skb_ci != skb_id));
+ return map->data[metadata];
}
-static bool mlx5e_ptp_ts_cqe_ooo(struct mlx5e_ptpsq *ptpsq, u16 skb_id)
+static struct sk_buff *
+mlx5e_ptp_metadata_map_remove(struct mlx5e_ptp_metadata_map *map, u16 metadata)
{
- u16 skb_ci = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc);
- u16 skb_pi = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_pc);
+ struct sk_buff *skb;
- if (PTP_WQE_CTR2IDX(skb_id - skb_ci) >= PTP_WQE_CTR2IDX(skb_pi - skb_ci))
- return true;
+ skb = map->data[metadata];
+ map->data[metadata] = NULL;
- return false;
+ return skb;
}
-static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_ci,
- u16 skb_id, int budget)
+static bool mlx5e_ptp_metadata_map_unhealthy(struct mlx5e_ptp_metadata_map *map)
{
- struct skb_shared_hwtstamps hwts = {};
- struct sk_buff *skb;
+ /* Considered beginning unhealthy state if size * 15 / 2^4 cannot be reclaimed. */
+ return map->undelivered_counter > (map->capacity >> 4) * 15;
+}
- ptpsq->cq_stats->resync_event++;
+static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq,
+ ktime_t port_tstamp)
+{
+ struct mlx5e_ptp_port_ts_cqe_list *cqe_list = ptpsq->ts_cqe_pending_list;
+ ktime_t timeout = ns_to_ktime(MLX5E_PTP_TS_CQE_UNDELIVERED_TIMEOUT);
+ struct mlx5e_ptp_metadata_map *metadata_map = &ptpsq->metadata_map;
+ struct mlx5e_ptp_port_ts_cqe_tracker *pos, *n;
+
+ spin_lock(&cqe_list->tracker_list_lock);
+ list_for_each_entry_safe(pos, n, &cqe_list->tracker_list_head, entry) {
+ struct sk_buff *skb =
+ mlx5e_ptp_metadata_map_lookup(metadata_map, pos->metadata_id);
+ ktime_t dma_tstamp = mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp;
+
+ if (!dma_tstamp ||
+ ktime_after(ktime_add(dma_tstamp, timeout), port_tstamp))
+ break;
- while (skb_ci != skb_id) {
- skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
- hwts.hwtstamp = mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp;
- skb_tstamp_tx(skb, &hwts);
- ptpsq->cq_stats->resync_cqe++;
- napi_consume_skb(skb, budget);
- skb_ci = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc);
+ metadata_map->undelivered_counter++;
+ WARN_ON_ONCE(!pos->inuse);
+ pos->inuse = false;
+ list_del(&pos->entry);
}
+ spin_unlock(&cqe_list->tracker_list_lock);
}
+#define PTP_WQE_CTR2IDX(val) ((val) & ptpsq->ts_cqe_ctr_mask)
+
static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,
struct mlx5_cqe64 *cqe,
int budget)
{
- u16 skb_id = PTP_WQE_CTR2IDX(be16_to_cpu(cqe->wqe_counter));
- u16 skb_ci = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc);
+ struct mlx5e_ptp_port_ts_cqe_list *pending_cqe_list = ptpsq->ts_cqe_pending_list;
+ u8 metadata_id = PTP_WQE_CTR2IDX(be16_to_cpu(cqe->wqe_counter));
+ bool is_err_cqe = !!MLX5E_RX_ERR_CQE(cqe);
struct mlx5e_txqsq *sq = &ptpsq->txqsq;
struct sk_buff *skb;
ktime_t hwtstamp;
- if (unlikely(MLX5E_RX_ERR_CQE(cqe))) {
- skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
- ptpsq->cq_stats->err_cqe++;
- goto out;
+ if (likely(pending_cqe_list->nodes[metadata_id].inuse)) {
+ mlx5e_ptp_port_ts_cqe_list_remove(pending_cqe_list, metadata_id);
+ } else {
+ /* Reclaim space in the unlikely event CQE was delivered after
+ * marking it late.
+ */
+ ptpsq->metadata_map.undelivered_counter--;
+ ptpsq->cq_stats->late_cqe++;
}
- if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_ci, skb_id)) {
- if (mlx5e_ptp_ts_cqe_ooo(ptpsq, skb_id)) {
- /* already handled by a previous resync */
- ptpsq->cq_stats->ooo_cqe_drop++;
- return;
- }
- mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_ci, skb_id, budget);
+ skb = mlx5e_ptp_metadata_map_remove(&ptpsq->metadata_map, metadata_id);
+
+ if (unlikely(is_err_cqe)) {
+ ptpsq->cq_stats->err_cqe++;
+ goto out;
}
- skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, get_cqe_ts(cqe));
mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_PORT_HWTSTAMP,
hwtstamp, ptpsq->cq_stats);
ptpsq->cq_stats->cqe++;
+ mlx5e_ptpsq_mark_ts_cqes_undelivered(ptpsq, hwtstamp);
out:
napi_consume_skb(skb, budget);
+ mlx5e_ptp_metadata_fifo_push(&ptpsq->metadata_freelist, metadata_id);
+ if (unlikely(mlx5e_ptp_metadata_map_unhealthy(&ptpsq->metadata_map)) &&
+ !test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
+ queue_work(ptpsq->txqsq.priv->wq, &ptpsq->report_unhealthy_work);
}
static bool mlx5e_ptp_poll_ts_cq(struct mlx5e_cq *cq, int budget)
@@ -291,36 +358,86 @@ static void mlx5e_ptp_destroy_sq(struct mlx5_core_dev *mdev, u32 sqn)
static int mlx5e_ptp_alloc_traffic_db(struct mlx5e_ptpsq *ptpsq, int numa)
{
- int wq_sz = mlx5_wq_cyc_get_size(&ptpsq->txqsq.wq);
- struct mlx5_core_dev *mdev = ptpsq->txqsq.mdev;
+ struct mlx5e_ptp_metadata_fifo *metadata_freelist = &ptpsq->metadata_freelist;
+ struct mlx5e_ptp_metadata_map *metadata_map = &ptpsq->metadata_map;
+ struct mlx5e_ptp_port_ts_cqe_list *cqe_list;
+ int db_sz;
+ int md;
- ptpsq->skb_fifo.fifo = kvzalloc_node(array_size(wq_sz, sizeof(*ptpsq->skb_fifo.fifo)),
- GFP_KERNEL, numa);
- if (!ptpsq->skb_fifo.fifo)
+ cqe_list = kvzalloc_node(sizeof(*ptpsq->ts_cqe_pending_list), GFP_KERNEL, numa);
+ if (!cqe_list)
return -ENOMEM;
+ ptpsq->ts_cqe_pending_list = cqe_list;
+
+ db_sz = min_t(u32, mlx5_wq_cyc_get_size(&ptpsq->txqsq.wq),
+ 1 << MLX5_CAP_GEN_2(ptpsq->txqsq.mdev,
+ ts_cqe_metadata_size2wqe_counter));
+ ptpsq->ts_cqe_ctr_mask = db_sz - 1;
+
+ cqe_list->nodes = kvzalloc_node(array_size(db_sz, sizeof(*cqe_list->nodes)),
+ GFP_KERNEL, numa);
+ if (!cqe_list->nodes)
+ goto free_cqe_list;
+ INIT_LIST_HEAD(&cqe_list->tracker_list_head);
+ spin_lock_init(&cqe_list->tracker_list_lock);
+
+ metadata_freelist->data =
+ kvzalloc_node(array_size(db_sz, sizeof(*metadata_freelist->data)),
+ GFP_KERNEL, numa);
+ if (!metadata_freelist->data)
+ goto free_cqe_list_nodes;
+ metadata_freelist->mask = ptpsq->ts_cqe_ctr_mask;
+
+ for (md = 0; md < db_sz; ++md) {
+ cqe_list->nodes[md].metadata_id = md;
+ metadata_freelist->data[md] = md;
+ }
+ metadata_freelist->pc = db_sz;
+
+ metadata_map->data =
+ kvzalloc_node(array_size(db_sz, sizeof(*metadata_map->data)),
+ GFP_KERNEL, numa);
+ if (!metadata_map->data)
+ goto free_metadata_freelist;
+ metadata_map->capacity = db_sz;
- ptpsq->skb_fifo.pc = &ptpsq->skb_fifo_pc;
- ptpsq->skb_fifo.cc = &ptpsq->skb_fifo_cc;
- ptpsq->skb_fifo.mask = wq_sz - 1;
- if (MLX5_CAP_GEN_2(mdev, ts_cqe_metadata_size2wqe_counter))
- ptpsq->ts_cqe_ctr_mask =
- (1 << MLX5_CAP_GEN_2(mdev, ts_cqe_metadata_size2wqe_counter)) - 1;
return 0;
+
+free_metadata_freelist:
+ kvfree(metadata_freelist->data);
+free_cqe_list_nodes:
+ kvfree(cqe_list->nodes);
+free_cqe_list:
+ kvfree(cqe_list);
+ return -ENOMEM;
}
-static void mlx5e_ptp_drain_skb_fifo(struct mlx5e_skb_fifo *skb_fifo)
+static void mlx5e_ptp_drain_metadata_map(struct mlx5e_ptp_metadata_map *map)
{
- while (*skb_fifo->pc != *skb_fifo->cc) {
- struct sk_buff *skb = mlx5e_skb_fifo_pop(skb_fifo);
+ int idx;
+
+ for (idx = 0; idx < map->capacity; ++idx) {
+ struct sk_buff *skb = map->data[idx];
dev_kfree_skb_any(skb);
}
}
-static void mlx5e_ptp_free_traffic_db(struct mlx5e_skb_fifo *skb_fifo)
+static void mlx5e_ptp_free_traffic_db(struct mlx5e_ptpsq *ptpsq)
{
- mlx5e_ptp_drain_skb_fifo(skb_fifo);
- kvfree(skb_fifo->fifo);
+ mlx5e_ptp_drain_metadata_map(&ptpsq->metadata_map);
+ kvfree(ptpsq->metadata_map.data);
+ kvfree(ptpsq->metadata_freelist.data);
+ kvfree(ptpsq->ts_cqe_pending_list->nodes);
+ kvfree(ptpsq->ts_cqe_pending_list);
+}
+
+static void mlx5e_ptpsq_unhealthy_work(struct work_struct *work)
+{
+ struct mlx5e_ptpsq *ptpsq =
+ container_of(work, struct mlx5e_ptpsq, report_unhealthy_work);
+
+ mlx5e_reporter_tx_ptpsq_unhealthy(ptpsq);
}
static int mlx5e_ptp_open_txqsq(struct mlx5e_ptp *c, u32 tisn,
@@ -348,11 +465,12 @@ static int mlx5e_ptp_open_txqsq(struct mlx5e_ptp *c, u32 tisn,
if (err)
goto err_free_txqsq;
- err = mlx5e_ptp_alloc_traffic_db(ptpsq,
- dev_to_node(mlx5_core_dma_dev(c->mdev)));
+ err = mlx5e_ptp_alloc_traffic_db(ptpsq, dev_to_node(mlx5_core_dma_dev(c->mdev)));
if (err)
goto err_free_txqsq;
+ INIT_WORK(&ptpsq->report_unhealthy_work, mlx5e_ptpsq_unhealthy_work);
+
return 0;
err_free_txqsq:
@@ -366,7 +484,9 @@ static void mlx5e_ptp_close_txqsq(struct mlx5e_ptpsq *ptpsq)
struct mlx5e_txqsq *sq = &ptpsq->txqsq;
struct mlx5_core_dev *mdev = sq->mdev;
- mlx5e_ptp_free_traffic_db(&ptpsq->skb_fifo);
+ if (current_work() != &ptpsq->report_unhealthy_work)
+ cancel_work_sync(&ptpsq->report_unhealthy_work);
+ mlx5e_ptp_free_traffic_db(ptpsq);
cancel_work_sync(&sq->recover_work);
mlx5e_ptp_destroy_sq(mdev, sq->sqn);
mlx5e_free_txqsq_descs(sq);
@@ -534,7 +654,10 @@ static void mlx5e_ptp_build_params(struct mlx5e_ptp *c,
/* SQ */
if (test_bit(MLX5E_PTP_STATE_TX, c->state)) {
- params->log_sq_size = orig->log_sq_size;
+ params->log_sq_size =
+ min(MLX5_CAP_GEN_2(c->mdev, ts_cqe_metadata_size2wqe_counter),
+ MLX5E_PTP_MAX_LOG_SQ_SIZE);
+ params->log_sq_size = min(params->log_sq_size, orig->log_sq_size);
mlx5e_ptp_build_sq_param(c->mdev, params, &cparams->txq_sq_param);
}
/* RQ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
index cc7efde88ac3..7b700d0f956a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
@@ -7,18 +7,38 @@
#include "en.h"
#include "en_stats.h"
#include "en/txrx.h"
+#include <linux/ktime.h>
#include <linux/ptp_classify.h>
+#include <linux/time64.h>
+#include <linux/workqueue.h>
#define MLX5E_PTP_CHANNEL_IX 0
+#define MLX5E_PTP_MAX_LOG_SQ_SIZE (8U)
+#define MLX5E_PTP_TS_CQE_UNDELIVERED_TIMEOUT (1 * NSEC_PER_SEC)
+
+struct mlx5e_ptp_metadata_fifo {
+ u8 cc;
+ u8 pc;
+ u8 mask;
+ u8 *data;
+};
+
+struct mlx5e_ptp_metadata_map {
+ u16 undelivered_counter;
+ u16 capacity;
+ struct sk_buff **data;
+};
struct mlx5e_ptpsq {
struct mlx5e_txqsq txqsq;
struct mlx5e_cq ts_cq;
- u16 skb_fifo_cc;
- u16 skb_fifo_pc;
- struct mlx5e_skb_fifo skb_fifo;
struct mlx5e_ptp_cq_stats *cq_stats;
u16 ts_cqe_ctr_mask;
+
+ struct work_struct report_unhealthy_work;
+ struct mlx5e_ptp_port_ts_cqe_list *ts_cqe_pending_list;
+ struct mlx5e_ptp_metadata_fifo metadata_freelist;
+ struct mlx5e_ptp_metadata_map metadata_map;
};
enum {
@@ -69,12 +89,35 @@ static inline bool mlx5e_use_ptpsq(struct sk_buff *skb)
fk.ports.dst == htons(PTP_EV_PORT));
}
-static inline bool mlx5e_ptpsq_fifo_has_room(struct mlx5e_txqsq *sq)
+static inline void mlx5e_ptp_metadata_fifo_push(struct mlx5e_ptp_metadata_fifo *fifo, u8 metadata)
{
- if (!sq->ptpsq)
- return true;
+ fifo->data[fifo->mask & fifo->pc++] = metadata;
+}
+
+static inline u8
+mlx5e_ptp_metadata_fifo_pop(struct mlx5e_ptp_metadata_fifo *fifo)
+{
+ return fifo->data[fifo->mask & fifo->cc++];
+}
- return mlx5e_skb_fifo_has_room(&sq->ptpsq->skb_fifo);
+static inline void
+mlx5e_ptp_metadata_map_put(struct mlx5e_ptp_metadata_map *map,
+ struct sk_buff *skb, u8 metadata)
+{
+ WARN_ON_ONCE(map->data[metadata]);
+ map->data[metadata] = skb;
+}
+
+static inline bool mlx5e_ptpsq_metadata_freelist_empty(struct mlx5e_ptpsq *ptpsq)
+{
+ struct mlx5e_ptp_metadata_fifo *freelist;
+
+ if (likely(!ptpsq))
+ return false;
+
+ freelist = &ptpsq->metadata_freelist;
+
+ return freelist->pc == freelist->cc;
}
int mlx5e_ptp_open(struct mlx5e_priv *priv, struct mlx5e_params *params,
@@ -89,6 +132,8 @@ void mlx5e_ptp_free_rx_fs(struct mlx5e_flow_steering *fs,
const struct mlx5e_profile *profile);
int mlx5e_ptp_rx_manage_fs(struct mlx5e_priv *priv, bool set);
+void mlx5e_ptpsq_track_metadata(struct mlx5e_ptpsq *ptpsq, u8 metadata);
+
enum {
MLX5E_SKB_CB_CQE_HWTSTAMP = BIT(0),
MLX5E_SKB_CB_PORT_HWTSTAMP = BIT(1),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
index 1874c2f0587f..244bc15a42ab 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
@@ -379,9 +379,9 @@ int mlx5e_htb_setup_tc(struct mlx5e_priv *priv, struct tc_htb_qopt_offload *htb_
if (!htb && htb_qopt->command != TC_HTB_CREATE)
return -EINVAL;
- if (htb_qopt->prio) {
+ if (htb_qopt->prio || htb_qopt->quantum) {
NL_SET_ERR_MSG_MOD(htb_qopt->extack,
- "prio parameter is not supported by device with HTB offload enabled.");
+ "prio and quantum parameters are not supported by device with HTB offload enabled.");
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
index 560800246573..0fef853eab62 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
@@ -77,6 +77,10 @@ mlx5_esw_bridge_rep_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_es
return NULL;
priv = netdev_priv(dev);
+
+ if (!priv->mdev->priv.eswitch->br_offloads)
+ return NULL;
+
rpriv = priv->ppriv;
*vport_num = rpriv->rep->vport;
*esw_owner_vhca_id = MLX5_CAP_GEN(priv->mdev, vhca_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index b5c773ffc763..b12fe3c5a258 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -715,9 +715,20 @@ void mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
uplink_priv = &uplink_rpriv->uplink_priv;
ct_priv = uplink_priv->ct_priv;
- if (!mlx5_ipsec_is_rx_flow(cqe) &&
- !mlx5e_tc_update_skb(cqe, skb, mapping_ctx, reg_c0, ct_priv, zone_restore_id, tunnel_id,
- &tc_priv))
+#ifdef CONFIG_MLX5_EN_IPSEC
+ if (!(tunnel_id >> ESW_TUN_OPTS_BITS)) {
+ u32 mapped_id;
+ u32 metadata;
+
+ mapped_id = tunnel_id & ESW_IPSEC_RX_MAPPED_ID_MASK;
+ if (mapped_id &&
+ !mlx5_esw_ipsec_rx_make_metadata(priv, mapped_id, &metadata))
+ mlx5e_ipsec_offload_handle_rx_skb(priv->netdev, skb, metadata);
+ }
+#endif
+
+ if (!mlx5e_tc_update_skb(cqe, skb, mapping_ctx, reg_c0, ct_priv,
+ zone_restore_id, tunnel_id, &tc_priv))
goto free_skb;
forward:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
index b35ff289af49..ff8242f67c54 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -164,6 +164,43 @@ static int mlx5e_tx_reporter_timeout_recover(void *ctx)
return err;
}
+static int mlx5e_tx_reporter_ptpsq_unhealthy_recover(void *ctx)
+{
+ struct mlx5e_ptpsq *ptpsq = ctx;
+ struct mlx5e_channels *chs;
+ struct net_device *netdev;
+ struct mlx5e_priv *priv;
+ int carrier_ok;
+ int err;
+
+ if (!test_bit(MLX5E_SQ_STATE_RECOVERING, &ptpsq->txqsq.state))
+ return 0;
+
+ priv = ptpsq->txqsq.priv;
+
+ mutex_lock(&priv->state_lock);
+ chs = &priv->channels;
+ netdev = priv->netdev;
+
+ carrier_ok = netif_carrier_ok(netdev);
+ netif_carrier_off(netdev);
+
+ mlx5e_deactivate_priv_channels(priv);
+
+ mlx5e_ptp_close(chs->ptp);
+ err = mlx5e_ptp_open(priv, &chs->params, chs->c[0]->lag_port, &chs->ptp);
+
+ mlx5e_activate_priv_channels(priv);
+
+ /* return carrier back if needed */
+ if (carrier_ok)
+ netif_carrier_on(netdev);
+
+ mutex_unlock(&priv->state_lock);
+
+ return err;
+}
+
/* state lock cannot be grabbed within this function.
* It can cause a dead lock or a read-after-free.
*/
@@ -516,6 +553,15 @@ static int mlx5e_tx_reporter_timeout_dump(struct mlx5e_priv *priv, struct devlin
return mlx5e_tx_reporter_dump_sq(priv, fmsg, to_ctx->sq);
}
+static int mlx5e_tx_reporter_ptpsq_unhealthy_dump(struct mlx5e_priv *priv,
+ struct devlink_fmsg *fmsg,
+ void *ctx)
+{
+ struct mlx5e_ptpsq *ptpsq = ctx;
+
+ return mlx5e_tx_reporter_dump_sq(priv, fmsg, &ptpsq->txqsq);
+}
+
static int mlx5e_tx_reporter_dump_all_sqs(struct mlx5e_priv *priv,
struct devlink_fmsg *fmsg)
{
@@ -621,6 +667,25 @@ int mlx5e_reporter_tx_timeout(struct mlx5e_txqsq *sq)
return to_ctx.status;
}
+void mlx5e_reporter_tx_ptpsq_unhealthy(struct mlx5e_ptpsq *ptpsq)
+{
+ struct mlx5e_ptp_metadata_map *map = &ptpsq->metadata_map;
+ char err_str[MLX5E_REPORTER_PER_Q_MAX_LEN];
+ struct mlx5e_txqsq *txqsq = &ptpsq->txqsq;
+ struct mlx5e_cq *ts_cq = &ptpsq->ts_cq;
+ struct mlx5e_priv *priv = txqsq->priv;
+ struct mlx5e_err_ctx err_ctx = {};
+
+ err_ctx.ctx = ptpsq;
+ err_ctx.recover = mlx5e_tx_reporter_ptpsq_unhealthy_recover;
+ err_ctx.dump = mlx5e_tx_reporter_ptpsq_unhealthy_dump;
+ snprintf(err_str, sizeof(err_str),
+ "Unhealthy TX port TS queue: %d, SQ: 0x%x, CQ: 0x%x, Undelivered CQEs: %u Map Capacity: %u",
+ txqsq->ch_ix, txqsq->sqn, ts_cq->mcq.cqn, map->undelivered_counter, map->capacity);
+
+ mlx5e_health_report(priv, priv->tx_reporter, err_str, &err_ctx);
+}
+
static const struct devlink_health_reporter_ops mlx5_tx_reporter_ops = {
.name = "tx",
.recover = mlx5e_tx_reporter_recover,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
index e1095bc36543..56e6b8c7501f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
@@ -218,17 +218,32 @@ int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
return mlx5e_rss_set_rxfh(rss, indir, key, hfunc, res->rss_rqns, res->rss_nch);
}
-u8 mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt)
+int mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, u32 rss_idx,
+ enum mlx5_traffic_types tt)
{
- struct mlx5e_rss *rss = res->rss[0];
+ struct mlx5e_rss *rss;
+
+ if (rss_idx >= MLX5E_MAX_NUM_RSS)
+ return -EINVAL;
+
+ rss = res->rss[rss_idx];
+ if (!rss)
+ return -ENOENT;
return mlx5e_rss_get_hash_fields(rss, tt);
}
-int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt,
- u8 rx_hash_fields)
+int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, u32 rss_idx,
+ enum mlx5_traffic_types tt, u8 rx_hash_fields)
{
- struct mlx5e_rss *rss = res->rss[0];
+ struct mlx5e_rss *rss;
+
+ if (rss_idx >= MLX5E_MAX_NUM_RSS)
+ return -EINVAL;
+
+ rss = res->rss[rss_idx];
+ if (!rss)
+ return -ENOENT;
return mlx5e_rss_set_hash_fields(rss, tt, rx_hash_fields);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
index 5d5f64fab60f..580fe8bc3cd2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
@@ -48,9 +48,10 @@ int mlx5e_rx_res_rss_get_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
const u32 *indir, const u8 *key, const u8 *hfunc);
-u8 mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt);
-int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt,
- u8 rx_hash_fields);
+int mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, u32 rss_idx,
+ enum mlx5_traffic_types tt);
+int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, u32 rss_idx,
+ enum mlx5_traffic_types tt, u8 rx_hash_fields);
int mlx5e_rx_res_packet_merge_set_param(struct mlx5e_rx_res *res,
struct mlx5e_packet_merge_param *pkt_merge_param);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c
index 2b80fe73549d..8c531f4ec912 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c
@@ -221,16 +221,21 @@ mlx5_ct_fs_smfs_destroy(struct mlx5_ct_fs *fs)
}
static inline bool
-mlx5_tc_ct_valid_used_dissector_keys(const u32 used_keys)
+mlx5_tc_ct_valid_used_dissector_keys(const u64 used_keys)
{
-#define DISS_BIT(name) BIT(FLOW_DISSECTOR_KEY_ ## name)
- const u32 basic_keys = DISS_BIT(BASIC) | DISS_BIT(CONTROL) | DISS_BIT(META);
- const u32 ipv4_tcp = basic_keys | DISS_BIT(IPV4_ADDRS) | DISS_BIT(PORTS) | DISS_BIT(TCP);
- const u32 ipv6_tcp = basic_keys | DISS_BIT(IPV6_ADDRS) | DISS_BIT(PORTS) | DISS_BIT(TCP);
- const u32 ipv4_udp = basic_keys | DISS_BIT(IPV4_ADDRS) | DISS_BIT(PORTS);
- const u32 ipv6_udp = basic_keys | DISS_BIT(IPV6_ADDRS) | DISS_BIT(PORTS);
- const u32 ipv4_gre = basic_keys | DISS_BIT(IPV4_ADDRS);
- const u32 ipv6_gre = basic_keys | DISS_BIT(IPV6_ADDRS);
+#define DISS_BIT(name) BIT_ULL(FLOW_DISSECTOR_KEY_ ## name)
+ const u64 basic_keys = DISS_BIT(BASIC) | DISS_BIT(CONTROL) |
+ DISS_BIT(META);
+ const u64 ipv4_tcp = basic_keys | DISS_BIT(IPV4_ADDRS) |
+ DISS_BIT(PORTS) | DISS_BIT(TCP);
+ const u64 ipv6_tcp = basic_keys | DISS_BIT(IPV6_ADDRS) |
+ DISS_BIT(PORTS) | DISS_BIT(TCP);
+ const u64 ipv4_udp = basic_keys | DISS_BIT(IPV4_ADDRS) |
+ DISS_BIT(PORTS);
+ const u64 ipv6_udp = basic_keys | DISS_BIT(IPV6_ADDRS) |
+ DISS_BIT(PORTS);
+ const u64 ipv4_gre = basic_keys | DISS_BIT(IPV4_ADDRS);
+ const u64 ipv6_gre = basic_keys | DISS_BIT(IPV6_ADDRS);
return (used_keys == ipv4_tcp || used_keys == ipv4_udp || used_keys == ipv6_tcp ||
used_keys == ipv6_udp || used_keys == ipv4_gre || used_keys == ipv6_gre);
@@ -247,7 +252,7 @@ mlx5_ct_fs_smfs_ct_validate_flow_rule(struct mlx5_ct_fs *fs, struct flow_rule *f
struct flow_match_tcp tcp;
if (!mlx5_tc_ct_valid_used_dissector_keys(flow_rule->match.dissector->used_keys)) {
- ct_dbg("rule uses unexpected dissectors (0x%08x)",
+ ct_dbg("rule uses unexpected dissectors (0x%016llx)",
flow_rule->match.dissector->used_keys);
return false;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
index 201ac7dd338f..5620d9f97518 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2020 Mellanox Technologies */
-#include <net/page_pool.h>
#include "en/txrx.h"
#include "en/params.h"
#include "en/trap.h"
@@ -128,7 +127,7 @@ static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
{
- int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
+ int cpu = mlx5_comp_vector_get_cpu(priv->mdev, 0);
struct net_device *netdev = priv->netdev;
struct mlx5e_trap *t;
int err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index 40589cebb773..12f56d0db0af 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -35,6 +35,7 @@
#include "en/xdp.h"
#include "en/params.h"
#include <linux/bitfield.h>
+#include <net/page_pool/helpers.h>
int mlx5e_xdp_max_mtu(struct mlx5e_params *params, struct mlx5e_xsk_param *xsk)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
index bac4717548c6..caa34b9c161e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
@@ -138,7 +138,7 @@ static inline bool mlx5e_accel_tx_begin(struct net_device *dev,
}
#endif
-#ifdef CONFIG_MLX5_EN_MACSEC
+#ifdef CONFIG_MLX5_MACSEC
if (unlikely(mlx5e_macsec_skb_is_offload(skb))) {
struct mlx5e_priv *priv = netdev_priv(dev);
@@ -173,7 +173,7 @@ static inline void mlx5e_accel_tx_eseg(struct mlx5e_priv *priv,
mlx5e_ipsec_tx_build_eseg(priv, skb, eseg);
#endif
-#ifdef CONFIG_MLX5_EN_MACSEC
+#ifdef CONFIG_MLX5_MACSEC
if (unlikely(mlx5e_macsec_skb_is_offload(skb)))
mlx5e_macsec_tx_build_eseg(priv->macsec, skb, eseg);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 891d39b4bfd4..7d4ceb9b9c16 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -38,8 +38,10 @@
#include <net/netevent.h>
#include "en.h"
+#include "eswitch.h"
#include "ipsec.h"
#include "ipsec_rxtx.h"
+#include "en_rep.h"
#define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000)
#define MLX5E_IPSEC_TUNNEL_SA XA_MARK_1
@@ -354,6 +356,12 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_init_limits(sa_entry, attrs);
mlx5e_ipsec_init_macs(sa_entry, attrs);
+
+ if (x->encap) {
+ attrs->encap = true;
+ attrs->sport = x->encap->encap_sport;
+ attrs->dport = x->encap->encap_dport;
+ }
}
static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
@@ -387,8 +395,25 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
return -EINVAL;
}
if (x->encap) {
- NL_SET_ERR_MSG_MOD(extack, "Encapsulated xfrm state may not be offloaded");
- return -EINVAL;
+ if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESPINUDP)) {
+ NL_SET_ERR_MSG_MOD(extack, "Encapsulation is not supported");
+ return -EINVAL;
+ }
+
+ if (x->encap->encap_type != UDP_ENCAP_ESPINUDP) {
+ NL_SET_ERR_MSG_MOD(extack, "Encapsulation other than UDP is not supported");
+ return -EINVAL;
+ }
+
+ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
+ NL_SET_ERR_MSG_MOD(extack, "Encapsulation is supported in packet offload mode only");
+ return -EINVAL;
+ }
+
+ if (x->props.mode != XFRM_MODE_TRANSPORT) {
+ NL_SET_ERR_MSG_MOD(extack, "Encapsulation is supported in transport mode only");
+ return -EINVAL;
+ }
}
if (!x->aead) {
NL_SET_ERR_MSG_MOD(extack, "Cannot offload xfrm states without aead");
@@ -416,9 +441,9 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
return -EINVAL;
}
- if (x->sel.proto != IPPROTO_IP &&
- (x->sel.proto != IPPROTO_UDP || x->xso.dir != XFRM_DEV_OFFLOAD_OUT)) {
- NL_SET_ERR_MSG_MOD(extack, "Device does not support upper protocol other than UDP, and only Tx direction");
+ if (x->sel.proto != IPPROTO_IP && x->sel.proto != IPPROTO_UDP &&
+ x->sel.proto != IPPROTO_TCP) {
+ NL_SET_ERR_MSG_MOD(extack, "Device does not support upper protocol other than TCP/UDP");
return -EINVAL;
}
@@ -646,6 +671,11 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x,
if (err)
goto err_xfrm;
+ if (!mlx5_eswitch_block_ipsec(priv->mdev)) {
+ err = -EBUSY;
+ goto err_xfrm;
+ }
+
/* check esn */
if (x->props.flags & XFRM_STATE_ESN)
mlx5e_ipsec_update_esn_state(sa_entry);
@@ -654,7 +684,7 @@ static int mlx5e_xfrm_add_state(struct xfrm_state *x,
err = mlx5_ipsec_create_work(sa_entry);
if (err)
- goto err_xfrm;
+ goto unblock_ipsec;
err = mlx5e_ipsec_create_dwork(sa_entry);
if (err)
@@ -711,6 +741,8 @@ release_work:
if (sa_entry->work)
kfree(sa_entry->work->data);
kfree(sa_entry->work);
+unblock_ipsec:
+ mlx5_eswitch_unblock_ipsec(priv->mdev);
err_xfrm:
kfree(sa_entry);
NL_SET_ERR_MSG_WEAK_MOD(extack, "Device failed to offload this state");
@@ -740,6 +772,7 @@ static void mlx5e_xfrm_del_state(struct xfrm_state *x)
static void mlx5e_xfrm_free_state(struct xfrm_state *x)
{
struct mlx5e_ipsec_sa_entry *sa_entry = to_ipsec_sa_entry(x);
+ struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ)
goto sa_entry_free;
@@ -756,6 +789,7 @@ static void mlx5e_xfrm_free_state(struct xfrm_state *x)
if (sa_entry->work)
kfree(sa_entry->work->data);
kfree(sa_entry->work);
+ mlx5_eswitch_unblock_ipsec(ipsec->mdev);
sa_entry_free:
kfree(sa_entry);
}
@@ -835,6 +869,7 @@ void mlx5e_ipsec_init(struct mlx5e_priv *priv)
goto clear_aso;
}
+ ipsec->is_uplink_rep = mlx5e_is_uplink_rep(priv);
ret = mlx5e_accel_ipsec_fs_init(ipsec);
if (ret)
goto err_fs_init;
@@ -958,9 +993,10 @@ static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev,
return -EINVAL;
}
- if (sel->proto != IPPROTO_IP &&
- (sel->proto != IPPROTO_UDP || x->xdo.dir != XFRM_DEV_OFFLOAD_OUT)) {
- NL_SET_ERR_MSG_MOD(extack, "Device does not support upper protocol other than UDP, and only Tx direction");
+ if (x->selector.proto != IPPROTO_IP &&
+ x->selector.proto != IPPROTO_UDP &&
+ x->selector.proto != IPPROTO_TCP) {
+ NL_SET_ERR_MSG_MOD(extack, "Device does not support upper protocol other than TCP/UDP");
return -EINVAL;
}
@@ -1029,6 +1065,11 @@ static int mlx5e_xfrm_add_policy(struct xfrm_policy *x,
pol_entry->x = x;
pol_entry->ipsec = priv->ipsec;
+ if (!mlx5_eswitch_block_ipsec(priv->mdev)) {
+ err = -EBUSY;
+ goto ipsec_busy;
+ }
+
mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs);
err = mlx5e_accel_ipsec_fs_add_pol(pol_entry);
if (err)
@@ -1038,6 +1079,8 @@ static int mlx5e_xfrm_add_policy(struct xfrm_policy *x,
return 0;
err_fs:
+ mlx5_eswitch_unblock_ipsec(priv->mdev);
+ipsec_busy:
kfree(pol_entry);
NL_SET_ERR_MSG_MOD(extack, "Device failed to offload this policy");
return err;
@@ -1048,6 +1091,7 @@ static void mlx5e_xfrm_del_policy(struct xfrm_policy *x)
struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(x);
mlx5e_accel_ipsec_fs_del_pol(pol_entry);
+ mlx5_eswitch_unblock_ipsec(pol_entry->ipsec->mdev);
}
static void mlx5e_xfrm_free_policy(struct xfrm_policy *x)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
index 4e9887171508..9e7c42c2f77b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
@@ -94,13 +94,20 @@ struct mlx5_accel_esp_xfrm_attrs {
u8 dir : 2;
u8 type : 2;
u8 drop : 1;
+ u8 encap : 1;
u8 family;
struct mlx5_replay_esn replay_esn;
u32 authsize;
u32 reqid;
struct mlx5_ipsec_lft lft;
- u8 smac[ETH_ALEN];
- u8 dmac[ETH_ALEN];
+ union {
+ u8 smac[ETH_ALEN];
+ __be16 sport;
+ };
+ union {
+ u8 dmac[ETH_ALEN];
+ __be16 dport;
+ };
};
enum mlx5_ipsec_cap {
@@ -110,6 +117,7 @@ enum mlx5_ipsec_cap {
MLX5_IPSEC_CAP_ROCE = 1 << 3,
MLX5_IPSEC_CAP_PRIO = 1 << 4,
MLX5_IPSEC_CAP_TUNNEL = 1 << 5,
+ MLX5_IPSEC_CAP_ESPINUDP = 1 << 6,
};
struct mlx5e_priv;
@@ -135,7 +143,7 @@ struct mlx5e_ipsec_sw_stats {
atomic64_t ipsec_tx_drop_trailer;
};
-struct mlx5e_ipsec_rx;
+struct mlx5e_ipsec_fc;
struct mlx5e_ipsec_tx;
struct mlx5e_ipsec_work {
@@ -161,6 +169,58 @@ struct mlx5e_ipsec_aso {
spinlock_t lock;
};
+struct mlx5e_ipsec_rx_create_attr {
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_ttc_table *ttc;
+ u32 family;
+ int prio;
+ int pol_level;
+ int sa_level;
+ int status_level;
+ enum mlx5_flow_namespace_type chains_ns;
+};
+
+struct mlx5e_ipsec_ft {
+ struct mutex mutex; /* Protect changes to this struct */
+ struct mlx5_flow_table *pol;
+ struct mlx5_flow_table *sa;
+ struct mlx5_flow_table *status;
+ u32 refcnt;
+};
+
+struct mlx5e_ipsec_rule {
+ struct mlx5_flow_handle *rule;
+ struct mlx5_modify_hdr *modify_hdr;
+ struct mlx5_pkt_reformat *pkt_reformat;
+ struct mlx5_fc *fc;
+};
+
+struct mlx5e_ipsec_miss {
+ struct mlx5_flow_group *group;
+ struct mlx5_flow_handle *rule;
+};
+
+struct mlx5e_ipsec_rx {
+ struct mlx5e_ipsec_ft ft;
+ struct mlx5e_ipsec_miss pol;
+ struct mlx5e_ipsec_miss sa;
+ struct mlx5e_ipsec_rule status;
+ struct mlx5e_ipsec_miss status_drop;
+ struct mlx5_fc *status_drop_cnt;
+ struct mlx5e_ipsec_fc *fc;
+ struct mlx5_fs_chains *chains;
+ u8 allow_tunnel_mode : 1;
+ struct xarray ipsec_obj_id_map;
+};
+
+struct mlx5e_ipsec_tx_create_attr {
+ int prio;
+ int pol_level;
+ int sa_level;
+ int cnt_level;
+ enum mlx5_flow_namespace_type chains_ns;
+};
+
struct mlx5e_ipsec {
struct mlx5_core_dev *mdev;
struct xarray sadb;
@@ -170,11 +230,14 @@ struct mlx5e_ipsec {
struct mlx5e_flow_steering *fs;
struct mlx5e_ipsec_rx *rx_ipv4;
struct mlx5e_ipsec_rx *rx_ipv6;
+ struct mlx5e_ipsec_rx *rx_esw;
struct mlx5e_ipsec_tx *tx;
+ struct mlx5e_ipsec_tx *tx_esw;
struct mlx5e_ipsec_aso *aso;
struct notifier_block nb;
struct notifier_block netevent_nb;
struct mlx5_ipsec_fs *roce;
+ u8 is_uplink_rep: 1;
};
struct mlx5e_ipsec_esn_state {
@@ -183,13 +246,6 @@ struct mlx5e_ipsec_esn_state {
u8 overlap: 1;
};
-struct mlx5e_ipsec_rule {
- struct mlx5_flow_handle *rule;
- struct mlx5_modify_hdr *modify_hdr;
- struct mlx5_pkt_reformat *pkt_reformat;
- struct mlx5_fc *fc;
-};
-
struct mlx5e_ipsec_limits {
u64 round;
u8 soft_limit_hit : 1;
@@ -209,6 +265,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_work *work;
struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits;
+ u32 rx_mapped_id;
};
struct mlx5_accel_pol_xfrm_attrs {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
index 832d36be4a17..7dba4221993f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
@@ -9,6 +9,8 @@
#include "fs_core.h"
#include "lib/ipsec_fs_roce.h"
#include "lib/fs_chains.h"
+#include "esw/ipsec_fs.h"
+#include "en_rep.h"
#define NUM_IPSEC_FTE BIT(15)
#define MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE 16
@@ -19,32 +21,10 @@ struct mlx5e_ipsec_fc {
struct mlx5_fc *drop;
};
-struct mlx5e_ipsec_ft {
- struct mutex mutex; /* Protect changes to this struct */
- struct mlx5_flow_table *pol;
- struct mlx5_flow_table *sa;
- struct mlx5_flow_table *status;
- u32 refcnt;
-};
-
-struct mlx5e_ipsec_miss {
- struct mlx5_flow_group *group;
- struct mlx5_flow_handle *rule;
-};
-
-struct mlx5e_ipsec_rx {
- struct mlx5e_ipsec_ft ft;
- struct mlx5e_ipsec_miss pol;
- struct mlx5e_ipsec_miss sa;
- struct mlx5e_ipsec_rule status;
- struct mlx5e_ipsec_fc *fc;
- struct mlx5_fs_chains *chains;
- u8 allow_tunnel_mode : 1;
-};
-
struct mlx5e_ipsec_tx {
struct mlx5e_ipsec_ft ft;
struct mlx5e_ipsec_miss pol;
+ struct mlx5e_ipsec_miss sa;
struct mlx5e_ipsec_rule status;
struct mlx5_flow_namespace *ns;
struct mlx5e_ipsec_fc *fc;
@@ -60,14 +40,25 @@ static enum mlx5_traffic_types family2tt(u32 family)
return MLX5_TT_IPV6_IPSEC_ESP;
}
-static struct mlx5e_ipsec_rx *ipsec_rx(struct mlx5e_ipsec *ipsec, u32 family)
+static struct mlx5e_ipsec_rx *ipsec_rx(struct mlx5e_ipsec *ipsec, u32 family, int type)
{
+ if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
+ return ipsec->rx_esw;
+
if (family == AF_INET)
return ipsec->rx_ipv4;
return ipsec->rx_ipv6;
}
+static struct mlx5e_ipsec_tx *ipsec_tx(struct mlx5e_ipsec *ipsec, int type)
+{
+ if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
+ return ipsec->tx_esw;
+
+ return ipsec->tx;
+}
+
static struct mlx5_fs_chains *
ipsec_chains_create(struct mlx5_core_dev *mdev, struct mlx5_flow_table *miss_ft,
enum mlx5_flow_namespace_type ns, int base_prio,
@@ -238,13 +229,19 @@ out:
return err;
}
-static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
- struct mlx5e_ipsec_rx *rx, u32 family)
+static void ipsec_rx_ft_disconnect(struct mlx5e_ipsec *ipsec, u32 family)
{
struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
- /* disconnect */
mlx5_ttc_fwd_default_dest(ttc, family2tt(family));
+}
+
+static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx, u32 family)
+{
+ /* disconnect */
+ if (rx != ipsec->rx_esw)
+ ipsec_rx_ft_disconnect(ipsec, family);
if (rx->chains) {
ipsec_chains_destroy(rx->chains);
@@ -259,51 +256,105 @@ static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
mlx5_destroy_flow_table(rx->ft.sa);
if (rx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
- mlx5_del_flow_rules(rx->status.rule);
- mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
+ if (rx == ipsec->rx_esw) {
+ mlx5_esw_ipsec_rx_status_destroy(ipsec, rx);
+ } else {
+ mlx5_del_flow_rules(rx->status.rule);
+ mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
+ }
mlx5_destroy_flow_table(rx->ft.status);
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family);
}
+static void ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ u32 family,
+ struct mlx5e_ipsec_rx_create_attr *attr)
+{
+ if (rx == ipsec->rx_esw) {
+ /* For packet offload in switchdev mode, RX & TX use FDB namespace */
+ attr->ns = ipsec->tx_esw->ns;
+ mlx5_esw_ipsec_rx_create_attr_set(ipsec, attr);
+ return;
+ }
+
+ attr->ns = mlx5e_fs_get_ns(ipsec->fs, false);
+ attr->ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
+ attr->family = family;
+ attr->prio = MLX5E_NIC_PRIO;
+ attr->pol_level = MLX5E_ACCEL_FS_POL_FT_LEVEL;
+ attr->sa_level = MLX5E_ACCEL_FS_ESP_FT_LEVEL;
+ attr->status_level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL;
+ attr->chains_ns = MLX5_FLOW_NAMESPACE_KERNEL;
+}
+
+static int ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5e_ipsec_rx_create_attr *attr,
+ struct mlx5_flow_destination *dest)
+{
+ struct mlx5_flow_table *ft;
+ int err;
+
+ if (rx == ipsec->rx_esw)
+ return mlx5_esw_ipsec_rx_status_pass_dest_get(ipsec, dest);
+
+ *dest = mlx5_ttc_get_default_dest(attr->ttc, family2tt(attr->family));
+ err = mlx5_ipsec_fs_roce_rx_create(ipsec->mdev, ipsec->roce, attr->ns, dest,
+ attr->family, MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL,
+ attr->prio);
+ if (err)
+ return err;
+
+ ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, attr->family);
+ if (ft) {
+ dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest->ft = ft;
+ }
+
+ return 0;
+}
+
+static void ipsec_rx_ft_connect(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5e_ipsec_rx_create_attr *attr)
+{
+ struct mlx5_flow_destination dest = {};
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest.ft = rx->ft.pol;
+ mlx5_ttc_fwd_dest(attr->ttc, family2tt(attr->family), &dest);
+}
+
static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx, u32 family)
{
- struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(ipsec->fs, false);
- struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
- struct mlx5_flow_destination default_dest;
+ struct mlx5e_ipsec_rx_create_attr attr;
struct mlx5_flow_destination dest[2];
struct mlx5_flow_table *ft;
u32 flags = 0;
int err;
- default_dest = mlx5_ttc_get_default_dest(ttc, family2tt(family));
- err = mlx5_ipsec_fs_roce_rx_create(mdev, ipsec->roce, ns, &default_dest,
- family, MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL,
- MLX5E_NIC_PRIO);
+ ipsec_rx_create_attr_set(ipsec, rx, family, &attr);
+
+ err = ipsec_rx_status_pass_dest_get(ipsec, rx, &attr, &dest[0]);
if (err)
return err;
- ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL,
- MLX5E_NIC_PRIO, 1, 0);
+ ft = ipsec_ft_create(attr.ns, attr.status_level, attr.prio, 1, 0);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
goto err_fs_ft_status;
}
-
rx->ft.status = ft;
- ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, family);
- if (ft) {
- dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest[0].ft = ft;
- } else {
- dest[0] = default_dest;
- }
-
dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest[1].counter_id = mlx5_fc_id(rx->fc->cnt);
- err = ipsec_status_rule(mdev, rx, dest);
+ if (rx == ipsec->rx_esw)
+ err = mlx5_esw_ipsec_rx_status_create(ipsec, rx, dest);
+ else
+ err = ipsec_status_rule(mdev, rx, dest);
if (err)
goto err_add;
@@ -312,8 +363,7 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
rx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
if (rx->allow_tunnel_mode)
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
- ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_LEVEL, MLX5E_NIC_PRIO, 2,
- flags);
+ ft = ipsec_ft_create(attr.ns, attr.sa_level, attr.prio, 2, flags);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
goto err_fs_ft;
@@ -326,9 +376,9 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
rx->chains = ipsec_chains_create(mdev, rx->ft.sa,
- MLX5_FLOW_NAMESPACE_KERNEL,
- MLX5E_NIC_PRIO,
- MLX5E_ACCEL_FS_POL_FT_LEVEL,
+ attr.chains_ns,
+ attr.prio,
+ attr.pol_level,
&rx->ft.pol);
if (IS_ERR(rx->chains)) {
err = PTR_ERR(rx->chains);
@@ -338,8 +388,7 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
goto connect;
}
- ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_POL_FT_LEVEL, MLX5E_NIC_PRIO,
- 2, 0);
+ ft = ipsec_ft_create(attr.ns, attr.pol_level, attr.prio, 2, 0);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
goto err_pol_ft;
@@ -354,10 +403,8 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
connect:
/* connect */
- memset(dest, 0x00, sizeof(*dest));
- dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest[0].ft = rx->ft.pol;
- mlx5_ttc_fwd_dest(ttc, family2tt(family), &dest[0]);
+ if (rx != ipsec->rx_esw)
+ ipsec_rx_ft_connect(ipsec, rx, &attr);
return 0;
err_pol_miss:
@@ -387,10 +434,16 @@ static int rx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (rx->ft.refcnt)
goto skip;
- err = rx_create(mdev, ipsec, rx, family);
+ err = mlx5_eswitch_block_mode(mdev);
if (err)
return err;
+ err = rx_create(mdev, ipsec, rx, family);
+ if (err) {
+ mlx5_eswitch_unblock_mode(mdev);
+ return err;
+ }
+
skip:
rx->ft.refcnt++;
return 0;
@@ -403,12 +456,14 @@ static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
return;
rx_destroy(ipsec->mdev, ipsec, rx, family);
+ mlx5_eswitch_unblock_mode(ipsec->mdev);
}
static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
- struct mlx5e_ipsec *ipsec, u32 family)
+ struct mlx5e_ipsec *ipsec, u32 family,
+ int type)
{
- struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family);
+ struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
int err;
mutex_lock(&rx->ft.mutex);
@@ -422,9 +477,9 @@ static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
static struct mlx5_flow_table *rx_ft_get_policy(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec,
- u32 family, u32 prio)
+ u32 family, u32 prio, int type)
{
- struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family);
+ struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
struct mlx5_flow_table *ft;
int err;
@@ -449,18 +504,18 @@ err_get:
return ERR_PTR(err);
}
-static void rx_ft_put(struct mlx5e_ipsec *ipsec, u32 family)
+static void rx_ft_put(struct mlx5e_ipsec *ipsec, u32 family, int type)
{
- struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family);
+ struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
mutex_lock(&rx->ft.mutex);
rx_put(ipsec, rx, family);
mutex_unlock(&rx->ft.mutex);
}
-static void rx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 family, u32 prio)
+static void rx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 family, u32 prio, int type)
{
- struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family);
+ struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
mutex_lock(&rx->ft.mutex);
if (rx->chains)
@@ -504,7 +559,7 @@ err_rule:
}
/* IPsec TX flow steering */
-static void tx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
+static void tx_destroy(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
struct mlx5_ipsec_fs *roce)
{
mlx5_ipsec_fs_roce_tx_destroy(roce);
@@ -516,22 +571,45 @@ static void tx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
mlx5_destroy_flow_table(tx->ft.pol);
}
+ if (tx == ipsec->tx_esw) {
+ mlx5_del_flow_rules(tx->sa.rule);
+ mlx5_destroy_flow_group(tx->sa.group);
+ }
mlx5_destroy_flow_table(tx->ft.sa);
if (tx->allow_tunnel_mode)
- mlx5_eswitch_unblock_encap(mdev);
+ mlx5_eswitch_unblock_encap(ipsec->mdev);
mlx5_del_flow_rules(tx->status.rule);
mlx5_destroy_flow_table(tx->ft.status);
}
-static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
+static void ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx *tx,
+ struct mlx5e_ipsec_tx_create_attr *attr)
+{
+ if (tx == ipsec->tx_esw) {
+ mlx5_esw_ipsec_tx_create_attr_set(ipsec, attr);
+ return;
+ }
+
+ attr->prio = 0;
+ attr->pol_level = 0;
+ attr->sa_level = 1;
+ attr->cnt_level = 2;
+ attr->chains_ns = MLX5_FLOW_NAMESPACE_EGRESS_IPSEC;
+}
+
+static int tx_create(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
struct mlx5_ipsec_fs *roce)
{
+ struct mlx5_core_dev *mdev = ipsec->mdev;
+ struct mlx5e_ipsec_tx_create_attr attr;
struct mlx5_flow_destination dest = {};
struct mlx5_flow_table *ft;
u32 flags = 0;
int err;
- ft = ipsec_ft_create(tx->ns, 2, 0, 1, 0);
+ ipsec_tx_create_attr_set(ipsec, tx, &attr);
+ ft = ipsec_ft_create(tx->ns, attr.cnt_level, attr.prio, 1, 0);
if (IS_ERR(ft))
return PTR_ERR(ft);
tx->ft.status = ft;
@@ -544,16 +622,25 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
tx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
if (tx->allow_tunnel_mode)
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
- ft = ipsec_ft_create(tx->ns, 1, 0, 4, flags);
+ ft = ipsec_ft_create(tx->ns, attr.sa_level, attr.prio, 4, flags);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
goto err_sa_ft;
}
tx->ft.sa = ft;
+ if (tx == ipsec->tx_esw) {
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+ dest.vport.num = MLX5_VPORT_UPLINK;
+ err = ipsec_miss_create(mdev, tx->ft.sa, &tx->sa, &dest);
+ if (err)
+ goto err_sa_miss;
+ memset(&dest, 0, sizeof(dest));
+ }
+
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
tx->chains = ipsec_chains_create(
- mdev, tx->ft.sa, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC, 0, 0,
+ mdev, tx->ft.sa, attr.chains_ns, attr.prio, attr.pol_level,
&tx->ft.pol);
if (IS_ERR(tx->chains)) {
err = PTR_ERR(tx->chains);
@@ -563,7 +650,7 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
goto connect_roce;
}
- ft = ipsec_ft_create(tx->ns, 0, 0, 2, 0);
+ ft = ipsec_ft_create(tx->ns, attr.pol_level, attr.prio, 2, 0);
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
goto err_pol_ft;
@@ -592,6 +679,11 @@ err_roce:
mlx5_destroy_flow_table(tx->ft.pol);
}
err_pol_ft:
+ if (tx == ipsec->tx_esw) {
+ mlx5_del_flow_rules(tx->sa.rule);
+ mlx5_destroy_flow_group(tx->sa.group);
+ }
+err_sa_miss:
mlx5_destroy_flow_table(tx->ft.sa);
err_sa_ft:
if (tx->allow_tunnel_mode)
@@ -602,6 +694,25 @@ err_status_rule:
return err;
}
+static void ipsec_esw_tx_ft_policy_set(struct mlx5_core_dev *mdev,
+ struct mlx5_flow_table *ft)
+{
+#ifdef CONFIG_MLX5_ESWITCH
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+ struct mlx5e_rep_priv *uplink_rpriv;
+ struct mlx5e_priv *priv;
+
+ esw->offloads.ft_ipsec_tx_pol = ft;
+ uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
+ priv = netdev_priv(uplink_rpriv->netdev);
+ if (!priv->channels.num)
+ return;
+
+ mlx5e_rep_deactivate_channels(priv);
+ mlx5e_rep_activate_channels(priv);
+#endif
+}
+
static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx *tx)
{
@@ -610,10 +721,19 @@ static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (tx->ft.refcnt)
goto skip;
- err = tx_create(mdev, tx, ipsec->roce);
+ err = mlx5_eswitch_block_mode(mdev);
if (err)
return err;
+ err = tx_create(ipsec, tx, ipsec->roce);
+ if (err) {
+ mlx5_eswitch_unblock_mode(mdev);
+ return err;
+ }
+
+ if (tx == ipsec->tx_esw)
+ ipsec_esw_tx_ft_policy_set(mdev, tx->ft.pol);
+
skip:
tx->ft.refcnt++;
return 0;
@@ -624,14 +744,20 @@ static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
if (--tx->ft.refcnt)
return;
- tx_destroy(ipsec->mdev, tx, ipsec->roce);
+ if (tx == ipsec->tx_esw) {
+ mlx5_esw_ipsec_restore_dest_uplink(ipsec->mdev);
+ ipsec_esw_tx_ft_policy_set(ipsec->mdev, NULL);
+ }
+
+ tx_destroy(ipsec, tx, ipsec->roce);
+ mlx5_eswitch_unblock_mode(ipsec->mdev);
}
static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec,
- u32 prio)
+ u32 prio, int type)
{
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
+ struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
struct mlx5_flow_table *ft;
int err;
@@ -657,9 +783,9 @@ err_get:
}
static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
- struct mlx5e_ipsec *ipsec)
+ struct mlx5e_ipsec *ipsec, int type)
{
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
+ struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
int err;
mutex_lock(&tx->ft.mutex);
@@ -671,18 +797,18 @@ static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
return tx;
}
-static void tx_ft_put(struct mlx5e_ipsec *ipsec)
+static void tx_ft_put(struct mlx5e_ipsec *ipsec, int type)
{
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
+ struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
mutex_lock(&tx->ft.mutex);
tx_put(ipsec, tx);
mutex_unlock(&tx->ft.mutex);
}
-static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio)
+static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio, int type)
{
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
+ struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
mutex_lock(&tx->ft.mutex);
if (tx->chains)
@@ -782,43 +908,75 @@ static void setup_fte_reg_a(struct mlx5_flow_spec *spec)
misc_parameters_2.metadata_reg_a, MLX5_ETH_WQE_FT_META_IPSEC);
}
-static void setup_fte_reg_c0(struct mlx5_flow_spec *spec, u32 reqid)
+static void setup_fte_reg_c4(struct mlx5_flow_spec *spec, u32 reqid)
{
/* Pass policy check before choosing this SA */
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
- MLX5_SET(fte_match_param, spec->match_criteria,
- misc_parameters_2.metadata_reg_c_0, reqid);
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ misc_parameters_2.metadata_reg_c_4);
MLX5_SET(fte_match_param, spec->match_value,
- misc_parameters_2.metadata_reg_c_0, reqid);
+ misc_parameters_2.metadata_reg_c_4, reqid);
}
static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upspec *upspec)
{
- if (upspec->proto != IPPROTO_UDP)
+ switch (upspec->proto) {
+ case IPPROTO_UDP:
+ if (upspec->dport) {
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria,
+ udp_dport, upspec->dport_mask);
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
+ udp_dport, upspec->dport);
+ }
+ if (upspec->sport) {
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria,
+ udp_sport, upspec->sport_mask);
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
+ udp_sport, upspec->sport);
+ }
+ break;
+ case IPPROTO_TCP:
+ if (upspec->dport) {
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria,
+ tcp_dport, upspec->dport_mask);
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
+ tcp_dport, upspec->dport);
+ }
+ if (upspec->sport) {
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria,
+ tcp_sport, upspec->sport_mask);
+ MLX5_SET(fte_match_set_lyr_2_4, spec->match_value,
+ tcp_sport, upspec->sport);
+ }
+ break;
+ default:
return;
+ }
spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, spec->match_criteria, ip_protocol);
MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, ip_protocol, upspec->proto);
- if (upspec->dport) {
- MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria, udp_dport,
- upspec->dport_mask);
- MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, udp_dport, upspec->dport);
- }
+}
- if (upspec->sport) {
- MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria, udp_sport,
- upspec->sport_mask);
- MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, udp_sport, upspec->sport);
- }
+static enum mlx5_flow_namespace_type ipsec_fs_get_ns(struct mlx5e_ipsec *ipsec,
+ int type, u8 dir)
+{
+ if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
+ return MLX5_FLOW_NAMESPACE_FDB;
+
+ if (dir == XFRM_DEV_OFFLOAD_IN)
+ return MLX5_FLOW_NAMESPACE_KERNEL;
+
+ return MLX5_FLOW_NAMESPACE_EGRESS;
}
-static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir,
+static int setup_modify_header(struct mlx5e_ipsec *ipsec, int type, u32 val, u8 dir,
struct mlx5_flow_act *flow_act)
{
+ enum mlx5_flow_namespace_type ns_type = ipsec_fs_get_ns(ipsec, type, dir);
u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
- enum mlx5_flow_namespace_type ns_type;
+ struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_modify_hdr *modify_hdr;
MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
@@ -826,12 +984,10 @@ static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir,
case XFRM_DEV_OFFLOAD_IN:
MLX5_SET(set_action_in, action, field,
MLX5_ACTION_IN_FIELD_METADATA_REG_B);
- ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
break;
case XFRM_DEV_OFFLOAD_OUT:
MLX5_SET(set_action_in, action, field,
- MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
- ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_4);
break;
default:
return -EINVAL;
@@ -951,37 +1107,70 @@ free_reformatbf:
return -EINVAL;
}
+static int get_reformat_type(struct mlx5_accel_esp_xfrm_attrs *attrs)
+{
+ switch (attrs->dir) {
+ case XFRM_DEV_OFFLOAD_IN:
+ if (attrs->encap)
+ return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT_OVER_UDP;
+ return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
+ case XFRM_DEV_OFFLOAD_OUT:
+ if (attrs->family == AF_INET) {
+ if (attrs->encap)
+ return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV4;
+ return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
+ }
+
+ if (attrs->encap)
+ return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV6;
+ return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
+ default:
+ WARN_ON(true);
+ }
+
+ return -EINVAL;
+}
+
static int
setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
struct mlx5_pkt_reformat_params *reformat_params)
{
- u8 *reformatbf;
+ struct udphdr *udphdr;
+ char *reformatbf;
+ size_t bfflen;
__be32 spi;
+ void *hdr;
+
+ reformat_params->type = get_reformat_type(attrs);
+ if (reformat_params->type < 0)
+ return reformat_params->type;
switch (attrs->dir) {
case XFRM_DEV_OFFLOAD_IN:
- reformat_params->type = MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
break;
case XFRM_DEV_OFFLOAD_OUT:
- if (attrs->family == AF_INET)
- reformat_params->type =
- MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
- else
- reformat_params->type =
- MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
-
- reformatbf = kzalloc(MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE,
- GFP_KERNEL);
+ bfflen = MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
+ if (attrs->encap)
+ bfflen += sizeof(*udphdr);
+
+ reformatbf = kzalloc(bfflen, GFP_KERNEL);
if (!reformatbf)
return -ENOMEM;
+ hdr = reformatbf;
+ if (attrs->encap) {
+ udphdr = (struct udphdr *)reformatbf;
+ udphdr->source = attrs->sport;
+ udphdr->dest = attrs->dport;
+ hdr += sizeof(*udphdr);
+ }
+
/* convert to network format */
spi = htonl(attrs->spi);
- memcpy(reformatbf, &spi, sizeof(spi));
+ memcpy(hdr, &spi, sizeof(spi));
reformat_params->param_0 = attrs->authsize;
- reformat_params->size =
- MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
+ reformat_params->size = bfflen;
reformat_params->data = reformatbf;
break;
default:
@@ -991,26 +1180,17 @@ setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
return 0;
}
-static int setup_pkt_reformat(struct mlx5_core_dev *mdev,
+static int setup_pkt_reformat(struct mlx5e_ipsec *ipsec,
struct mlx5_accel_esp_xfrm_attrs *attrs,
struct mlx5_flow_act *flow_act)
{
+ enum mlx5_flow_namespace_type ns_type = ipsec_fs_get_ns(ipsec, attrs->type,
+ attrs->dir);
struct mlx5_pkt_reformat_params reformat_params = {};
+ struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_pkt_reformat *pkt_reformat;
- enum mlx5_flow_namespace_type ns_type;
int ret;
- switch (attrs->dir) {
- case XFRM_DEV_OFFLOAD_IN:
- ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
- break;
- case XFRM_DEV_OFFLOAD_OUT:
- ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
- break;
- default:
- return -EINVAL;
- }
-
switch (attrs->mode) {
case XFRM_MODE_TRANSPORT:
ret = setup_pkt_transport_reformat(attrs, &reformat_params);
@@ -1047,9 +1227,9 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
struct mlx5_flow_spec *spec;
struct mlx5e_ipsec_rx *rx;
struct mlx5_fc *counter;
- int err;
+ int err = 0;
- rx = rx_ft_get(mdev, ipsec, attrs->family);
+ rx = rx_ft_get(mdev, ipsec, attrs->family, attrs->type);
if (IS_ERR(rx))
return PTR_ERR(rx);
@@ -1067,15 +1247,21 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
setup_fte_spi(spec, attrs->spi);
setup_fte_esp(spec);
setup_fte_no_frags(spec);
+ setup_fte_upper_proto_match(spec, &attrs->upspec);
+
+ if (rx != ipsec->rx_esw)
+ err = setup_modify_header(ipsec, attrs->type,
+ sa_entry->ipsec_obj_id | BIT(31),
+ XFRM_DEV_OFFLOAD_IN, &flow_act);
+ else
+ err = mlx5_esw_ipsec_rx_setup_modify_header(sa_entry, &flow_act);
- err = setup_modify_header(mdev, sa_entry->ipsec_obj_id | BIT(31),
- XFRM_DEV_OFFLOAD_IN, &flow_act);
if (err)
goto err_mod_header;
switch (attrs->type) {
case XFRM_DEV_OFFLOAD_PACKET:
- err = setup_pkt_reformat(mdev, attrs, &flow_act);
+ err = setup_pkt_reformat(ipsec, attrs, &flow_act);
if (err)
goto err_pkt_reformat;
break;
@@ -1125,7 +1311,7 @@ err_pkt_reformat:
err_mod_header:
kvfree(spec);
err_alloc:
- rx_ft_put(ipsec, attrs->family);
+ rx_ft_put(ipsec, attrs->family, attrs->type);
return err;
}
@@ -1142,7 +1328,7 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
struct mlx5_fc *counter;
int err;
- tx = tx_ft_get(mdev, ipsec);
+ tx = tx_ft_get(mdev, ipsec, attrs->type);
if (IS_ERR(tx))
return PTR_ERR(tx);
@@ -1168,8 +1354,8 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
break;
case XFRM_DEV_OFFLOAD_PACKET:
if (attrs->reqid)
- setup_fte_reg_c0(spec, attrs->reqid);
- err = setup_pkt_reformat(mdev, attrs, &flow_act);
+ setup_fte_reg_c4(spec, attrs->reqid);
+ err = setup_pkt_reformat(ipsec, attrs, &flow_act);
if (err)
goto err_pkt_reformat;
break;
@@ -1218,7 +1404,7 @@ err_add_cnt:
err_pkt_reformat:
kvfree(spec);
err_alloc:
- tx_ft_put(ipsec);
+ tx_ft_put(ipsec, attrs->type);
return err;
}
@@ -1226,15 +1412,16 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
{
struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
- struct mlx5e_ipsec_tx *tx = pol_entry->ipsec->tx;
+ struct mlx5e_ipsec *ipsec = pol_entry->ipsec;
struct mlx5_flow_destination dest[2] = {};
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
struct mlx5_flow_table *ft;
+ struct mlx5e_ipsec_tx *tx;
int err, dstn = 0;
- ft = tx_ft_get_policy(mdev, pol_entry->ipsec, attrs->prio);
+ ft = tx_ft_get_policy(mdev, ipsec, attrs->prio, attrs->type);
if (IS_ERR(ft))
return PTR_ERR(ft);
@@ -1244,6 +1431,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
goto err_alloc;
}
+ tx = ipsec_tx(ipsec, attrs->type);
if (attrs->family == AF_INET)
setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
else
@@ -1258,7 +1446,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
if (!attrs->reqid)
break;
- err = setup_modify_header(mdev, attrs->reqid,
+ err = setup_modify_header(ipsec, attrs->type, attrs->reqid,
XFRM_DEV_OFFLOAD_OUT, &flow_act);
if (err)
goto err_mod_header;
@@ -1277,6 +1465,8 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
}
flow_act.flags |= FLOW_ACT_NO_APPEND;
+ if (tx == ipsec->tx_esw && tx->chains)
+ flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[dstn].ft = tx->ft.sa;
dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dstn++;
@@ -1298,7 +1488,7 @@ err_action:
err_mod_header:
kvfree(spec);
err_alloc:
- tx_ft_put_policy(pol_entry->ipsec, attrs->prio);
+ tx_ft_put_policy(ipsec, attrs->prio, attrs->type);
return err;
}
@@ -1306,6 +1496,7 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
{
struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
+ struct mlx5e_ipsec *ipsec = pol_entry->ipsec;
struct mlx5_flow_destination dest[2];
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
@@ -1314,11 +1505,12 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
struct mlx5e_ipsec_rx *rx;
int err, dstn = 0;
- ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->family, attrs->prio);
+ ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->family, attrs->prio,
+ attrs->type);
if (IS_ERR(ft))
return PTR_ERR(ft);
- rx = ipsec_rx(pol_entry->ipsec, attrs->family);
+ rx = ipsec_rx(pol_entry->ipsec, attrs->family, attrs->type);
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) {
@@ -1332,6 +1524,7 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6);
setup_fte_no_frags(spec);
+ setup_fte_upper_proto_match(spec, &attrs->upspec);
switch (attrs->action) {
case XFRM_POLICY_ALLOW:
@@ -1350,6 +1543,8 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
}
flow_act.flags |= FLOW_ACT_NO_APPEND;
+ if (rx == ipsec->rx_esw && rx->chains)
+ flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[dstn].ft = rx->ft.sa;
dstn++;
@@ -1367,88 +1562,110 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
err_action:
kvfree(spec);
err_alloc:
- rx_ft_put_policy(pol_entry->ipsec, attrs->family, attrs->prio);
+ rx_ft_put_policy(pol_entry->ipsec, attrs->family, attrs->prio, attrs->type);
return err;
}
+static void ipsec_fs_destroy_single_counter(struct mlx5_core_dev *mdev,
+ struct mlx5e_ipsec_fc *fc)
+{
+ mlx5_fc_destroy(mdev, fc->drop);
+ mlx5_fc_destroy(mdev, fc->cnt);
+ kfree(fc);
+}
+
static void ipsec_fs_destroy_counters(struct mlx5e_ipsec *ipsec)
{
- struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
struct mlx5_core_dev *mdev = ipsec->mdev;
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
- mlx5_fc_destroy(mdev, tx->fc->drop);
- mlx5_fc_destroy(mdev, tx->fc->cnt);
- kfree(tx->fc);
- mlx5_fc_destroy(mdev, rx_ipv4->fc->drop);
- mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt);
- kfree(rx_ipv4->fc);
+ ipsec_fs_destroy_single_counter(mdev, ipsec->tx->fc);
+ ipsec_fs_destroy_single_counter(mdev, ipsec->rx_ipv4->fc);
+ if (ipsec->is_uplink_rep) {
+ ipsec_fs_destroy_single_counter(mdev, ipsec->tx_esw->fc);
+ ipsec_fs_destroy_single_counter(mdev, ipsec->rx_esw->fc);
+ }
}
-static int ipsec_fs_init_counters(struct mlx5e_ipsec *ipsec)
+static struct mlx5e_ipsec_fc *ipsec_fs_init_single_counter(struct mlx5_core_dev *mdev)
{
- struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
- struct mlx5e_ipsec_rx *rx_ipv6 = ipsec->rx_ipv6;
- struct mlx5_core_dev *mdev = ipsec->mdev;
- struct mlx5e_ipsec_tx *tx = ipsec->tx;
struct mlx5e_ipsec_fc *fc;
struct mlx5_fc *counter;
int err;
- fc = kzalloc(sizeof(*rx_ipv4->fc), GFP_KERNEL);
+ fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- /* Both IPv4 and IPv6 point to same flow counters struct. */
- rx_ipv4->fc = fc;
- rx_ipv6->fc = fc;
counter = mlx5_fc_create(mdev, false);
if (IS_ERR(counter)) {
err = PTR_ERR(counter);
- goto err_rx_cnt;
+ goto err_cnt;
}
-
fc->cnt = counter;
+
counter = mlx5_fc_create(mdev, false);
if (IS_ERR(counter)) {
err = PTR_ERR(counter);
- goto err_rx_drop;
+ goto err_drop;
}
-
fc->drop = counter;
- fc = kzalloc(sizeof(*tx->fc), GFP_KERNEL);
- if (!fc) {
- err = -ENOMEM;
- goto err_tx_fc;
+
+ return fc;
+
+err_drop:
+ mlx5_fc_destroy(mdev, fc->cnt);
+err_cnt:
+ kfree(fc);
+ return ERR_PTR(err);
+}
+
+static int ipsec_fs_init_counters(struct mlx5e_ipsec *ipsec)
+{
+ struct mlx5_core_dev *mdev = ipsec->mdev;
+ struct mlx5e_ipsec_fc *fc;
+ int err;
+
+ fc = ipsec_fs_init_single_counter(mdev);
+ if (IS_ERR(fc)) {
+ err = PTR_ERR(fc);
+ goto err_rx_cnt;
}
+ ipsec->rx_ipv4->fc = fc;
- tx->fc = fc;
- counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(counter)) {
- err = PTR_ERR(counter);
+ fc = ipsec_fs_init_single_counter(mdev);
+ if (IS_ERR(fc)) {
+ err = PTR_ERR(fc);
goto err_tx_cnt;
}
+ ipsec->tx->fc = fc;
- fc->cnt = counter;
- counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(counter)) {
- err = PTR_ERR(counter);
- goto err_tx_drop;
+ if (ipsec->is_uplink_rep) {
+ fc = ipsec_fs_init_single_counter(mdev);
+ if (IS_ERR(fc)) {
+ err = PTR_ERR(fc);
+ goto err_rx_esw_cnt;
+ }
+ ipsec->rx_esw->fc = fc;
+
+ fc = ipsec_fs_init_single_counter(mdev);
+ if (IS_ERR(fc)) {
+ err = PTR_ERR(fc);
+ goto err_tx_esw_cnt;
+ }
+ ipsec->tx_esw->fc = fc;
}
- fc->drop = counter;
+ /* Both IPv4 and IPv6 point to same flow counters struct. */
+ ipsec->rx_ipv6->fc = ipsec->rx_ipv4->fc;
return 0;
-err_tx_drop:
- mlx5_fc_destroy(mdev, tx->fc->cnt);
+err_tx_esw_cnt:
+ ipsec_fs_destroy_single_counter(mdev, ipsec->rx_esw->fc);
+err_rx_esw_cnt:
+ ipsec_fs_destroy_single_counter(mdev, ipsec->tx->fc);
err_tx_cnt:
- kfree(tx->fc);
-err_tx_fc:
- mlx5_fc_destroy(mdev, rx_ipv4->fc->drop);
-err_rx_drop:
- mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt);
+ ipsec_fs_destroy_single_counter(mdev, ipsec->rx_ipv4->fc);
err_rx_cnt:
- kfree(rx_ipv4->fc);
return err;
}
@@ -1458,6 +1675,7 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
struct mlx5e_ipsec *ipsec = priv->ipsec;
struct mlx5e_ipsec_hw_stats *stats;
struct mlx5e_ipsec_fc *fc;
+ u64 packets, bytes;
stats = (struct mlx5e_ipsec_hw_stats *)ipsec_stats;
@@ -1479,14 +1697,94 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
mlx5_fc_query(mdev, fc->cnt, &stats->ipsec_tx_pkts, &stats->ipsec_tx_bytes);
mlx5_fc_query(mdev, fc->drop, &stats->ipsec_tx_drop_pkts,
&stats->ipsec_tx_drop_bytes);
+
+ if (ipsec->is_uplink_rep) {
+ fc = ipsec->rx_esw->fc;
+ if (!mlx5_fc_query(mdev, fc->cnt, &packets, &bytes)) {
+ stats->ipsec_rx_pkts += packets;
+ stats->ipsec_rx_bytes += bytes;
+ }
+
+ if (!mlx5_fc_query(mdev, fc->drop, &packets, &bytes)) {
+ stats->ipsec_rx_drop_pkts += packets;
+ stats->ipsec_rx_drop_bytes += bytes;
+ }
+
+ fc = ipsec->tx_esw->fc;
+ if (!mlx5_fc_query(mdev, fc->cnt, &packets, &bytes)) {
+ stats->ipsec_tx_pkts += packets;
+ stats->ipsec_tx_bytes += bytes;
+ }
+
+ if (!mlx5_fc_query(mdev, fc->drop, &packets, &bytes)) {
+ stats->ipsec_tx_drop_pkts += packets;
+ stats->ipsec_tx_drop_bytes += bytes;
+ }
+ }
+}
+
+#ifdef CONFIG_MLX5_ESWITCH
+static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+ int err = 0;
+
+ if (esw)
+ down_write(&esw->mode_lock);
+
+ if (mdev->num_block_ipsec) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ mdev->num_block_tc++;
+
+unlock:
+ if (esw)
+ up_write(&esw->mode_lock);
+
+ return err;
+}
+#else
+static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
+{
+ if (mdev->num_block_ipsec)
+ return -EBUSY;
+
+ mdev->num_block_tc++;
+ return 0;
+}
+#endif
+
+static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)
+{
+ mdev->num_block_tc++;
}
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
{
+ int err;
+
+ if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET) {
+ err = mlx5e_ipsec_block_tc_offload(sa_entry->ipsec->mdev);
+ if (err)
+ return err;
+ }
+
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
- return tx_add_rule(sa_entry);
+ err = tx_add_rule(sa_entry);
+ else
+ err = rx_add_rule(sa_entry);
+
+ if (err)
+ goto err_out;
- return rx_add_rule(sa_entry);
+ return 0;
+
+err_out:
+ if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
+ mlx5e_ipsec_unblock_tc_offload(sa_entry->ipsec->mdev);
+ return err;
}
void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
@@ -1499,21 +1797,40 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
if (ipsec_rule->pkt_reformat)
mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat);
+ if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
+ mlx5e_ipsec_unblock_tc_offload(mdev);
+
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) {
- tx_ft_put(sa_entry->ipsec);
+ tx_ft_put(sa_entry->ipsec, sa_entry->attrs.type);
return;
}
mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
- rx_ft_put(sa_entry->ipsec, sa_entry->attrs.family);
+ mlx5_esw_ipsec_rx_id_mapping_remove(sa_entry);
+ rx_ft_put(sa_entry->ipsec, sa_entry->attrs.family, sa_entry->attrs.type);
}
int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
{
+ int err;
+
+ err = mlx5e_ipsec_block_tc_offload(pol_entry->ipsec->mdev);
+ if (err)
+ return err;
+
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
- return tx_add_policy(pol_entry);
+ err = tx_add_policy(pol_entry);
+ else
+ err = rx_add_policy(pol_entry);
+
+ if (err)
+ goto err_out;
- return rx_add_policy(pol_entry);
+ return 0;
+
+err_out:
+ mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
+ return err;
}
void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
@@ -1523,16 +1840,18 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
mlx5_del_flow_rules(ipsec_rule->rule);
+ mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
+
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) {
rx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.family,
- pol_entry->attrs.prio);
+ pol_entry->attrs.prio, pol_entry->attrs.type);
return;
}
if (ipsec_rule->modify_hdr)
mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
- tx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.prio);
+ tx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.prio, pol_entry->attrs.type);
}
void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
@@ -1540,7 +1859,7 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
if (!ipsec->tx)
return;
- if (mlx5_ipsec_device_caps(ipsec->mdev) & MLX5_IPSEC_CAP_ROCE)
+ if (ipsec->roce)
mlx5_ipsec_fs_roce_cleanup(ipsec->roce);
ipsec_fs_destroy_counters(ipsec);
@@ -1555,12 +1874,24 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
mutex_destroy(&ipsec->rx_ipv6->ft.mutex);
WARN_ON(ipsec->rx_ipv6->ft.refcnt);
kfree(ipsec->rx_ipv6);
+
+ if (ipsec->is_uplink_rep) {
+ xa_destroy(&ipsec->rx_esw->ipsec_obj_id_map);
+
+ mutex_destroy(&ipsec->tx_esw->ft.mutex);
+ WARN_ON(ipsec->tx_esw->ft.refcnt);
+ kfree(ipsec->tx_esw);
+
+ mutex_destroy(&ipsec->rx_esw->ft.mutex);
+ WARN_ON(ipsec->rx_esw->ft.refcnt);
+ kfree(ipsec->rx_esw);
+ }
}
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
{
struct mlx5_core_dev *mdev = ipsec->mdev;
- struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_namespace *ns, *ns_esw;
int err = -ENOMEM;
ns = mlx5_get_flow_namespace(ipsec->mdev,
@@ -1568,9 +1899,23 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
if (!ns)
return -EOPNOTSUPP;
+ if (ipsec->is_uplink_rep) {
+ ns_esw = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_FDB);
+ if (!ns_esw)
+ return -EOPNOTSUPP;
+
+ ipsec->tx_esw = kzalloc(sizeof(*ipsec->tx_esw), GFP_KERNEL);
+ if (!ipsec->tx_esw)
+ return -ENOMEM;
+
+ ipsec->rx_esw = kzalloc(sizeof(*ipsec->rx_esw), GFP_KERNEL);
+ if (!ipsec->rx_esw)
+ goto err_rx_esw;
+ }
+
ipsec->tx = kzalloc(sizeof(*ipsec->tx), GFP_KERNEL);
if (!ipsec->tx)
- return -ENOMEM;
+ goto err_tx;
ipsec->rx_ipv4 = kzalloc(sizeof(*ipsec->rx_ipv4), GFP_KERNEL);
if (!ipsec->rx_ipv4)
@@ -1589,8 +1934,14 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
mutex_init(&ipsec->rx_ipv6->ft.mutex);
ipsec->tx->ns = ns;
- if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ROCE)
+ if (ipsec->is_uplink_rep) {
+ mutex_init(&ipsec->tx_esw->ft.mutex);
+ mutex_init(&ipsec->rx_esw->ft.mutex);
+ ipsec->tx_esw->ns = ns_esw;
+ xa_init_flags(&ipsec->rx_esw->ipsec_obj_id_map, XA_FLAGS_ALLOC1);
+ } else if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ROCE) {
ipsec->roce = mlx5_ipsec_fs_roce_init(mdev);
+ }
return 0;
@@ -1600,6 +1951,10 @@ err_rx_ipv6:
kfree(ipsec->rx_ipv4);
err_rx_ipv4:
kfree(ipsec->tx);
+err_tx:
+ kfree(ipsec->rx_esw);
+err_rx_esw:
+ kfree(ipsec->tx_esw);
return err;
}
@@ -1621,10 +1976,12 @@ void mlx5e_accel_ipsec_fs_modify(struct mlx5e_ipsec_sa_entry *sa_entry)
bool mlx5e_ipsec_fs_tunnel_enabled(struct mlx5e_ipsec_sa_entry *sa_entry)
{
- struct mlx5e_ipsec_rx *rx =
- ipsec_rx(sa_entry->ipsec, sa_entry->attrs.family);
- struct mlx5e_ipsec_tx *tx = sa_entry->ipsec->tx;
+ struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
+ struct mlx5e_ipsec_rx *rx;
+ struct mlx5e_ipsec_tx *tx;
+ rx = ipsec_rx(sa_entry->ipsec, attrs->family, attrs->type);
+ tx = ipsec_tx(sa_entry->ipsec, attrs->type);
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx->allow_tunnel_mode;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
index a3554bde3e07..3245d1c9d539 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
@@ -45,8 +45,9 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap))
caps |= MLX5_IPSEC_CAP_PACKET_OFFLOAD;
- if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) &&
- MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level))
+ if ((MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) &&
+ MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) ||
+ MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, ignore_flow_level))
caps |= MLX5_IPSEC_CAP_PRIO;
if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
@@ -54,6 +55,12 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
reformat_l3_esp_tunnel_to_l2))
caps |= MLX5_IPSEC_CAP_TUNNEL;
+
+ if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
+ reformat_add_esp_transport_over_udp) &&
+ MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
+ reformat_del_esp_transport_over_udp))
+ caps |= MLX5_IPSEC_CAP_ESPINUDP;
}
if (mlx5_get_roce_state(mdev) &&
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
index 8d995e304869..51a144246ea6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
@@ -37,6 +37,7 @@
#include "ipsec.h"
#include "ipsec_rxtx.h"
#include "en.h"
+#include "esw/ipsec_fs.h"
enum {
MLX5E_IPSEC_TX_SYNDROME_OFFLOAD = 0x8,
@@ -311,9 +312,8 @@ enum {
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
- struct mlx5_cqe64 *cqe)
+ u32 ipsec_meta_data)
{
- u32 ipsec_meta_data = be32_to_cpu(cqe->ft_metadata);
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_ipsec *ipsec = priv->ipsec;
struct mlx5e_ipsec_sa_entry *sa_entry;
@@ -358,3 +358,24 @@ void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_syndrome);
}
}
+
+int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metadata)
+{
+ struct mlx5e_ipsec *ipsec = priv->ipsec;
+ u32 ipsec_obj_id;
+ int err;
+
+ if (!ipsec || !ipsec->is_uplink_rep)
+ return -EINVAL;
+
+ err = mlx5_esw_ipsec_rx_ipsec_obj_id_search(priv, id, &ipsec_obj_id);
+ if (err) {
+ atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_sadb_miss);
+ return err;
+ }
+
+ *metadata = MLX5_IPSEC_METADATA_CREATE(ipsec_obj_id,
+ MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
index 1878a70b9031..9ee014a8ad24 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
@@ -43,6 +43,7 @@
#define MLX5_IPSEC_METADATA_MARKER(metadata) (((metadata) >> 31) & 0x1)
#define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) >> 24) & GENMASK(5, 0))
#define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(23, 0))
+#define MLX5_IPSEC_METADATA_CREATE(id, syndrome) ((id) | ((syndrome) << 24))
struct mlx5e_accel_tx_ipsec_state {
struct xfrm_offload *xo;
@@ -66,7 +67,8 @@ void mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
struct mlx5_wqe_inline_seg *inlseg);
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
- struct mlx5_cqe64 *cqe);
+ u32 ipsec_meta_data);
+int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metadata);
static inline unsigned int mlx5e_ipsec_tx_ids_len(struct mlx5e_accel_tx_ipsec_state *ipsec_st)
{
return ipsec_st->tailen;
@@ -145,7 +147,7 @@ mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
static inline
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
- struct mlx5_cqe64 *cqe)
+ u32 ipsec_meta_data)
{}
static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index 592b165530ff..c9c1db971652 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -10,7 +10,6 @@
#include "lib/aso.h"
#include "lib/crypto.h"
#include "en_accel/macsec.h"
-#include "en_accel/macsec_fs.h"
#define MLX5_MACSEC_EPN_SCOPE_MID 0x80000000L
#define MLX5E_MACSEC_ASO_CTX_SZ MLX5_ST_SZ_BYTES(macsec_aso)
@@ -66,9 +65,7 @@ struct mlx5e_macsec_sa {
ssci_t ssci;
salt_t salt;
- struct rhash_head hash;
- u32 fs_id;
- union mlx5e_macsec_rule *macsec_rule;
+ union mlx5_macsec_rule *macsec_rule;
struct rcu_head rcu_head;
struct mlx5e_macsec_epn_state epn_state;
};
@@ -106,14 +103,6 @@ struct mlx5e_macsec_aso {
u32 pdn;
};
-static const struct rhashtable_params rhash_sci = {
- .key_len = sizeof_field(struct mlx5e_macsec_sa, sci),
- .key_offset = offsetof(struct mlx5e_macsec_sa, sci),
- .head_offset = offsetof(struct mlx5e_macsec_sa, hash),
- .automatic_shrinking = true,
- .min_size = 1,
-};
-
struct mlx5e_macsec_device {
const struct net_device *netdev;
struct mlx5e_macsec_sa *tx_sa[MACSEC_NUM_AN];
@@ -125,20 +114,13 @@ struct mlx5e_macsec_device {
struct mlx5e_macsec {
struct list_head macsec_device_list_head;
int num_of_devices;
- struct mlx5e_macsec_fs *macsec_fs;
struct mutex lock; /* Protects mlx5e_macsec internal contexts */
- /* Tx sci -> fs id mapping handling */
- struct rhashtable sci_hash; /* sci -> mlx5e_macsec_sa */
-
/* Rx fs_id -> rx_sc mapping */
struct xarray sc_xarray;
struct mlx5_core_dev *mdev;
- /* Stats manage */
- struct mlx5e_macsec_stats stats;
-
/* ASO */
struct mlx5e_macsec_aso aso;
@@ -330,36 +312,30 @@ static void mlx5e_macsec_destroy_object(struct mlx5_core_dev *mdev, u32 macsec_o
static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
struct mlx5e_macsec_sa *sa,
- bool is_tx)
+ bool is_tx, struct net_device *netdev, u32 fs_id)
{
int action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
- if ((is_tx) && sa->fs_id) {
- /* Make sure ongoing datapath readers sees a valid SA */
- rhashtable_remove_fast(&macsec->sci_hash, &sa->hash, rhash_sci);
- sa->fs_id = 0;
- }
-
if (!sa->macsec_rule)
return;
- mlx5e_macsec_fs_del_rule(macsec->macsec_fs, sa->macsec_rule, action);
+ mlx5_macsec_fs_del_rule(macsec->mdev->macsec_fs, sa->macsec_rule, action, netdev,
+ fs_id);
mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
sa->macsec_rule = NULL;
}
static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
struct mlx5e_macsec_sa *sa,
- bool encrypt,
- bool is_tx)
+ bool encrypt, bool is_tx, u32 *fs_id)
{
struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
struct mlx5e_macsec *macsec = priv->macsec;
struct mlx5_macsec_rule_attrs rule_attrs;
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_macsec_obj_attrs obj_attrs;
- union mlx5e_macsec_rule *macsec_rule;
+ union mlx5_macsec_rule *macsec_rule;
int err;
obj_attrs.next_pn = sa->next_pn;
@@ -387,7 +363,7 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
- macsec_rule = mlx5e_macsec_fs_add_rule(macsec->macsec_fs, ctx, &rule_attrs, &sa->fs_id);
+ macsec_rule = mlx5_macsec_fs_add_rule(mdev->macsec_fs, ctx, &rule_attrs, fs_id);
if (!macsec_rule) {
err = -ENOMEM;
goto destroy_macsec_object;
@@ -395,16 +371,8 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
sa->macsec_rule = macsec_rule;
- if (is_tx) {
- err = rhashtable_insert_fast(&macsec->sci_hash, &sa->hash, rhash_sci);
- if (err)
- goto destroy_macsec_object_and_rule;
- }
-
return 0;
-destroy_macsec_object_and_rule:
- mlx5e_macsec_cleanup_sa(macsec, sa, is_tx);
destroy_macsec_object:
mlx5e_macsec_destroy_object(mdev, sa->macsec_obj_id);
@@ -426,7 +394,7 @@ mlx5e_macsec_get_rx_sc_from_sc_list(const struct list_head *list, sci_t sci)
static int macsec_rx_sa_active_update(struct macsec_context *ctx,
struct mlx5e_macsec_sa *rx_sa,
- bool active)
+ bool active, u32 *fs_id)
{
struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
struct mlx5e_macsec *macsec = priv->macsec;
@@ -437,11 +405,11 @@ static int macsec_rx_sa_active_update(struct macsec_context *ctx,
rx_sa->active = active;
if (!active) {
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev, *fs_id);
return 0;
}
- err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false);
+ err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false, fs_id);
if (err)
rx_sa->active = false;
@@ -563,7 +531,7 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx)
!tx_sa->active)
goto out;
- err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true);
+ err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
if (err)
goto destroy_encryption_key;
@@ -627,7 +595,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
goto out;
if (ctx_tx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true);
+ err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
if (err)
goto out;
} else {
@@ -636,7 +604,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
goto out;
}
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true);
+ mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
}
out:
mutex_unlock(&macsec->lock);
@@ -669,7 +637,7 @@ static int mlx5e_macsec_del_txsa(struct macsec_context *ctx)
goto out;
}
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true);
+ mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id);
kfree_rcu_mightsleep(tx_sa);
macsec_device->tx_sa[assoc_num] = NULL;
@@ -680,20 +648,6 @@ out:
return err;
}
-static u32 mlx5e_macsec_get_sa_from_hashtable(struct rhashtable *sci_hash, sci_t *sci)
-{
- struct mlx5e_macsec_sa *macsec_sa;
- u32 fs_id = 0;
-
- rcu_read_lock();
- macsec_sa = rhashtable_lookup(sci_hash, sci, rhash_sci);
- if (macsec_sa)
- fs_id = macsec_sa->fs_id;
- rcu_read_unlock();
-
- return fs_id;
-}
-
static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
{
struct mlx5e_macsec_rx_sc_xarray_element *sc_xarray_element;
@@ -813,7 +767,8 @@ static int mlx5e_macsec_upd_rxsc(struct macsec_context *ctx)
if (!rx_sa)
continue;
- err = macsec_rx_sa_active_update(ctx, rx_sa, rx_sa->active && ctx_rx_sc->active);
+ err = macsec_rx_sa_active_update(ctx, rx_sa, rx_sa->active && ctx_rx_sc->active,
+ &rx_sc->sc_xarray_element->fs_id);
if (err)
goto out;
}
@@ -824,7 +779,8 @@ out:
return err;
}
-static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec_rx_sc *rx_sc)
+static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec_rx_sc *rx_sc,
+ struct net_device *netdev)
{
struct mlx5e_macsec_sa *rx_sa;
int i;
@@ -834,7 +790,8 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec
if (!rx_sa)
continue;
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, netdev,
+ rx_sc->sc_xarray_element->fs_id);
mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
kfree(rx_sa);
@@ -882,7 +839,7 @@ static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx)
goto out;
}
- macsec_del_rxsc_ctx(macsec, rx_sc);
+ macsec_del_rxsc_ctx(macsec, rx_sc, ctx->secy->netdev);
out:
mutex_unlock(&macsec->lock);
@@ -941,7 +898,6 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx)
rx_sa->next_pn = ctx_rx_sa->next_pn;
rx_sa->sci = sci;
rx_sa->assoc_num = assoc_num;
- rx_sa->fs_id = rx_sc->sc_xarray_element->fs_id;
if (ctx->secy->xpn)
update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves,
@@ -958,7 +914,7 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx)
goto out;
//TODO - add support for both authentication and encryption flows
- err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false);
+ err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false, &rx_sc->sc_xarray_element->fs_id);
if (err)
goto destroy_encryption_key;
@@ -1025,7 +981,8 @@ static int mlx5e_macsec_upd_rxsa(struct macsec_context *ctx)
goto out;
}
- err = macsec_rx_sa_active_update(ctx, rx_sa, ctx_rx_sa->active);
+ err = macsec_rx_sa_active_update(ctx, rx_sa, ctx_rx_sa->active,
+ &rx_sc->sc_xarray_element->fs_id);
out:
mutex_unlock(&macsec->lock);
@@ -1073,7 +1030,8 @@ static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx)
goto out;
}
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
+ rx_sc->sc_xarray_element->fs_id);
mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
kfree(rx_sa);
rx_sc->rx_sa[assoc_num] = NULL;
@@ -1154,7 +1112,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
if (!rx_sa || !rx_sa->macsec_rule)
continue;
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false);
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
+ rx_sc->sc_xarray_element->fs_id);
}
}
@@ -1165,7 +1124,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
continue;
if (rx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false);
+ err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false,
+ &rx_sc->sc_xarray_element->fs_id);
if (err)
goto out;
}
@@ -1218,7 +1178,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
if (!tx_sa)
continue;
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true);
+ mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
}
for (i = 0; i < MACSEC_NUM_AN; ++i) {
@@ -1227,7 +1187,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
continue;
if (tx_sa->assoc_num == tx_sc->encoding_sa && tx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true);
+ err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
if (err)
goto out;
}
@@ -1265,7 +1225,7 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
if (!tx_sa)
continue;
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true);
+ mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id);
kfree(tx_sa);
macsec_device->tx_sa[i] = NULL;
@@ -1273,7 +1233,7 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
list = &macsec_device->macsec_rx_sc_list_head;
list_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element)
- macsec_del_rxsc_ctx(macsec, rx_sc);
+ macsec_del_rxsc_ctx(macsec, rx_sc, ctx->secy->netdev);
kfree(macsec_device->dev_addr);
macsec_device->dev_addr = NULL;
@@ -1647,50 +1607,6 @@ static void mlx5e_macsec_aso_cleanup(struct mlx5e_macsec_aso *aso, struct mlx5_c
mlx5_core_dealloc_pd(mdev, aso->pdn);
}
-bool mlx5e_is_macsec_device(const struct mlx5_core_dev *mdev)
-{
- if (!(MLX5_CAP_GEN_64(mdev, general_obj_types) &
- MLX5_GENERAL_OBJ_TYPES_CAP_MACSEC_OFFLOAD))
- return false;
-
- if (!MLX5_CAP_GEN(mdev, log_max_dek))
- return false;
-
- if (!MLX5_CAP_MACSEC(mdev, log_max_macsec_offload))
- return false;
-
- if (!MLX5_CAP_FLOWTABLE_NIC_RX(mdev, macsec_decrypt) ||
- !MLX5_CAP_FLOWTABLE_NIC_RX(mdev, reformat_remove_macsec))
- return false;
-
- if (!MLX5_CAP_FLOWTABLE_NIC_TX(mdev, macsec_encrypt) ||
- !MLX5_CAP_FLOWTABLE_NIC_TX(mdev, reformat_add_macsec))
- return false;
-
- if (!MLX5_CAP_MACSEC(mdev, macsec_crypto_esp_aes_gcm_128_encrypt) &&
- !MLX5_CAP_MACSEC(mdev, macsec_crypto_esp_aes_gcm_256_encrypt))
- return false;
-
- if (!MLX5_CAP_MACSEC(mdev, macsec_crypto_esp_aes_gcm_128_decrypt) &&
- !MLX5_CAP_MACSEC(mdev, macsec_crypto_esp_aes_gcm_256_decrypt))
- return false;
-
- return true;
-}
-
-void mlx5e_macsec_get_stats_fill(struct mlx5e_macsec *macsec, void *macsec_stats)
-{
- mlx5e_macsec_fs_get_stats_fill(macsec->macsec_fs, macsec_stats);
-}
-
-struct mlx5e_macsec_stats *mlx5e_macsec_get_stats(struct mlx5e_macsec *macsec)
-{
- if (!macsec)
- return NULL;
-
- return &macsec->stats;
-}
-
static const struct macsec_ops macsec_offload_ops = {
.mdo_add_txsa = mlx5e_macsec_add_txsa,
.mdo_upd_txsa = mlx5e_macsec_upd_txsa,
@@ -1711,7 +1627,8 @@ bool mlx5e_macsec_handle_tx_skb(struct mlx5e_macsec *macsec, struct sk_buff *skb
struct metadata_dst *md_dst = skb_metadata_dst(skb);
u32 fs_id;
- fs_id = mlx5e_macsec_get_sa_from_hashtable(&macsec->sci_hash, &md_dst->u.macsec_info.sci);
+ fs_id = mlx5_macsec_fs_get_fs_id_from_hashtable(macsec->mdev->macsec_fs,
+ &md_dst->u.macsec_info.sci);
if (!fs_id)
goto err_out;
@@ -1729,7 +1646,8 @@ void mlx5e_macsec_tx_build_eseg(struct mlx5e_macsec *macsec,
struct metadata_dst *md_dst = skb_metadata_dst(skb);
u32 fs_id;
- fs_id = mlx5e_macsec_get_sa_from_hashtable(&macsec->sci_hash, &md_dst->u.macsec_info.sci);
+ fs_id = mlx5_macsec_fs_get_fs_id_from_hashtable(macsec->mdev->macsec_fs,
+ &md_dst->u.macsec_info.sci);
if (!fs_id)
return;
@@ -1782,7 +1700,7 @@ int mlx5e_macsec_init(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_macsec *macsec = NULL;
- struct mlx5e_macsec_fs *macsec_fs;
+ struct mlx5_macsec_fs *macsec_fs;
int err;
if (!mlx5e_is_macsec_device(priv->mdev)) {
@@ -1797,13 +1715,6 @@ int mlx5e_macsec_init(struct mlx5e_priv *priv)
INIT_LIST_HEAD(&macsec->macsec_device_list_head);
mutex_init(&macsec->lock);
- err = rhashtable_init(&macsec->sci_hash, &rhash_sci);
- if (err) {
- mlx5_core_err(mdev, "MACsec offload: Failed to init SCI hash table, err=%d\n",
- err);
- goto err_hash;
- }
-
err = mlx5e_macsec_aso_init(&macsec->aso, priv->mdev);
if (err) {
mlx5_core_err(mdev, "MACsec offload: Failed to init aso, err=%d\n", err);
@@ -1822,13 +1733,13 @@ int mlx5e_macsec_init(struct mlx5e_priv *priv)
macsec->mdev = mdev;
- macsec_fs = mlx5e_macsec_fs_init(mdev, priv->netdev);
+ macsec_fs = mlx5_macsec_fs_init(mdev);
if (!macsec_fs) {
err = -ENOMEM;
goto err_out;
}
- macsec->macsec_fs = macsec_fs;
+ mdev->macsec_fs = macsec_fs;
macsec->nb.notifier_call = macsec_obj_change_event;
mlx5_notifier_register(mdev, &macsec->nb);
@@ -1842,8 +1753,6 @@ err_out:
err_wq:
mlx5e_macsec_aso_cleanup(&macsec->aso, priv->mdev);
err_aso:
- rhashtable_destroy(&macsec->sci_hash);
-err_hash:
kfree(macsec);
priv->macsec = NULL;
return err;
@@ -1858,10 +1767,9 @@ void mlx5e_macsec_cleanup(struct mlx5e_priv *priv)
return;
mlx5_notifier_unregister(mdev, &macsec->nb);
- mlx5e_macsec_fs_cleanup(macsec->macsec_fs);
+ mlx5_macsec_fs_cleanup(mdev->macsec_fs);
destroy_workqueue(macsec->wq);
mlx5e_macsec_aso_cleanup(&macsec->aso, mdev);
- rhashtable_destroy(&macsec->sci_hash);
mutex_destroy(&macsec->lock);
kfree(macsec);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
index 347380a2cd9c..27df72e23106 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
@@ -4,32 +4,16 @@
#ifndef __MLX5_EN_ACCEL_MACSEC_H__
#define __MLX5_EN_ACCEL_MACSEC_H__
-#ifdef CONFIG_MLX5_EN_MACSEC
+#ifdef CONFIG_MLX5_MACSEC
#include <linux/mlx5/driver.h>
#include <net/macsec.h>
#include <net/dst_metadata.h>
-
-/* Bit31 - 30: MACsec marker, Bit15-0: MACsec id */
-#define MLX5_MACEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */
-#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACEC_RX_FS_ID_MAX
-#define MLX5_MACSEC_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x1)
-#define MLX5_MACSEC_RX_METADAT_HANDLE(metadata) ((metadata) & MLX5_MACSEC_RX_FS_ID_MASK)
+#include "lib/macsec_fs.h"
struct mlx5e_priv;
struct mlx5e_macsec;
-struct mlx5e_macsec_stats {
- u64 macsec_rx_pkts;
- u64 macsec_rx_bytes;
- u64 macsec_rx_pkts_drop;
- u64 macsec_rx_bytes_drop;
- u64 macsec_tx_pkts;
- u64 macsec_tx_bytes;
- u64 macsec_tx_pkts_drop;
- u64 macsec_tx_bytes_drop;
-};
-
void mlx5e_macsec_build_netdev(struct mlx5e_priv *priv);
int mlx5e_macsec_init(struct mlx5e_priv *priv);
void mlx5e_macsec_cleanup(struct mlx5e_priv *priv);
@@ -52,9 +36,6 @@ static inline bool mlx5e_macsec_is_rx_flow(struct mlx5_cqe64 *cqe)
void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
struct mlx5_cqe64 *cqe);
-bool mlx5e_is_macsec_device(const struct mlx5_core_dev *mdev);
-void mlx5e_macsec_get_stats_fill(struct mlx5e_macsec *macsec, void *macsec_stats);
-struct mlx5e_macsec_stats *mlx5e_macsec_get_stats(struct mlx5e_macsec *macsec);
#else
@@ -67,7 +48,6 @@ static inline void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
struct mlx5_cqe64 *cqe)
{}
-static inline bool mlx5e_is_macsec_device(const struct mlx5_core_dev *mdev) { return false; }
-#endif /* CONFIG_MLX5_EN_MACSEC */
+#endif /* CONFIG_MLX5_MACSEC */
#endif /* __MLX5_ACCEL_EN_MACSEC_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c
deleted file mode 100644
index 414e28584881..000000000000
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c
+++ /dev/null
@@ -1,1394 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
-/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
-
-#include <net/macsec.h>
-#include <linux/netdevice.h>
-#include <linux/mlx5/qp.h>
-#include <linux/if_vlan.h>
-#include "fs_core.h"
-#include "en/fs.h"
-#include "en_accel/macsec_fs.h"
-#include "mlx5_core.h"
-
-/* MACsec TX flow steering */
-#define CRYPTO_NUM_MAXSEC_FTE BIT(15)
-#define CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE 1
-
-#define TX_CRYPTO_TABLE_LEVEL 0
-#define TX_CRYPTO_TABLE_NUM_GROUPS 3
-#define TX_CRYPTO_TABLE_MKE_GROUP_SIZE 1
-#define TX_CRYPTO_TABLE_SA_GROUP_SIZE \
- (CRYPTO_NUM_MAXSEC_FTE - (TX_CRYPTO_TABLE_MKE_GROUP_SIZE + \
- CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE))
-#define TX_CHECK_TABLE_LEVEL 1
-#define TX_CHECK_TABLE_NUM_FTE 2
-#define RX_CRYPTO_TABLE_LEVEL 0
-#define RX_CHECK_TABLE_LEVEL 1
-#define RX_CHECK_TABLE_NUM_FTE 3
-#define RX_CRYPTO_TABLE_NUM_GROUPS 3
-#define RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE \
- ((CRYPTO_NUM_MAXSEC_FTE - CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE) / 2)
-#define RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE \
- (CRYPTO_NUM_MAXSEC_FTE - RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE)
-#define RX_NUM_OF_RULES_PER_SA 2
-
-#define MLX5_MACSEC_TAG_LEN 8 /* SecTAG length with ethertype and without the optional SCI */
-#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK 0x23
-#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET 0x8
-#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET 0x5
-#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT (0x1 << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET)
-#define MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI 0x8
-#define MLX5_SECTAG_HEADER_SIZE_WITH_SCI (MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI + MACSEC_SCI_LEN)
-
-/* MACsec RX flow steering */
-#define MLX5_ETH_WQE_FT_META_MACSEC_MASK 0x3E
-
-struct mlx5_sectag_header {
- __be16 ethertype;
- u8 tci_an;
- u8 sl;
- u32 pn;
- u8 sci[MACSEC_SCI_LEN]; /* optional */
-} __packed;
-
-struct mlx5e_macsec_tx_rule {
- struct mlx5_flow_handle *rule;
- struct mlx5_pkt_reformat *pkt_reformat;
- u32 fs_id;
-};
-
-struct mlx5e_macsec_tables {
- struct mlx5e_flow_table ft_crypto;
- struct mlx5_flow_handle *crypto_miss_rule;
-
- struct mlx5_flow_table *ft_check;
- struct mlx5_flow_group *ft_check_group;
- struct mlx5_fc *check_miss_rule_counter;
- struct mlx5_flow_handle *check_miss_rule;
- struct mlx5_fc *check_rule_counter;
-
- u32 refcnt;
-};
-
-struct mlx5e_macsec_tx {
- struct mlx5_flow_handle *crypto_mke_rule;
- struct mlx5_flow_handle *check_rule;
-
- struct ida tx_halloc;
-
- struct mlx5e_macsec_tables tables;
-};
-
-struct mlx5e_macsec_rx_rule {
- struct mlx5_flow_handle *rule[RX_NUM_OF_RULES_PER_SA];
- struct mlx5_modify_hdr *meta_modhdr;
-};
-
-struct mlx5e_macsec_rx {
- struct mlx5_flow_handle *check_rule[2];
- struct mlx5_pkt_reformat *check_rule_pkt_reformat[2];
-
- struct mlx5e_macsec_tables tables;
-};
-
-union mlx5e_macsec_rule {
- struct mlx5e_macsec_tx_rule tx_rule;
- struct mlx5e_macsec_rx_rule rx_rule;
-};
-
-struct mlx5e_macsec_fs {
- struct mlx5_core_dev *mdev;
- struct net_device *netdev;
- struct mlx5e_macsec_tx *tx_fs;
- struct mlx5e_macsec_rx *rx_fs;
-};
-
-static void macsec_fs_tx_destroy(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- struct mlx5e_macsec_tables *tx_tables;
-
- tx_tables = &tx_fs->tables;
-
- /* Tx check table */
- if (tx_fs->check_rule) {
- mlx5_del_flow_rules(tx_fs->check_rule);
- tx_fs->check_rule = NULL;
- }
-
- if (tx_tables->check_miss_rule) {
- mlx5_del_flow_rules(tx_tables->check_miss_rule);
- tx_tables->check_miss_rule = NULL;
- }
-
- if (tx_tables->ft_check_group) {
- mlx5_destroy_flow_group(tx_tables->ft_check_group);
- tx_tables->ft_check_group = NULL;
- }
-
- if (tx_tables->ft_check) {
- mlx5_destroy_flow_table(tx_tables->ft_check);
- tx_tables->ft_check = NULL;
- }
-
- /* Tx crypto table */
- if (tx_fs->crypto_mke_rule) {
- mlx5_del_flow_rules(tx_fs->crypto_mke_rule);
- tx_fs->crypto_mke_rule = NULL;
- }
-
- if (tx_tables->crypto_miss_rule) {
- mlx5_del_flow_rules(tx_tables->crypto_miss_rule);
- tx_tables->crypto_miss_rule = NULL;
- }
-
- mlx5e_destroy_flow_table(&tx_tables->ft_crypto);
-}
-
-static int macsec_fs_tx_create_crypto_table_groups(struct mlx5e_flow_table *ft)
-{
- int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
- int mclen = MLX5_ST_SZ_BYTES(fte_match_param);
- int ix = 0;
- u32 *in;
- int err;
- u8 *mc;
-
- ft->g = kcalloc(TX_CRYPTO_TABLE_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
- if (!ft->g)
- return -ENOMEM;
- in = kvzalloc(inlen, GFP_KERNEL);
-
- if (!in) {
- kfree(ft->g);
- ft->g = NULL;
- return -ENOMEM;
- }
-
- mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
-
- /* Flow Group for MKE match */
- MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
- MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
-
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += TX_CRYPTO_TABLE_MKE_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- /* Flow Group for SA rules */
- memset(in, 0, inlen);
- memset(mc, 0, mclen);
- MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS_2);
- MLX5_SET(fte_match_param, mc, misc_parameters_2.metadata_reg_a,
- MLX5_ETH_WQE_FT_META_MACSEC_MASK);
-
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += TX_CRYPTO_TABLE_SA_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- /* Flow Group for l2 traps */
- memset(in, 0, inlen);
- memset(mc, 0, mclen);
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- kvfree(in);
- return 0;
-
-err:
- err = PTR_ERR(ft->g[ft->num_groups]);
- ft->g[ft->num_groups] = NULL;
- kvfree(in);
-
- return err;
-}
-
-static struct mlx5_flow_table
- *macsec_fs_auto_group_table_create(struct mlx5_flow_namespace *ns, int flags,
- int level, int max_fte)
-{
- struct mlx5_flow_table_attr ft_attr = {};
- struct mlx5_flow_table *fdb = NULL;
-
- /* reserve entry for the match all miss group and rule */
- ft_attr.autogroup.num_reserved_entries = 1;
- ft_attr.autogroup.max_num_groups = 1;
- ft_attr.prio = 0;
- ft_attr.flags = flags;
- ft_attr.level = level;
- ft_attr.max_fte = max_fte;
-
- fdb = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
-
- return fdb;
-}
-
-static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs)
-{
- int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- struct net_device *netdev = macsec_fs->netdev;
- struct mlx5_flow_table_attr ft_attr = {};
- struct mlx5_flow_destination dest = {};
- struct mlx5e_macsec_tables *tx_tables;
- struct mlx5_flow_act flow_act = {};
- struct mlx5e_flow_table *ft_crypto;
- struct mlx5_flow_table *flow_table;
- struct mlx5_flow_group *flow_group;
- struct mlx5_flow_namespace *ns;
- struct mlx5_flow_handle *rule;
- struct mlx5_flow_spec *spec;
- u32 *flow_group_in;
- int err;
-
- ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_EGRESS_MACSEC);
- if (!ns)
- return -ENOMEM;
-
- spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
-
- flow_group_in = kvzalloc(inlen, GFP_KERNEL);
- if (!flow_group_in) {
- err = -ENOMEM;
- goto out_spec;
- }
-
- tx_tables = &tx_fs->tables;
- ft_crypto = &tx_tables->ft_crypto;
-
- /* Tx crypto table */
- ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
- ft_attr.level = TX_CRYPTO_TABLE_LEVEL;
- ft_attr.max_fte = CRYPTO_NUM_MAXSEC_FTE;
-
- flow_table = mlx5_create_flow_table(ns, &ft_attr);
- if (IS_ERR(flow_table)) {
- err = PTR_ERR(flow_table);
- netdev_err(netdev, "Failed to create MACsec Tx crypto table err(%d)\n", err);
- goto out_flow_group;
- }
- ft_crypto->t = flow_table;
-
- /* Tx crypto table groups */
- err = macsec_fs_tx_create_crypto_table_groups(ft_crypto);
- if (err) {
- netdev_err(netdev,
- "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
- err);
- goto err;
- }
-
- /* Tx crypto table MKE rule - MKE packets shouldn't be offloaded */
- spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
-
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
- MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ETH_P_PAE);
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
-
- rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, NULL, 0);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to add MACsec TX MKE rule, err=%d\n", err);
- goto err;
- }
- tx_fs->crypto_mke_rule = rule;
-
- /* Tx crypto table Default miss rule */
- memset(&flow_act, 0, sizeof(flow_act));
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
- rule = mlx5_add_flow_rules(ft_crypto->t, NULL, &flow_act, NULL, 0);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to add MACsec Tx table default miss rule %d\n", err);
- goto err;
- }
- tx_tables->crypto_miss_rule = rule;
-
- /* Tx check table */
- flow_table = macsec_fs_auto_group_table_create(ns, 0, TX_CHECK_TABLE_LEVEL,
- TX_CHECK_TABLE_NUM_FTE);
- if (IS_ERR(flow_table)) {
- err = PTR_ERR(flow_table);
- netdev_err(netdev, "fail to create MACsec TX check table, err(%d)\n", err);
- goto err;
- }
- tx_tables->ft_check = flow_table;
-
- /* Tx check table Default miss group/rule */
- memset(flow_group_in, 0, inlen);
- MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1);
- MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1);
- flow_group = mlx5_create_flow_group(tx_tables->ft_check, flow_group_in);
- if (IS_ERR(flow_group)) {
- err = PTR_ERR(flow_group);
- netdev_err(netdev,
- "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
- err);
- goto err;
- }
- tx_tables->ft_check_group = flow_group;
-
- /* Tx check table default drop rule */
- memset(&dest, 0, sizeof(struct mlx5_flow_destination));
- memset(&flow_act, 0, sizeof(flow_act));
- dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest.counter_id = mlx5_fc_id(tx_tables->check_miss_rule_counter);
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
- rule = mlx5_add_flow_rules(tx_tables->ft_check, NULL, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to added MACsec tx check drop rule, err(%d)\n", err);
- goto err;
- }
- tx_tables->check_miss_rule = rule;
-
- /* Tx check table rule */
- memset(spec, 0, sizeof(struct mlx5_flow_spec));
- memset(&dest, 0, sizeof(struct mlx5_flow_destination));
- memset(&flow_act, 0, sizeof(flow_act));
-
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 0);
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
-
- flow_act.flags = FLOW_ACT_NO_APPEND;
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW | MLX5_FLOW_CONTEXT_ACTION_COUNT;
- dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest.counter_id = mlx5_fc_id(tx_tables->check_rule_counter);
- rule = mlx5_add_flow_rules(tx_tables->ft_check, spec, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to add MACsec check rule, err=%d\n", err);
- goto err;
- }
- tx_fs->check_rule = rule;
-
- goto out_flow_group;
-
-err:
- macsec_fs_tx_destroy(macsec_fs);
-out_flow_group:
- kvfree(flow_group_in);
-out_spec:
- kvfree(spec);
- return err;
-}
-
-static int macsec_fs_tx_ft_get(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- struct mlx5e_macsec_tables *tx_tables;
- int err = 0;
-
- tx_tables = &tx_fs->tables;
- if (tx_tables->refcnt)
- goto out;
-
- err = macsec_fs_tx_create(macsec_fs);
- if (err)
- return err;
-
-out:
- tx_tables->refcnt++;
- return err;
-}
-
-static void macsec_fs_tx_ft_put(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tables *tx_tables = &macsec_fs->tx_fs->tables;
-
- if (--tx_tables->refcnt)
- return;
-
- macsec_fs_tx_destroy(macsec_fs);
-}
-
-static int macsec_fs_tx_setup_fte(struct mlx5e_macsec_fs *macsec_fs,
- struct mlx5_flow_spec *spec,
- struct mlx5_flow_act *flow_act,
- u32 macsec_obj_id,
- u32 *fs_id)
-{
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- int err = 0;
- u32 id;
-
- err = ida_alloc_range(&tx_fs->tx_halloc, 1,
- MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES,
- GFP_KERNEL);
- if (err < 0)
- return err;
-
- id = err;
- spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
-
- /* Metadata match */
- MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_a,
- MLX5_ETH_WQE_FT_META_MACSEC_MASK);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_a,
- MLX5_ETH_WQE_FT_META_MACSEC | id << 2);
-
- *fs_id = id;
- flow_act->crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_MACSEC;
- flow_act->crypto.obj_id = macsec_obj_id;
-
- mlx5_core_dbg(macsec_fs->mdev, "Tx fte: macsec obj_id %u, fs_id %u\n", macsec_obj_id, id);
- return 0;
-}
-
-static void macsec_fs_tx_create_sectag_header(const struct macsec_context *ctx,
- char *reformatbf,
- size_t *reformat_size)
-{
- const struct macsec_secy *secy = ctx->secy;
- bool sci_present = macsec_send_sci(secy);
- struct mlx5_sectag_header sectag = {};
- const struct macsec_tx_sc *tx_sc;
-
- tx_sc = &secy->tx_sc;
- sectag.ethertype = htons(ETH_P_MACSEC);
-
- if (sci_present) {
- sectag.tci_an |= MACSEC_TCI_SC;
- memcpy(&sectag.sci, &secy->sci,
- sizeof(sectag.sci));
- } else {
- if (tx_sc->end_station)
- sectag.tci_an |= MACSEC_TCI_ES;
- if (tx_sc->scb)
- sectag.tci_an |= MACSEC_TCI_SCB;
- }
-
- /* With GCM, C/E clear for !encrypt, both set for encrypt */
- if (tx_sc->encrypt)
- sectag.tci_an |= MACSEC_TCI_CONFID;
- else if (secy->icv_len != MACSEC_DEFAULT_ICV_LEN)
- sectag.tci_an |= MACSEC_TCI_C;
-
- sectag.tci_an |= tx_sc->encoding_sa;
-
- *reformat_size = MLX5_MACSEC_TAG_LEN + (sci_present ? MACSEC_SCI_LEN : 0);
-
- memcpy(reformatbf, &sectag, *reformat_size);
-}
-
-static void macsec_fs_tx_del_rule(struct mlx5e_macsec_fs *macsec_fs,
- struct mlx5e_macsec_tx_rule *tx_rule)
-{
- if (tx_rule->rule) {
- mlx5_del_flow_rules(tx_rule->rule);
- tx_rule->rule = NULL;
- }
-
- if (tx_rule->pkt_reformat) {
- mlx5_packet_reformat_dealloc(macsec_fs->mdev, tx_rule->pkt_reformat);
- tx_rule->pkt_reformat = NULL;
- }
-
- if (tx_rule->fs_id) {
- ida_free(&macsec_fs->tx_fs->tx_halloc, tx_rule->fs_id);
- tx_rule->fs_id = 0;
- }
-
- kfree(tx_rule);
-
- macsec_fs_tx_ft_put(macsec_fs);
-}
-
-#define MLX5_REFORMAT_PARAM_ADD_MACSEC_OFFSET_4_BYTES 1
-
-static union mlx5e_macsec_rule *
-macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs,
- const struct macsec_context *macsec_ctx,
- struct mlx5_macsec_rule_attrs *attrs,
- u32 *sa_fs_id)
-{
- char reformatbf[MLX5_MACSEC_TAG_LEN + MACSEC_SCI_LEN];
- struct mlx5_pkt_reformat_params reformat_params = {};
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- struct net_device *netdev = macsec_fs->netdev;
- union mlx5e_macsec_rule *macsec_rule = NULL;
- struct mlx5_flow_destination dest = {};
- struct mlx5e_macsec_tables *tx_tables;
- struct mlx5e_macsec_tx_rule *tx_rule;
- struct mlx5_flow_act flow_act = {};
- struct mlx5_flow_handle *rule;
- struct mlx5_flow_spec *spec;
- size_t reformat_size;
- int err = 0;
- u32 fs_id;
-
- tx_tables = &tx_fs->tables;
-
- spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return NULL;
-
- err = macsec_fs_tx_ft_get(macsec_fs);
- if (err)
- goto out_spec;
-
- macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL);
- if (!macsec_rule) {
- macsec_fs_tx_ft_put(macsec_fs);
- goto out_spec;
- }
-
- tx_rule = &macsec_rule->tx_rule;
-
- /* Tx crypto table crypto rule */
- macsec_fs_tx_create_sectag_header(macsec_ctx, reformatbf, &reformat_size);
-
- reformat_params.type = MLX5_REFORMAT_TYPE_ADD_MACSEC;
- reformat_params.size = reformat_size;
- reformat_params.data = reformatbf;
-
- if (is_vlan_dev(macsec_ctx->netdev))
- reformat_params.param_0 = MLX5_REFORMAT_PARAM_ADD_MACSEC_OFFSET_4_BYTES;
-
- flow_act.pkt_reformat = mlx5_packet_reformat_alloc(macsec_fs->mdev,
- &reformat_params,
- MLX5_FLOW_NAMESPACE_EGRESS_MACSEC);
- if (IS_ERR(flow_act.pkt_reformat)) {
- err = PTR_ERR(flow_act.pkt_reformat);
- netdev_err(netdev, "Failed to allocate MACsec Tx reformat context err=%d\n", err);
- goto err;
- }
- tx_rule->pkt_reformat = flow_act.pkt_reformat;
-
- err = macsec_fs_tx_setup_fte(macsec_fs, spec, &flow_act, attrs->macsec_obj_id, &fs_id);
- if (err) {
- netdev_err(netdev,
- "Failed to add packet reformat for MACsec TX crypto rule, err=%d\n",
- err);
- goto err;
- }
-
- tx_rule->fs_id = fs_id;
- *sa_fs_id = fs_id;
-
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
- MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT |
- MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
- dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest.ft = tx_tables->ft_check;
- rule = mlx5_add_flow_rules(tx_tables->ft_crypto.t, spec, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to add MACsec TX crypto rule, err=%d\n", err);
- goto err;
- }
- tx_rule->rule = rule;
-
- goto out_spec;
-
-err:
- macsec_fs_tx_del_rule(macsec_fs, tx_rule);
- macsec_rule = NULL;
-out_spec:
- kvfree(spec);
-
- return macsec_rule;
-}
-
-static void macsec_fs_tx_cleanup(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs;
- struct mlx5_core_dev *mdev = macsec_fs->mdev;
- struct mlx5e_macsec_tables *tx_tables;
-
- if (!tx_fs)
- return;
-
- tx_tables = &tx_fs->tables;
- if (tx_tables->refcnt) {
- netdev_err(macsec_fs->netdev,
- "Can't destroy MACsec offload tx_fs, refcnt(%u) isn't 0\n",
- tx_tables->refcnt);
- return;
- }
-
- ida_destroy(&tx_fs->tx_halloc);
-
- if (tx_tables->check_miss_rule_counter) {
- mlx5_fc_destroy(mdev, tx_tables->check_miss_rule_counter);
- tx_tables->check_miss_rule_counter = NULL;
- }
-
- if (tx_tables->check_rule_counter) {
- mlx5_fc_destroy(mdev, tx_tables->check_rule_counter);
- tx_tables->check_rule_counter = NULL;
- }
-
- kfree(tx_fs);
- macsec_fs->tx_fs = NULL;
-}
-
-static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct net_device *netdev = macsec_fs->netdev;
- struct mlx5_core_dev *mdev = macsec_fs->mdev;
- struct mlx5e_macsec_tables *tx_tables;
- struct mlx5e_macsec_tx *tx_fs;
- struct mlx5_fc *flow_counter;
- int err;
-
- tx_fs = kzalloc(sizeof(*tx_fs), GFP_KERNEL);
- if (!tx_fs)
- return -ENOMEM;
-
- tx_tables = &tx_fs->tables;
-
- flow_counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(flow_counter)) {
- err = PTR_ERR(flow_counter);
- netdev_err(netdev,
- "Failed to create MACsec Tx encrypt flow counter, err(%d)\n",
- err);
- goto err_encrypt_counter;
- }
- tx_tables->check_rule_counter = flow_counter;
-
- flow_counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(flow_counter)) {
- err = PTR_ERR(flow_counter);
- netdev_err(netdev,
- "Failed to create MACsec Tx drop flow counter, err(%d)\n",
- err);
- goto err_drop_counter;
- }
- tx_tables->check_miss_rule_counter = flow_counter;
-
- ida_init(&tx_fs->tx_halloc);
-
- macsec_fs->tx_fs = tx_fs;
-
- return 0;
-
-err_drop_counter:
- mlx5_fc_destroy(mdev, tx_tables->check_rule_counter);
- tx_tables->check_rule_counter = NULL;
-
-err_encrypt_counter:
- kfree(tx_fs);
- macsec_fs->tx_fs = NULL;
-
- return err;
-}
-
-static void macsec_fs_rx_destroy(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs;
- struct mlx5e_macsec_tables *rx_tables;
- int i;
-
- /* Rx check table */
- for (i = 1; i >= 0; --i) {
- if (rx_fs->check_rule[i]) {
- mlx5_del_flow_rules(rx_fs->check_rule[i]);
- rx_fs->check_rule[i] = NULL;
- }
-
- if (rx_fs->check_rule_pkt_reformat[i]) {
- mlx5_packet_reformat_dealloc(macsec_fs->mdev,
- rx_fs->check_rule_pkt_reformat[i]);
- rx_fs->check_rule_pkt_reformat[i] = NULL;
- }
- }
-
- rx_tables = &rx_fs->tables;
-
- if (rx_tables->check_miss_rule) {
- mlx5_del_flow_rules(rx_tables->check_miss_rule);
- rx_tables->check_miss_rule = NULL;
- }
-
- if (rx_tables->ft_check_group) {
- mlx5_destroy_flow_group(rx_tables->ft_check_group);
- rx_tables->ft_check_group = NULL;
- }
-
- if (rx_tables->ft_check) {
- mlx5_destroy_flow_table(rx_tables->ft_check);
- rx_tables->ft_check = NULL;
- }
-
- /* Rx crypto table */
- if (rx_tables->crypto_miss_rule) {
- mlx5_del_flow_rules(rx_tables->crypto_miss_rule);
- rx_tables->crypto_miss_rule = NULL;
- }
-
- mlx5e_destroy_flow_table(&rx_tables->ft_crypto);
-}
-
-static int macsec_fs_rx_create_crypto_table_groups(struct mlx5e_flow_table *ft)
-{
- int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
- int mclen = MLX5_ST_SZ_BYTES(fte_match_param);
- int ix = 0;
- u32 *in;
- int err;
- u8 *mc;
-
- ft->g = kcalloc(RX_CRYPTO_TABLE_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
- if (!ft->g)
- return -ENOMEM;
-
- in = kvzalloc(inlen, GFP_KERNEL);
- if (!in) {
- kfree(ft->g);
- return -ENOMEM;
- }
-
- mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
-
- /* Flow group for SA rule with SCI */
- MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS |
- MLX5_MATCH_MISC_PARAMETERS_5);
- MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
-
- MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0,
- MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK <<
- MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
- MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_2);
- MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_3);
-
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- /* Flow group for SA rule without SCI */
- memset(in, 0, inlen);
- memset(mc, 0, mclen);
- MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS |
- MLX5_MATCH_MISC_PARAMETERS_5);
- MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_47_16);
- MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_15_0);
- MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
-
- MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0,
- MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
-
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- /* Flow Group for l2 traps */
- memset(in, 0, inlen);
- memset(mc, 0, mclen);
- MLX5_SET_CFG(in, start_flow_index, ix);
- ix += CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE;
- MLX5_SET_CFG(in, end_flow_index, ix - 1);
- ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
- if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
- ft->num_groups++;
-
- kvfree(in);
- return 0;
-
-err:
- err = PTR_ERR(ft->g[ft->num_groups]);
- ft->g[ft->num_groups] = NULL;
- kvfree(in);
-
- return err;
-}
-
-static int macsec_fs_rx_create_check_decap_rule(struct mlx5e_macsec_fs *macsec_fs,
- struct mlx5_flow_destination *dest,
- struct mlx5_flow_act *flow_act,
- struct mlx5_flow_spec *spec,
- int reformat_param_size)
-{
- int rule_index = (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI) ? 0 : 1;
- u8 mlx5_reformat_buf[MLX5_SECTAG_HEADER_SIZE_WITH_SCI];
- struct mlx5_pkt_reformat_params reformat_params = {};
- struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs;
- struct net_device *netdev = macsec_fs->netdev;
- struct mlx5e_macsec_tables *rx_tables;
- struct mlx5_flow_handle *rule;
- int err = 0;
-
- rx_tables = &rx_fs->tables;
-
- /* Rx check table decap 16B rule */
- memset(dest, 0, sizeof(*dest));
- memset(flow_act, 0, sizeof(*flow_act));
- memset(spec, 0, sizeof(*spec));
-
- reformat_params.type = MLX5_REFORMAT_TYPE_DEL_MACSEC;
- reformat_params.size = reformat_param_size;
- reformat_params.data = mlx5_reformat_buf;
- flow_act->pkt_reformat = mlx5_packet_reformat_alloc(macsec_fs->mdev,
- &reformat_params,
- MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
- if (IS_ERR(flow_act->pkt_reformat)) {
- err = PTR_ERR(flow_act->pkt_reformat);
- netdev_err(netdev, "Failed to allocate MACsec Rx reformat context err=%d\n", err);
- return err;
- }
- rx_fs->check_rule_pkt_reformat[rule_index] = flow_act->pkt_reformat;
-
- spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
- /* MACsec syndrome match */
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.macsec_syndrome);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.macsec_syndrome, 0);
- /* ASO return reg syndrome match */
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 0);
-
- spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5;
- /* Sectag TCI SC present bit*/
- MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0,
- MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
-
- if (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI)
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0,
- MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT <<
- MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
-
- flow_act->flags = FLOW_ACT_NO_APPEND;
- flow_act->action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO |
- MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
- MLX5_FLOW_CONTEXT_ACTION_COUNT;
- dest->type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest->counter_id = mlx5_fc_id(rx_tables->check_rule_counter);
- rule = mlx5_add_flow_rules(rx_tables->ft_check, spec, flow_act, dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to add MACsec Rx check rule, err=%d\n", err);
- return err;
- }
-
- rx_fs->check_rule[rule_index] = rule;
-
- return 0;
-}
-
-static int macsec_fs_rx_create(struct mlx5e_macsec_fs *macsec_fs)
-{
- int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
- struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs;
- struct net_device *netdev = macsec_fs->netdev;
- struct mlx5_flow_table_attr ft_attr = {};
- struct mlx5_flow_destination dest = {};
- struct mlx5e_macsec_tables *rx_tables;
- struct mlx5e_flow_table *ft_crypto;
- struct mlx5_flow_table *flow_table;
- struct mlx5_flow_group *flow_group;
- struct mlx5_flow_act flow_act = {};
- struct mlx5_flow_namespace *ns;
- struct mlx5_flow_handle *rule;
- struct mlx5_flow_spec *spec;
- u32 *flow_group_in;
- int err;
-
- ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
- if (!ns)
- return -ENOMEM;
-
- spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
-
- flow_group_in = kvzalloc(inlen, GFP_KERNEL);
- if (!flow_group_in) {
- err = -ENOMEM;
- goto free_spec;
- }
-
- rx_tables = &rx_fs->tables;
- ft_crypto = &rx_tables->ft_crypto;
-
- /* Rx crypto table */
- ft_attr.level = RX_CRYPTO_TABLE_LEVEL;
- ft_attr.max_fte = CRYPTO_NUM_MAXSEC_FTE;
-
- flow_table = mlx5_create_flow_table(ns, &ft_attr);
- if (IS_ERR(flow_table)) {
- err = PTR_ERR(flow_table);
- netdev_err(netdev, "Failed to create MACsec Rx crypto table err(%d)\n", err);
- goto out_flow_group;
- }
- ft_crypto->t = flow_table;
-
- /* Rx crypto table groups */
- err = macsec_fs_rx_create_crypto_table_groups(ft_crypto);
- if (err) {
- netdev_err(netdev,
- "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
- err);
- goto err;
- }
-
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
- rule = mlx5_add_flow_rules(ft_crypto->t, NULL, &flow_act, NULL, 0);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev,
- "Failed to add MACsec Rx crypto table default miss rule %d\n",
- err);
- goto err;
- }
- rx_tables->crypto_miss_rule = rule;
-
- /* Rx check table */
- flow_table = macsec_fs_auto_group_table_create(ns,
- MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT,
- RX_CHECK_TABLE_LEVEL,
- RX_CHECK_TABLE_NUM_FTE);
- if (IS_ERR(flow_table)) {
- err = PTR_ERR(flow_table);
- netdev_err(netdev, "fail to create MACsec RX check table, err(%d)\n", err);
- goto err;
- }
- rx_tables->ft_check = flow_table;
-
- /* Rx check table Default miss group/rule */
- MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1);
- MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1);
- flow_group = mlx5_create_flow_group(rx_tables->ft_check, flow_group_in);
- if (IS_ERR(flow_group)) {
- err = PTR_ERR(flow_group);
- netdev_err(netdev,
- "Failed to create default flow group for MACsec Rx check table err(%d)\n",
- err);
- goto err;
- }
- rx_tables->ft_check_group = flow_group;
-
- /* Rx check table default drop rule */
- memset(&flow_act, 0, sizeof(flow_act));
-
- dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
- dest.counter_id = mlx5_fc_id(rx_tables->check_miss_rule_counter);
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
- rule = mlx5_add_flow_rules(rx_tables->ft_check, NULL, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev, "Failed to added MACsec Rx check drop rule, err(%d)\n", err);
- goto err;
- }
- rx_tables->check_miss_rule = rule;
-
- /* Rx check table decap rules */
- err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec,
- MLX5_SECTAG_HEADER_SIZE_WITH_SCI);
- if (err)
- goto err;
-
- err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec,
- MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI);
- if (err)
- goto err;
-
- goto out_flow_group;
-
-err:
- macsec_fs_rx_destroy(macsec_fs);
-out_flow_group:
- kvfree(flow_group_in);
-free_spec:
- kvfree(spec);
- return err;
-}
-
-static int macsec_fs_rx_ft_get(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
- int err = 0;
-
- if (rx_tables->refcnt)
- goto out;
-
- err = macsec_fs_rx_create(macsec_fs);
- if (err)
- return err;
-
-out:
- rx_tables->refcnt++;
- return err;
-}
-
-static void macsec_fs_rx_ft_put(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
-
- if (--rx_tables->refcnt)
- return;
-
- macsec_fs_rx_destroy(macsec_fs);
-}
-
-static void macsec_fs_rx_del_rule(struct mlx5e_macsec_fs *macsec_fs,
- struct mlx5e_macsec_rx_rule *rx_rule)
-{
- int i;
-
- for (i = 0; i < RX_NUM_OF_RULES_PER_SA; ++i) {
- if (rx_rule->rule[i]) {
- mlx5_del_flow_rules(rx_rule->rule[i]);
- rx_rule->rule[i] = NULL;
- }
- }
-
- if (rx_rule->meta_modhdr) {
- mlx5_modify_header_dealloc(macsec_fs->mdev, rx_rule->meta_modhdr);
- rx_rule->meta_modhdr = NULL;
- }
-
- kfree(rx_rule);
-
- macsec_fs_rx_ft_put(macsec_fs);
-}
-
-static void macsec_fs_rx_setup_fte(struct mlx5_flow_spec *spec,
- struct mlx5_flow_act *flow_act,
- struct mlx5_macsec_rule_attrs *attrs,
- bool sci_present)
-{
- u8 tci_an = (sci_present << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET) | attrs->assoc_num;
- struct mlx5_flow_act_crypto_params *crypto_params = &flow_act->crypto;
- __be32 *sci_p = (__be32 *)(&attrs->sci);
-
- spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
-
- /* MACsec ethertype */
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
- MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ETH_P_MACSEC);
-
- spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5;
-
- /* Sectag AN + TCI SC present bit*/
- MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0,
- MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0,
- tci_an << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
-
- if (sci_present) {
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
- misc_parameters_5.macsec_tag_2);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_2,
- be32_to_cpu(sci_p[0]));
-
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
- misc_parameters_5.macsec_tag_3);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_3,
- be32_to_cpu(sci_p[1]));
- } else {
- /* When SCI isn't present in the Sectag, need to match the source */
- /* MAC address only if the SCI contains the default MACsec PORT */
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16);
- MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0);
- memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.smac_47_16),
- sci_p, ETH_ALEN);
- }
-
- crypto_params->type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_MACSEC;
- crypto_params->obj_id = attrs->macsec_obj_id;
-}
-
-static union mlx5e_macsec_rule *
-macsec_fs_rx_add_rule(struct mlx5e_macsec_fs *macsec_fs,
- struct mlx5_macsec_rule_attrs *attrs,
- u32 fs_id)
-{
- u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
- struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs;
- struct net_device *netdev = macsec_fs->netdev;
- union mlx5e_macsec_rule *macsec_rule = NULL;
- struct mlx5_modify_hdr *modify_hdr = NULL;
- struct mlx5_flow_destination dest = {};
- struct mlx5e_macsec_tables *rx_tables;
- struct mlx5e_macsec_rx_rule *rx_rule;
- struct mlx5_flow_act flow_act = {};
- struct mlx5e_flow_table *ft_crypto;
- struct mlx5_flow_handle *rule;
- struct mlx5_flow_spec *spec;
- int err = 0;
-
- spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return NULL;
-
- err = macsec_fs_rx_ft_get(macsec_fs);
- if (err)
- goto out_spec;
-
- macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL);
- if (!macsec_rule) {
- macsec_fs_rx_ft_put(macsec_fs);
- goto out_spec;
- }
-
- rx_rule = &macsec_rule->rx_rule;
- rx_tables = &rx_fs->tables;
- ft_crypto = &rx_tables->ft_crypto;
-
- /* Set bit[31 - 30] macsec marker - 0x01 */
- /* Set bit[15-0] fs id */
- MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
- MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
- MLX5_SET(set_action_in, action, data, MLX5_MACSEC_RX_METADAT_HANDLE(fs_id) | BIT(30));
- MLX5_SET(set_action_in, action, offset, 0);
- MLX5_SET(set_action_in, action, length, 32);
-
- modify_hdr = mlx5_modify_header_alloc(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC,
- 1, action);
- if (IS_ERR(modify_hdr)) {
- err = PTR_ERR(modify_hdr);
- netdev_err(netdev, "fail to alloc MACsec set modify_header_id err=%d\n", err);
- modify_hdr = NULL;
- goto err;
- }
- rx_rule->meta_modhdr = modify_hdr;
-
- /* Rx crypto table with SCI rule */
- macsec_fs_rx_setup_fte(spec, &flow_act, attrs, true);
-
- flow_act.modify_hdr = modify_hdr;
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
- MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
- MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
-
- dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest.ft = rx_tables->ft_check;
- rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev,
- "Failed to add SA with SCI rule to Rx crypto rule, err=%d\n",
- err);
- goto err;
- }
- rx_rule->rule[0] = rule;
-
- /* Rx crypto table without SCI rule */
- if ((cpu_to_be64((__force u64)attrs->sci) & 0xFFFF) == ntohs(MACSEC_PORT_ES)) {
- memset(spec, 0, sizeof(struct mlx5_flow_spec));
- memset(&dest, 0, sizeof(struct mlx5_flow_destination));
- memset(&flow_act, 0, sizeof(flow_act));
-
- macsec_fs_rx_setup_fte(spec, &flow_act, attrs, false);
-
- flow_act.modify_hdr = modify_hdr;
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
- MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
- MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
-
- dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
- dest.ft = rx_tables->ft_check;
- rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
- netdev_err(netdev,
- "Failed to add SA without SCI rule to Rx crypto rule, err=%d\n",
- err);
- goto err;
- }
- rx_rule->rule[1] = rule;
- }
-
- kvfree(spec);
- return macsec_rule;
-
-err:
- macsec_fs_rx_del_rule(macsec_fs, rx_rule);
- macsec_rule = NULL;
-out_spec:
- kvfree(spec);
- return macsec_rule;
-}
-
-static int macsec_fs_rx_init(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct net_device *netdev = macsec_fs->netdev;
- struct mlx5_core_dev *mdev = macsec_fs->mdev;
- struct mlx5e_macsec_tables *rx_tables;
- struct mlx5e_macsec_rx *rx_fs;
- struct mlx5_fc *flow_counter;
- int err;
-
- rx_fs = kzalloc(sizeof(*rx_fs), GFP_KERNEL);
- if (!rx_fs)
- return -ENOMEM;
-
- flow_counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(flow_counter)) {
- err = PTR_ERR(flow_counter);
- netdev_err(netdev,
- "Failed to create MACsec Rx encrypt flow counter, err(%d)\n",
- err);
- goto err_encrypt_counter;
- }
-
- rx_tables = &rx_fs->tables;
- rx_tables->check_rule_counter = flow_counter;
-
- flow_counter = mlx5_fc_create(mdev, false);
- if (IS_ERR(flow_counter)) {
- err = PTR_ERR(flow_counter);
- netdev_err(netdev,
- "Failed to create MACsec Rx drop flow counter, err(%d)\n",
- err);
- goto err_drop_counter;
- }
- rx_tables->check_miss_rule_counter = flow_counter;
-
- macsec_fs->rx_fs = rx_fs;
-
- return 0;
-
-err_drop_counter:
- mlx5_fc_destroy(mdev, rx_tables->check_rule_counter);
- rx_tables->check_rule_counter = NULL;
-
-err_encrypt_counter:
- kfree(rx_fs);
- macsec_fs->rx_fs = NULL;
-
- return err;
-}
-
-static void macsec_fs_rx_cleanup(struct mlx5e_macsec_fs *macsec_fs)
-{
- struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs;
- struct mlx5_core_dev *mdev = macsec_fs->mdev;
- struct mlx5e_macsec_tables *rx_tables;
-
- if (!rx_fs)
- return;
-
- rx_tables = &rx_fs->tables;
-
- if (rx_tables->refcnt) {
- netdev_err(macsec_fs->netdev,
- "Can't destroy MACsec offload rx_fs, refcnt(%u) isn't 0\n",
- rx_tables->refcnt);
- return;
- }
-
- if (rx_tables->check_miss_rule_counter) {
- mlx5_fc_destroy(mdev, rx_tables->check_miss_rule_counter);
- rx_tables->check_miss_rule_counter = NULL;
- }
-
- if (rx_tables->check_rule_counter) {
- mlx5_fc_destroy(mdev, rx_tables->check_rule_counter);
- rx_tables->check_rule_counter = NULL;
- }
-
- kfree(rx_fs);
- macsec_fs->rx_fs = NULL;
-}
-
-void mlx5e_macsec_fs_get_stats_fill(struct mlx5e_macsec_fs *macsec_fs, void *macsec_stats)
-{
- struct mlx5e_macsec_stats *stats = (struct mlx5e_macsec_stats *)macsec_stats;
- struct mlx5e_macsec_tables *tx_tables = &macsec_fs->tx_fs->tables;
- struct mlx5e_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
- struct mlx5_core_dev *mdev = macsec_fs->mdev;
-
- if (tx_tables->check_rule_counter)
- mlx5_fc_query(mdev, tx_tables->check_rule_counter,
- &stats->macsec_tx_pkts, &stats->macsec_tx_bytes);
-
- if (tx_tables->check_miss_rule_counter)
- mlx5_fc_query(mdev, tx_tables->check_miss_rule_counter,
- &stats->macsec_tx_pkts_drop, &stats->macsec_tx_bytes_drop);
-
- if (rx_tables->check_rule_counter)
- mlx5_fc_query(mdev, rx_tables->check_rule_counter,
- &stats->macsec_rx_pkts, &stats->macsec_rx_bytes);
-
- if (rx_tables->check_miss_rule_counter)
- mlx5_fc_query(mdev, rx_tables->check_miss_rule_counter,
- &stats->macsec_rx_pkts_drop, &stats->macsec_rx_bytes_drop);
-}
-
-union mlx5e_macsec_rule *
-mlx5e_macsec_fs_add_rule(struct mlx5e_macsec_fs *macsec_fs,
- const struct macsec_context *macsec_ctx,
- struct mlx5_macsec_rule_attrs *attrs,
- u32 *sa_fs_id)
-{
- return (attrs->action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ?
- macsec_fs_tx_add_rule(macsec_fs, macsec_ctx, attrs, sa_fs_id) :
- macsec_fs_rx_add_rule(macsec_fs, attrs, *sa_fs_id);
-}
-
-void mlx5e_macsec_fs_del_rule(struct mlx5e_macsec_fs *macsec_fs,
- union mlx5e_macsec_rule *macsec_rule,
- int action)
-{
- (action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ?
- macsec_fs_tx_del_rule(macsec_fs, &macsec_rule->tx_rule) :
- macsec_fs_rx_del_rule(macsec_fs, &macsec_rule->rx_rule);
-}
-
-void mlx5e_macsec_fs_cleanup(struct mlx5e_macsec_fs *macsec_fs)
-{
- macsec_fs_rx_cleanup(macsec_fs);
- macsec_fs_tx_cleanup(macsec_fs);
- kfree(macsec_fs);
-}
-
-struct mlx5e_macsec_fs *
-mlx5e_macsec_fs_init(struct mlx5_core_dev *mdev,
- struct net_device *netdev)
-{
- struct mlx5e_macsec_fs *macsec_fs;
- int err;
-
- macsec_fs = kzalloc(sizeof(*macsec_fs), GFP_KERNEL);
- if (!macsec_fs)
- return NULL;
-
- macsec_fs->mdev = mdev;
- macsec_fs->netdev = netdev;
-
- err = macsec_fs_tx_init(macsec_fs);
- if (err) {
- netdev_err(netdev, "MACsec offload: Failed to init tx_fs, err=%d\n", err);
- goto err;
- }
-
- err = macsec_fs_rx_init(macsec_fs);
- if (err) {
- netdev_err(netdev, "MACsec offload: Failed to init tx_fs, err=%d\n", err);
- goto tx_cleanup;
- }
-
- return macsec_fs;
-
-tx_cleanup:
- macsec_fs_tx_cleanup(macsec_fs);
-err:
- kfree(macsec_fs);
- return NULL;
-}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h
deleted file mode 100644
index b429648d4ee7..000000000000
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
-/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
-
-#ifndef __MLX5_MACSEC_STEERING_H__
-#define __MLX5_MACSEC_STEERING_H__
-
-#ifdef CONFIG_MLX5_EN_MACSEC
-
-#include "en_accel/macsec.h"
-
-#define MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES 16
-
-struct mlx5e_macsec_fs;
-union mlx5e_macsec_rule;
-
-struct mlx5_macsec_rule_attrs {
- sci_t sci;
- u32 macsec_obj_id;
- u8 assoc_num;
- int action;
-};
-
-enum mlx5_macsec_action {
- MLX5_ACCEL_MACSEC_ACTION_ENCRYPT,
- MLX5_ACCEL_MACSEC_ACTION_DECRYPT,
-};
-
-void mlx5e_macsec_fs_cleanup(struct mlx5e_macsec_fs *macsec_fs);
-
-struct mlx5e_macsec_fs *
-mlx5e_macsec_fs_init(struct mlx5_core_dev *mdev, struct net_device *netdev);
-
-union mlx5e_macsec_rule *
-mlx5e_macsec_fs_add_rule(struct mlx5e_macsec_fs *macsec_fs,
- const struct macsec_context *ctx,
- struct mlx5_macsec_rule_attrs *attrs,
- u32 *sa_fs_id);
-
-void mlx5e_macsec_fs_del_rule(struct mlx5e_macsec_fs *macsec_fs,
- union mlx5e_macsec_rule *macsec_rule,
- int action);
-
-void mlx5e_macsec_fs_get_stats_fill(struct mlx5e_macsec_fs *macsec_fs, void *macsec_stats);
-
-#endif
-
-#endif /* __MLX5_MACSEC_STEERING_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_stats.c
index e50a2e3f3d18..4559ee16a11a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_stats.c
@@ -8,14 +8,14 @@
#include "en_accel/macsec.h"
static const struct counter_desc mlx5e_macsec_hw_stats_desc[] = {
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_rx_pkts) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_rx_bytes) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_rx_pkts_drop) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_rx_bytes_drop) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_tx_pkts) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_tx_bytes) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_tx_pkts_drop) },
- { MLX5E_DECLARE_STAT(struct mlx5e_macsec_stats, macsec_tx_bytes_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_rx_pkts) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_rx_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_rx_pkts_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_rx_bytes_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_tx_pkts) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_tx_bytes) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_tx_pkts_drop) },
+ { MLX5E_DECLARE_STAT(struct mlx5_macsec_stats, macsec_tx_bytes_drop) },
};
#define NUM_MACSEC_HW_COUNTERS ARRAY_SIZE(mlx5e_macsec_hw_stats_desc)
@@ -52,6 +52,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(macsec_hw)
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(macsec_hw)
{
+ struct mlx5_macsec_fs *macsec_fs;
int i;
if (!priv->macsec)
@@ -60,9 +61,10 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(macsec_hw)
if (!mlx5e_is_macsec_device(priv->mdev))
return idx;
- mlx5e_macsec_get_stats_fill(priv->macsec, mlx5e_macsec_get_stats(priv->macsec));
+ macsec_fs = priv->mdev->macsec_fs;
+ mlx5_macsec_fs_get_stats_fill(macsec_fs, mlx5_macsec_fs_get_stats(macsec_fs));
for (i = 0; i < NUM_MACSEC_HW_COUNTERS; i++)
- data[idx++] = MLX5E_READ_CTR64_CPU(mlx5e_macsec_get_stats(priv->macsec),
+ data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_macsec_fs_get_stats(macsec_fs),
mlx5e_macsec_hw_stats_desc,
i);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
index 5aa51d74f8b4..bb7f86c993e5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
@@ -432,8 +432,10 @@ static void arfs_may_expire_flow(struct mlx5e_priv *priv)
}
spin_unlock_bh(&arfs->arfs_lock);
hlist_for_each_entry_safe(arfs_rule, htmp, &del_list, hlist) {
- if (arfs_rule->rule)
+ if (arfs_rule->rule) {
mlx5_del_flow_rules(arfs_rule->rule);
+ priv->channel_stats[arfs_rule->rxq]->rq.arfs_expired++;
+ }
hlist_del(&arfs_rule->hlist);
kfree(arfs_rule);
}
@@ -509,6 +511,7 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv,
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) {
+ priv->channel_stats[arfs_rule->rxq]->rq.arfs_err++;
err = -ENOMEM;
goto out;
}
@@ -519,6 +522,8 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv,
ntohs(tuple->etype));
arfs_table = arfs_get_table(arfs, tuple->ip_proto, tuple->etype);
if (!arfs_table) {
+ WARN_ONCE(1, "arfs table does not exist for etype %u and ip_proto %u\n",
+ tuple->etype, tuple->ip_proto);
err = -EINVAL;
goto out;
}
@@ -600,9 +605,11 @@ static void arfs_modify_rule_rq(struct mlx5e_priv *priv,
dst.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
dst.tir_num = mlx5e_rx_res_get_tirn_direct(priv->rx_res, rxq);
err = mlx5_modify_rule_destination(rule, &dst, NULL);
- if (err)
+ if (err) {
+ priv->channel_stats[rxq]->rq.arfs_err++;
netdev_warn(priv->netdev,
"Failed to modify aRFS rule destination to rq=%d\n", rxq);
+ }
}
static void arfs_handle_work(struct work_struct *work)
@@ -632,6 +639,7 @@ static void arfs_handle_work(struct work_struct *work)
if (IS_ERR(rule))
goto out;
arfs_rule->rule = rule;
+ priv->channel_stats[arfs_rule->rxq]->rq.arfs_add++;
} else {
arfs_modify_rule_rq(priv, arfs_rule->rule,
arfs_rule->rxq);
@@ -650,8 +658,10 @@ static struct arfs_rule *arfs_alloc_rule(struct mlx5e_priv *priv,
struct arfs_tuple *tuple;
rule = kzalloc(sizeof(*rule), GFP_ATOMIC);
- if (!rule)
+ if (!rule) {
+ priv->channel_stats[rxq]->rq.arfs_err++;
return NULL;
+ }
rule->priv = priv;
rule->rxq = rxq;
@@ -740,10 +750,13 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
spin_lock_bh(&arfs->arfs_lock);
arfs_rule = arfs_find_rule(arfs_t, &fk);
if (arfs_rule) {
- if (arfs_rule->rxq == rxq_index) {
+ if (arfs_rule->rxq == rxq_index || work_busy(&arfs_rule->arfs_work)) {
spin_unlock_bh(&arfs->arfs_lock);
return arfs_rule->filter_id;
}
+
+ priv->channel_stats[rxq_index]->rq.arfs_request_in++;
+ priv->channel_stats[arfs_rule->rxq]->rq.arfs_request_out++;
arfs_rule->rxq = rxq_index;
} else {
arfs_rule = arfs_alloc_rule(priv, arfs_t, &fk, rxq_index, flow_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 27861b68ced5..dff02434ff45 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -2061,7 +2061,8 @@ static int set_pflag_tx_port_ts(struct net_device *netdev, bool enable)
struct mlx5e_params new_params;
int err;
- if (!MLX5_CAP_GEN(mdev, ts_cqe_to_dest_cqn))
+ if (!MLX5_CAP_GEN(mdev, ts_cqe_to_dest_cqn) ||
+ !MLX5_CAP_GEN_2(mdev, ts_cqe_metadata_size2wqe_counter))
return -EOPNOTSUPP;
/* Don't allow changing the PTP state if HTB offload is active, because
@@ -2163,8 +2164,8 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev)
return priv->channels.params.pflags;
}
-int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
- u32 *rule_locs)
+static int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
+ u32 *rule_locs)
{
struct mlx5e_priv *priv = netdev_priv(dev);
@@ -2181,7 +2182,7 @@ int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs);
}
-int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct mlx5e_priv *priv = netdev_priv(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
index aac32e505c14..3eccdadc0357 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
@@ -96,10 +96,6 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv,
case UDP_V4_FLOW:
case TCP_V6_FLOW:
case UDP_V6_FLOW:
- max_tuples = ETHTOOL_NUM_L3_L4_FTS;
- prio = MLX5E_ETHTOOL_L3_L4_PRIO + (max_tuples - num_tuples);
- eth_ft = &ethtool->l3_l4_ft[prio];
- break;
case IP_USER_FLOW:
case IPV6_USER_FLOW:
max_tuples = ETHTOOL_NUM_L3_L4_FTS;
@@ -900,10 +896,16 @@ static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
struct ethtool_rxnfc *nfc)
{
u8 rx_hash_field = 0;
+ u32 flow_type = 0;
+ u32 rss_idx = 0;
int err;
int tt;
- tt = flow_type_to_traffic_type(nfc->flow_type);
+ if (nfc->flow_type & FLOW_RSS)
+ rss_idx = nfc->rss_context;
+
+ flow_type = flow_type_mask(nfc->flow_type);
+ tt = flow_type_to_traffic_type(flow_type);
if (tt < 0)
return tt;
@@ -911,10 +913,10 @@ static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
* on src IP, dest IP, TCP/UDP src port and TCP/UDP dest
* port.
*/
- if (nfc->flow_type != TCP_V4_FLOW &&
- nfc->flow_type != TCP_V6_FLOW &&
- nfc->flow_type != UDP_V4_FLOW &&
- nfc->flow_type != UDP_V6_FLOW)
+ if (flow_type != TCP_V4_FLOW &&
+ flow_type != TCP_V6_FLOW &&
+ flow_type != UDP_V4_FLOW &&
+ flow_type != UDP_V6_FLOW)
return -EOPNOTSUPP;
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
@@ -931,7 +933,7 @@ static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
rx_hash_field |= MLX5_HASH_FIELD_SEL_L4_DPORT;
mutex_lock(&priv->state_lock);
- err = mlx5e_rx_res_rss_set_hash_fields(priv->rx_res, tt, rx_hash_field);
+ err = mlx5e_rx_res_rss_set_hash_fields(priv->rx_res, rss_idx, tt, rx_hash_field);
mutex_unlock(&priv->state_lock);
return err;
@@ -940,14 +942,23 @@ static int mlx5e_set_rss_hash_opt(struct mlx5e_priv *priv,
static int mlx5e_get_rss_hash_opt(struct mlx5e_priv *priv,
struct ethtool_rxnfc *nfc)
{
- u32 hash_field = 0;
+ int hash_field = 0;
+ u32 flow_type = 0;
+ u32 rss_idx = 0;
int tt;
- tt = flow_type_to_traffic_type(nfc->flow_type);
+ if (nfc->flow_type & FLOW_RSS)
+ rss_idx = nfc->rss_context;
+
+ flow_type = flow_type_mask(nfc->flow_type);
+ tt = flow_type_to_traffic_type(flow_type);
if (tt < 0)
return tt;
- hash_field = mlx5e_rx_res_rss_get_hash_fields(priv->rx_res, tt);
+ hash_field = mlx5e_rx_res_rss_get_hash_fields(priv->rx_res, rss_idx, tt);
+ if (hash_field < 0)
+ return hash_field;
+
nfc->data = 0;
if (hash_field & MLX5_HASH_FIELD_SEL_SRC_IP)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index f7b494125eee..a2ae791538ed 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -38,7 +38,7 @@
#include <linux/debugfs.h>
#include <linux/if_bridge.h>
#include <linux/filter.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <net/pkt_sched.h>
#include <net/xdp_sock_drv.h>
#include "eswitch.h"
@@ -1991,7 +1991,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
int eqn;
int err;
- err = mlx5_vector2eqn(mdev, param->eq_ix, &eqn);
+ err = mlx5_comp_eqn_get(mdev, param->eq_ix, &eqn);
if (err)
return err;
@@ -2447,14 +2447,14 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
struct xsk_buff_pool *xsk_pool,
struct mlx5e_channel **cp)
{
- int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
+ int cpu = mlx5_comp_vector_get_cpu(priv->mdev, ix);
struct net_device *netdev = priv->netdev;
struct mlx5e_xsk_param xsk;
struct mlx5e_channel *c;
unsigned int irq;
int err;
- err = mlx5_vector2irqn(priv->mdev, ix, &irq);
+ err = mlx5_comp_irqn_get(priv->mdev, ix, &irq);
if (err)
return err;
@@ -2858,13 +2858,13 @@ static void mlx5e_set_default_xps_cpumasks(struct mlx5e_priv *priv,
struct mlx5_core_dev *mdev = priv->mdev;
int num_comp_vectors, ix, irq;
- num_comp_vectors = mlx5_comp_vectors_count(mdev);
+ num_comp_vectors = mlx5_comp_vectors_max(mdev);
for (ix = 0; ix < params->num_channels; ix++) {
cpumask_clear(priv->scratchpad.cpumask);
for (irq = ix; irq < num_comp_vectors; irq += params->num_channels) {
- int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(mdev, irq));
+ int cpu = mlx5_comp_vector_get_cpu(mdev, irq);
cpumask_set_cpu(cpu, priv->scratchpad.cpumask);
}
@@ -4898,9 +4898,6 @@ static int mlx5e_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
- if (nla_len(attr) < sizeof(mode))
- return -EINVAL;
-
mode = nla_get_u16(attr);
if (mode > BRIDGE_MODE_VEPA)
return -EINVAL;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 99b3843396f3..2fdb8895aecd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -399,15 +399,13 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw,
}
static int mlx5e_sqs2vport_add_peers_rules(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep,
- struct mlx5_devcom *devcom,
struct mlx5e_rep_sq *rep_sq, int i)
{
- struct mlx5_eswitch *peer_esw = NULL;
struct mlx5_flow_handle *flow_rule;
- int tmp;
+ struct mlx5_devcom_comp_dev *tmp;
+ struct mlx5_eswitch *peer_esw;
- mlx5_devcom_for_each_peer_entry(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
- peer_esw, tmp) {
+ mlx5_devcom_for_each_peer_entry(esw->devcom, peer_esw, tmp) {
u16 peer_rule_idx = MLX5_CAP_GEN(peer_esw->dev, vhca_id);
struct mlx5e_rep_sq_peer *sq_peer;
int err;
@@ -443,7 +441,6 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
struct mlx5_flow_handle *flow_rule;
struct mlx5e_rep_priv *rpriv;
struct mlx5e_rep_sq *rep_sq;
- struct mlx5_devcom *devcom;
bool devcom_locked = false;
int err;
int i;
@@ -451,10 +448,10 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return 0;
- devcom = esw->dev->priv.devcom;
rpriv = mlx5e_rep_to_rep_priv(rep);
- if (mlx5_devcom_comp_is_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS) &&
- mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
+
+ if (mlx5_devcom_comp_is_ready(esw->devcom) &&
+ mlx5_devcom_for_each_peer_begin(esw->devcom))
devcom_locked = true;
for (i = 0; i < sqns_num; i++) {
@@ -477,7 +474,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
xa_init(&rep_sq->sq_peer);
if (devcom_locked) {
- err = mlx5e_sqs2vport_add_peers_rules(esw, rep, devcom, rep_sq, i);
+ err = mlx5e_sqs2vport_add_peers_rules(esw, rep, rep_sq, i);
if (err) {
mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule);
xa_destroy(&rep_sq->sq_peer);
@@ -490,7 +487,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
}
if (devcom_locked)
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_for_each_peer_end(esw->devcom);
return 0;
@@ -498,7 +495,7 @@ out_err:
mlx5e_sqs2vport_stop(esw, rep);
if (devcom_locked)
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_for_each_peer_end(esw->devcom);
return err;
}
@@ -1339,6 +1336,7 @@ static mlx5e_stats_grp_t mlx5e_ul_rep_stats_grps[] = {
&MLX5E_STATS_GRP(channels),
&MLX5E_STATS_GRP(per_port_buff_congest),
#ifdef CONFIG_MLX5_EN_IPSEC
+ &MLX5E_STATS_GRP(ipsec_hw),
&MLX5E_STATS_GRP(ipsec_sw),
#endif
&MLX5E_STATS_GRP(ptp),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 41d37159e027..3fd11b0761e0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -36,7 +36,7 @@
#include <linux/bitmap.h>
#include <linux/filter.h>
#include <net/ip6_checksum.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/inet_ecn.h>
#include <net/gro.h>
#include <net/udp.h>
@@ -1543,7 +1543,8 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
mlx5e_ktls_handle_rx_skb(rq, skb, cqe, &cqe_bcnt);
if (unlikely(mlx5_ipsec_is_rx_flow(cqe)))
- mlx5e_ipsec_offload_handle_rx_skb(netdev, skb, cqe);
+ mlx5e_ipsec_offload_handle_rx_skb(netdev, skb,
+ be32_to_cpu(cqe->ft_metadata));
if (unlikely(mlx5e_macsec_is_rx_flow(cqe)))
mlx5e_macsec_offload_handle_rx_skb(netdev, skb, cqe);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 4d77055abd4b..4b96ad657145 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -38,7 +38,7 @@
#include "en/port.h"
#ifdef CONFIG_PAGE_POOL_STATS
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#endif
static unsigned int stats_grps_num(struct mlx5e_priv *priv)
@@ -180,7 +180,13 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_congst_umr) },
+#ifdef CONFIG_MLX5_EN_ARFS
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_add) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_request_in) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_request_out) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_expired) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_err) },
+#endif
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_recover) },
#ifdef CONFIG_PAGE_POOL_STATS
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_fast) },
@@ -231,7 +237,6 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_cqe_compress_blks) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_cqe_compress_pkts) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_congst_umr) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_arfs_err) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_xmit) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_mpwqe) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_inlnw) },
@@ -321,7 +326,6 @@ static void mlx5e_stats_grp_sw_update_stats_xskrq(struct mlx5e_sw_stats *s,
s->rx_xsk_cqe_compress_blks += xskrq_stats->cqe_compress_blks;
s->rx_xsk_cqe_compress_pkts += xskrq_stats->cqe_compress_pkts;
s->rx_xsk_congst_umr += xskrq_stats->congst_umr;
- s->rx_xsk_arfs_err += xskrq_stats->arfs_err;
}
static void mlx5e_stats_grp_sw_update_stats_rq_stats(struct mlx5e_sw_stats *s,
@@ -354,7 +358,13 @@ static void mlx5e_stats_grp_sw_update_stats_rq_stats(struct mlx5e_sw_stats *s,
s->rx_cqe_compress_blks += rq_stats->cqe_compress_blks;
s->rx_cqe_compress_pkts += rq_stats->cqe_compress_pkts;
s->rx_congst_umr += rq_stats->congst_umr;
+#ifdef CONFIG_MLX5_EN_ARFS
+ s->rx_arfs_add += rq_stats->arfs_add;
+ s->rx_arfs_request_in += rq_stats->arfs_request_in;
+ s->rx_arfs_request_out += rq_stats->arfs_request_out;
+ s->rx_arfs_expired += rq_stats->arfs_expired;
s->rx_arfs_err += rq_stats->arfs_err;
+#endif
s->rx_recover += rq_stats->recover;
#ifdef CONFIG_PAGE_POOL_STATS
s->rx_pp_alloc_fast += rq_stats->pp_alloc_fast;
@@ -1990,7 +2000,13 @@ static const struct counter_desc rq_stats_desc[] = {
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_blks) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_pkts) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, congst_umr) },
+#ifdef CONFIG_MLX5_EN_ARFS
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_add) },
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_request_in) },
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_request_out) },
+ { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_expired) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_err) },
+#endif
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, recover) },
#ifdef CONFIG_PAGE_POOL_STATS
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_fast) },
@@ -2092,7 +2108,6 @@ static const struct counter_desc xskrq_stats_desc[] = {
{ MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, cqe_compress_blks) },
{ MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, cqe_compress_pkts) },
{ MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, congst_umr) },
- { MLX5E_DECLARE_XSKRQ_STAT(struct mlx5e_rq_stats, arfs_err) },
};
static const struct counter_desc xsksq_stats_desc[] = {
@@ -2142,9 +2157,7 @@ static const struct counter_desc ptp_cq_stats_desc[] = {
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, err_cqe) },
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort) },
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort_abs_diff_ns) },
- { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_cqe) },
- { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_event) },
- { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, ooo_cqe_drop) },
+ { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, late_cqe) },
};
static const struct counter_desc ptp_rq_stats_desc[] = {
@@ -2170,7 +2183,6 @@ static const struct counter_desc ptp_rq_stats_desc[] = {
{ MLX5E_DECLARE_PTP_RQ_STAT(struct mlx5e_rq_stats, cqe_compress_blks) },
{ MLX5E_DECLARE_PTP_RQ_STAT(struct mlx5e_rq_stats, cqe_compress_pkts) },
{ MLX5E_DECLARE_PTP_RQ_STAT(struct mlx5e_rq_stats, congst_umr) },
- { MLX5E_DECLARE_PTP_RQ_STAT(struct mlx5e_rq_stats, arfs_err) },
{ MLX5E_DECLARE_PTP_RQ_STAT(struct mlx5e_rq_stats, recover) },
};
@@ -2490,7 +2502,7 @@ mlx5e_stats_grp_t mlx5e_nic_stats_grps[] = {
&MLX5E_STATS_GRP(per_port_buff_congest),
&MLX5E_STATS_GRP(ptp),
&MLX5E_STATS_GRP(qos),
-#ifdef CONFIG_MLX5_EN_MACSEC
+#ifdef CONFIG_MLX5_MACSEC
&MLX5E_STATS_GRP(macsec_hw),
#endif
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 1ff8a06027dc..176fa5976259 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -194,7 +194,13 @@ struct mlx5e_sw_stats {
u64 rx_cqe_compress_blks;
u64 rx_cqe_compress_pkts;
u64 rx_congst_umr;
+#ifdef CONFIG_MLX5_EN_ARFS
+ u64 rx_arfs_add;
+ u64 rx_arfs_request_in;
+ u64 rx_arfs_request_out;
+ u64 rx_arfs_expired;
u64 rx_arfs_err;
+#endif
u64 rx_recover;
u64 ch_events;
u64 ch_poll;
@@ -256,7 +262,6 @@ struct mlx5e_sw_stats {
u64 rx_xsk_cqe_compress_blks;
u64 rx_xsk_cqe_compress_pkts;
u64 rx_xsk_congst_umr;
- u64 rx_xsk_arfs_err;
u64 tx_xsk_xmit;
u64 tx_xsk_mpwqe;
u64 tx_xsk_inlnw;
@@ -358,7 +363,13 @@ struct mlx5e_rq_stats {
u64 cqe_compress_blks;
u64 cqe_compress_pkts;
u64 congst_umr;
+#ifdef CONFIG_MLX5_EN_ARFS
+ u64 arfs_add;
+ u64 arfs_request_in;
+ u64 arfs_request_out;
+ u64 arfs_expired;
u64 arfs_err;
+#endif
u64 recover;
#ifdef CONFIG_PAGE_POOL_STATS
u64 pp_alloc_fast;
@@ -449,9 +460,7 @@ struct mlx5e_ptp_cq_stats {
u64 err_cqe;
u64 abort;
u64 abort_abs_diff_ns;
- u64 resync_cqe;
- u64 resync_event;
- u64 ooo_cqe_drop;
+ u64 late_cqe;
};
struct mlx5e_rep_stats {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 31708d5aa608..318083690fcd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1668,11 +1668,10 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro
{
struct mlx5e_priv *out_priv, *route_priv;
struct mlx5_core_dev *route_mdev;
- struct mlx5_devcom *devcom;
+ struct mlx5_devcom_comp_dev *pos;
struct mlx5_eswitch *esw;
u16 vhca_id;
int err;
- int i;
out_priv = netdev_priv(out_dev);
esw = out_priv->mdev->priv.eswitch;
@@ -1688,10 +1687,8 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro
return err;
rcu_read_lock();
- devcom = out_priv->mdev->priv.devcom;
err = -ENODEV;
- mlx5_devcom_for_each_peer_entry_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
- esw, i) {
+ mlx5_devcom_for_each_peer_entry_rcu(esw->devcom, esw, pos) {
err = mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport);
if (!err)
break;
@@ -2038,15 +2035,15 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
if (mlx5e_is_eswitch_flow(flow)) {
- struct mlx5_devcom *devcom = flow->priv->mdev->priv.devcom;
+ struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
- if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) {
+ if (!mlx5_devcom_for_each_peer_begin(devcom)) {
mlx5e_tc_del_fdb_flow(priv, flow);
return;
}
mlx5e_tc_del_fdb_peers_flow(flow);
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_for_each_peer_end(devcom);
mlx5e_tc_del_fdb_flow(priv, flow);
} else {
mlx5e_tc_del_nic_flow(priv, flow);
@@ -2600,29 +2597,29 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
match_level = outer_match_level;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_META) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_CVLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_TCP) |
- BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_CT) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
- BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) |
- BIT(FLOW_DISSECTOR_KEY_ICMP) |
- BIT(FLOW_DISSECTOR_KEY_MPLS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_META) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CT) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_OPTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ICMP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_MPLS))) {
NL_SET_ERR_MSG_MOD(extack, "Unsupported key");
- netdev_dbg(priv->netdev, "Unsupported key used: 0x%x\n",
+ netdev_dbg(priv->netdev, "Unsupported key used: 0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
@@ -4223,8 +4220,7 @@ static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow)
flow_flag_test(flow, INGRESS);
bool act_is_encap = !!(attr->action &
MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT);
- bool esw_paired = mlx5_devcom_comp_is_ready(esw_attr->in_mdev->priv.devcom,
- MLX5_DEVCOM_ESW_OFFLOADS);
+ bool esw_paired = mlx5_devcom_comp_is_ready(esw_attr->in_mdev->priv.eswitch->devcom);
if (!esw_paired)
return false;
@@ -4491,14 +4487,13 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
struct net_device *filter_dev,
struct mlx5e_tc_flow **__flow)
{
- struct mlx5_devcom *devcom = priv->mdev->priv.devcom;
+ struct mlx5_devcom_comp_dev *devcom = priv->mdev->priv.eswitch->devcom, *pos;
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct mlx5_eswitch_rep *in_rep = rpriv->rep;
struct mlx5_core_dev *in_mdev = priv->mdev;
struct mlx5_eswitch *peer_esw;
struct mlx5e_tc_flow *flow;
int err;
- int i;
flow = __mlx5e_add_fdb_flow(priv, f, flow_flags, filter_dev, in_rep,
in_mdev);
@@ -4510,27 +4505,25 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
return 0;
}
- if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) {
+ if (!mlx5_devcom_for_each_peer_begin(devcom)) {
err = -ENODEV;
goto clean_flow;
}
- mlx5_devcom_for_each_peer_entry(devcom,
- MLX5_DEVCOM_ESW_OFFLOADS,
- peer_esw, i) {
+ mlx5_devcom_for_each_peer_entry(devcom, peer_esw, pos) {
err = mlx5e_tc_add_fdb_peer_flow(f, flow, flow_flags, peer_esw);
if (err)
goto peer_clean;
}
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_for_each_peer_end(devcom);
*__flow = flow;
return 0;
peer_clean:
mlx5e_tc_del_fdb_peers_flow(flow);
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_for_each_peer_end(devcom);
clean_flow:
mlx5e_tc_del_fdb_flow(priv, flow);
return err;
@@ -4633,6 +4626,46 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev,
return netif_is_lag_port(dev) && rpriv && rpriv->rep->vport != MLX5_VPORT_UPLINK;
}
+/* As IPsec and TC order is not aligned between software and hardware-offload,
+ * either IPsec offload or TC offload, not both, is allowed for a specific interface.
+ */
+static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx5e_priv *priv)
+{
+ if (!IS_ENABLED(CONFIG_MLX5_EN_IPSEC))
+ return false;
+
+ if (filter != priv->netdev)
+ return false;
+
+ if (mlx5e_eswitch_vf_rep(priv->netdev))
+ return false;
+
+ return true;
+}
+
+static int mlx5e_tc_block_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
+{
+ struct mlx5_core_dev *mdev = priv->mdev;
+
+ if (!is_tc_ipsec_order_check_needed(filter, priv))
+ return 0;
+
+ if (mdev->num_block_tc)
+ return -EBUSY;
+
+ mdev->num_block_ipsec++;
+
+ return 0;
+}
+
+static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
+{
+ if (!is_tc_ipsec_order_check_needed(filter, priv))
+ return;
+
+ priv->mdev->num_block_ipsec--;
+}
+
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct flow_cls_offload *f, unsigned long flags)
{
@@ -4645,6 +4678,10 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (!mlx5_esw_hold(priv->mdev))
return -EBUSY;
+ err = mlx5e_tc_block_ipsec_offload(dev, priv);
+ if (err)
+ goto esw_release;
+
mlx5_esw_get(priv->mdev);
rcu_read_lock();
@@ -4690,7 +4727,9 @@ rcu_unlock:
err_free:
mlx5e_flow_put(priv, flow);
out:
+ mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev);
+esw_release:
mlx5_esw_release(priv->mdev);
return err;
}
@@ -4731,6 +4770,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
trace_mlx5e_delete_flower(f);
mlx5e_flow_put(priv, flow);
+ mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev);
return 0;
@@ -4748,7 +4788,7 @@ int mlx5e_tc_fill_action_stats(struct mlx5e_priv *priv,
int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct flow_cls_offload *f, unsigned long flags)
{
- struct mlx5_devcom *devcom = priv->mdev->priv.devcom;
+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct rhashtable *tc_ht = get_tc_ht(priv, flags);
struct mlx5e_tc_flow *flow;
struct mlx5_fc *counter;
@@ -4784,7 +4824,7 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
/* Under multipath it's possible for one rule to be currently
* un-offloaded while the other rule is offloaded.
*/
- if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
+ if (esw && !mlx5_devcom_for_each_peer_begin(esw->devcom))
goto out;
if (flow_flag_test(flow, DUP)) {
@@ -4815,7 +4855,8 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
}
no_peer_counter:
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ if (esw)
+ mlx5_devcom_for_each_peer_end(esw->devcom);
out:
flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
FLOW_ACTION_HW_STATS_DELAYED);
@@ -5220,11 +5261,12 @@ void mlx5e_tc_ht_cleanup(struct rhashtable *tc_ht)
int mlx5e_tc_esw_init(struct mlx5_rep_uplink_priv *uplink_priv)
{
const size_t sz_enc_opts = sizeof(struct tunnel_match_enc_opts);
+ struct netdev_phys_item_id ppid;
struct mlx5e_rep_priv *rpriv;
struct mapping_ctx *mapping;
struct mlx5_eswitch *esw;
struct mlx5e_priv *priv;
- u64 mapping_id;
+ u64 mapping_id, key;
int err = 0;
rpriv = container_of(uplink_priv, struct mlx5e_rep_priv, uplink_priv);
@@ -5278,7 +5320,11 @@ int mlx5e_tc_esw_init(struct mlx5_rep_uplink_priv *uplink_priv)
goto err_action_counter;
}
- mlx5_esw_offloads_devcom_init(esw);
+ err = dev_get_port_parent_id(priv->netdev, &ppid, false);
+ if (!err) {
+ memcpy(&key, &ppid.id, sizeof(key));
+ mlx5_esw_offloads_devcom_init(esw, key);
+ }
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index c7eb6b238c2b..d41435c22ce5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -372,7 +372,7 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
const struct mlx5e_tx_attr *attr,
const struct mlx5e_tx_wqe_attr *wqe_attr, u8 num_dma,
struct mlx5e_tx_wqe_info *wi, struct mlx5_wqe_ctrl_seg *cseg,
- bool xmit_more)
+ struct mlx5_wqe_eth_seg *eseg, bool xmit_more)
{
struct mlx5_wq_cyc *wq = &sq->wq;
bool send_doorbell;
@@ -394,11 +394,16 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
mlx5e_tx_check_stop(sq);
- if (unlikely(sq->ptpsq)) {
+ if (unlikely(sq->ptpsq &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) {
+ u8 metadata_index = be32_to_cpu(eseg->flow_table_metadata);
+
mlx5e_skb_cb_hwtstamp_init(skb);
- mlx5e_skb_fifo_push(&sq->ptpsq->skb_fifo, skb);
+ mlx5e_ptpsq_track_metadata(sq->ptpsq, metadata_index);
+ mlx5e_ptp_metadata_map_put(&sq->ptpsq->metadata_map, skb,
+ metadata_index);
if (!netif_tx_queue_stopped(sq->txq) &&
- !mlx5e_skb_fifo_has_room(&sq->ptpsq->skb_fifo)) {
+ mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq)) {
netif_tx_stop_queue(sq->txq);
sq->stats->stopped++;
}
@@ -483,13 +488,16 @@ mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
if (unlikely(num_dma < 0))
goto err_drop;
- mlx5e_txwqe_complete(sq, skb, attr, wqe_attr, num_dma, wi, cseg, xmit_more);
+ mlx5e_txwqe_complete(sq, skb, attr, wqe_attr, num_dma, wi, cseg, eseg, xmit_more);
return;
err_drop:
stats->dropped++;
dev_kfree_skb_any(skb);
+ if (unlikely(sq->ptpsq && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
+ mlx5e_ptp_metadata_fifo_push(&sq->ptpsq->metadata_freelist,
+ be32_to_cpu(eseg->flow_table_metadata));
mlx5e_tx_flush(sq);
}
@@ -645,9 +653,9 @@ void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
static void mlx5e_cqe_ts_id_eseg(struct mlx5e_ptpsq *ptpsq, struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg)
{
- if (ptpsq->ts_cqe_ctr_mask && unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
- eseg->flow_table_metadata = cpu_to_be32(ptpsq->skb_fifo_pc &
- ptpsq->ts_cqe_ctr_mask);
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ eseg->flow_table_metadata =
+ cpu_to_be32(mlx5e_ptp_metadata_fifo_pop(&ptpsq->metadata_freelist));
}
static void mlx5e_txwqe_build_eseg(struct mlx5e_priv *priv, struct mlx5e_txqsq *sq,
@@ -766,7 +774,7 @@ void mlx5e_txqsq_wake(struct mlx5e_txqsq *sq)
{
if (netif_tx_queue_stopped(sq->txq) &&
mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) &&
- mlx5e_ptpsq_fifo_has_room(sq) &&
+ !mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq) &&
!test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) {
netif_tx_wake_queue(sq->txq);
sq->stats->wake++;
@@ -1031,7 +1039,7 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
if (unlikely(num_dma < 0))
goto err_drop;
- mlx5e_txwqe_complete(sq, skb, &attr, &wqe_attr, num_dma, wi, cseg, xmit_more);
+ mlx5e_txwqe_complete(sq, skb, &attr, &wqe_attr, num_dma, wi, cseg, eseg, xmit_more);
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 3db4866d7880..ea0405e0a43f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -47,7 +47,7 @@ enum {
static_assert(MLX5_EQ_POLLING_BUDGET <= MLX5_NUM_SPARE_EQE);
struct mlx5_eq_table {
- struct list_head comp_eqs_list;
+ struct xarray comp_eqs;
struct mlx5_eq_async pages_eq;
struct mlx5_eq_async cmd_eq;
struct mlx5_eq_async async_eq;
@@ -58,11 +58,14 @@ struct mlx5_eq_table {
struct mlx5_nb cq_err_nb;
struct mutex lock; /* sync async eqs creations */
- int num_comp_eqs;
+ struct mutex comp_lock; /* sync comp eqs creations */
+ int curr_comp_eqs;
+ int max_comp_eqs;
struct mlx5_irq_table *irq_table;
- struct mlx5_irq **comp_irqs;
+ struct xarray comp_irqs;
struct mlx5_irq *ctrl_irq;
struct cpu_rmap *rmap;
+ struct cpumask used_cpus;
};
#define MLX5_ASYNC_EVENT_MASK ((1ull << MLX5_EVENT_TYPE_PATH_MIG) | \
@@ -452,13 +455,22 @@ int mlx5_eq_table_init(struct mlx5_core_dev *dev)
ATOMIC_INIT_NOTIFIER_HEAD(&eq_table->nh[i]);
eq_table->irq_table = mlx5_irq_table_get(dev);
+ cpumask_clear(&eq_table->used_cpus);
+ xa_init(&eq_table->comp_eqs);
+ xa_init(&eq_table->comp_irqs);
+ mutex_init(&eq_table->comp_lock);
+ eq_table->curr_comp_eqs = 0;
return 0;
}
void mlx5_eq_table_cleanup(struct mlx5_core_dev *dev)
{
+ struct mlx5_eq_table *table = dev->priv.eq_table;
+
mlx5_eq_debugfs_cleanup(dev);
- kvfree(dev->priv.eq_table);
+ xa_destroy(&table->comp_irqs);
+ xa_destroy(&table->comp_eqs);
+ kvfree(table);
}
/* Async EQs */
@@ -803,88 +815,112 @@ void mlx5_eq_update_ci(struct mlx5_eq *eq, u32 cc, bool arm)
}
EXPORT_SYMBOL(mlx5_eq_update_ci);
-static void comp_irqs_release_pci(struct mlx5_core_dev *dev)
+static void comp_irq_release_pci(struct mlx5_core_dev *dev, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_irq *irq;
+
+ irq = xa_load(&table->comp_irqs, vecidx);
+ if (!irq)
+ return;
- mlx5_irqs_release_vectors(table->comp_irqs, table->num_comp_eqs);
+ xa_erase(&table->comp_irqs, vecidx);
+ mlx5_irq_release_vector(irq);
}
-static int comp_irqs_request_pci(struct mlx5_core_dev *dev)
+static int mlx5_cpumask_default_spread(int numa_node, int index)
{
- struct mlx5_eq_table *table = dev->priv.eq_table;
const struct cpumask *prev = cpu_none_mask;
const struct cpumask *mask;
- int ncomp_eqs;
- u16 *cpus;
- int ret;
+ int found_cpu = 0;
+ int i = 0;
int cpu;
- int i;
-
- ncomp_eqs = table->num_comp_eqs;
- cpus = kcalloc(ncomp_eqs, sizeof(*cpus), GFP_KERNEL);
- if (!cpus)
- return -ENOMEM;
- i = 0;
rcu_read_lock();
- for_each_numa_hop_mask(mask, dev->priv.numa_node) {
+ for_each_numa_hop_mask(mask, numa_node) {
for_each_cpu_andnot(cpu, mask, prev) {
- cpus[i] = cpu;
- if (++i == ncomp_eqs)
+ if (i++ == index) {
+ found_cpu = cpu;
goto spread_done;
+ }
}
prev = mask;
}
+
spread_done:
rcu_read_unlock();
- ret = mlx5_irqs_request_vectors(dev, cpus, ncomp_eqs, table->comp_irqs, &table->rmap);
- kfree(cpus);
- return ret;
+ return found_cpu;
}
-static void comp_irqs_release_sf(struct mlx5_core_dev *dev)
+static struct cpu_rmap *mlx5_eq_table_get_pci_rmap(struct mlx5_core_dev *dev)
{
- struct mlx5_eq_table *table = dev->priv.eq_table;
-
- mlx5_irq_affinity_irqs_release(dev, table->comp_irqs, table->num_comp_eqs);
+#ifdef CONFIG_RFS_ACCEL
+#ifdef CONFIG_MLX5_SF
+ if (mlx5_core_is_sf(dev))
+ return dev->priv.parent_mdev->priv.eq_table->rmap;
+#endif
+ return dev->priv.eq_table->rmap;
+#else
+ return NULL;
+#endif
}
-static int comp_irqs_request_sf(struct mlx5_core_dev *dev)
+static int comp_irq_request_pci(struct mlx5_core_dev *dev, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
- int ncomp_eqs = table->num_comp_eqs;
+ struct cpu_rmap *rmap;
+ struct mlx5_irq *irq;
+ int cpu;
+
+ rmap = mlx5_eq_table_get_pci_rmap(dev);
+ cpu = mlx5_cpumask_default_spread(dev->priv.numa_node, vecidx);
+ irq = mlx5_irq_request_vector(dev, cpu, vecidx, &rmap);
+ if (IS_ERR(irq))
+ return PTR_ERR(irq);
- return mlx5_irq_affinity_irqs_request_auto(dev, ncomp_eqs, table->comp_irqs);
+ return xa_err(xa_store(&table->comp_irqs, vecidx, irq, GFP_KERNEL));
}
-static void comp_irqs_release(struct mlx5_core_dev *dev)
+static void comp_irq_release_sf(struct mlx5_core_dev *dev, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_irq *irq;
- mlx5_core_is_sf(dev) ? comp_irqs_release_sf(dev) :
- comp_irqs_release_pci(dev);
+ irq = xa_load(&table->comp_irqs, vecidx);
+ if (!irq)
+ return;
- kfree(table->comp_irqs);
+ xa_erase(&table->comp_irqs, vecidx);
+ mlx5_irq_affinity_irq_release(dev, irq);
}
-static int comp_irqs_request(struct mlx5_core_dev *dev)
+static int comp_irq_request_sf(struct mlx5_core_dev *dev, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
- int ncomp_eqs;
- int ret;
+ struct mlx5_irq *irq;
- ncomp_eqs = table->num_comp_eqs;
- table->comp_irqs = kcalloc(ncomp_eqs, sizeof(*table->comp_irqs), GFP_KERNEL);
- if (!table->comp_irqs)
- return -ENOMEM;
+ irq = mlx5_irq_affinity_irq_request_auto(dev, &table->used_cpus, vecidx);
+ if (IS_ERR(irq)) {
+ /* In case SF irq pool does not exist, fallback to the PF irqs*/
+ if (PTR_ERR(irq) == -ENOENT)
+ return comp_irq_request_pci(dev, vecidx);
+
+ return PTR_ERR(irq);
+ }
+
+ return xa_err(xa_store(&table->comp_irqs, vecidx, irq, GFP_KERNEL));
+}
- ret = mlx5_core_is_sf(dev) ? comp_irqs_request_sf(dev) :
- comp_irqs_request_pci(dev);
- if (ret < 0)
- kfree(table->comp_irqs);
+static void comp_irq_release(struct mlx5_core_dev *dev, u16 vecidx)
+{
+ mlx5_core_is_sf(dev) ? comp_irq_release_sf(dev, vecidx) :
+ comp_irq_release_pci(dev, vecidx);
+}
- return ret;
+static int comp_irq_request(struct mlx5_core_dev *dev, u16 vecidx)
+{
+ return mlx5_core_is_sf(dev) ? comp_irq_request_sf(dev, vecidx) :
+ comp_irq_request_pci(dev, vecidx);
}
#ifdef CONFIG_RFS_ACCEL
@@ -901,7 +937,7 @@ static int alloc_rmap(struct mlx5_core_dev *mdev)
if (mlx5_core_is_sf(mdev))
return 0;
- eq_table->rmap = alloc_irq_cpu_rmap(eq_table->num_comp_eqs);
+ eq_table->rmap = alloc_irq_cpu_rmap(eq_table->max_comp_eqs);
if (!eq_table->rmap)
return -ENOMEM;
return 0;
@@ -921,22 +957,19 @@ static int alloc_rmap(struct mlx5_core_dev *mdev) { return 0; }
static void free_rmap(struct mlx5_core_dev *mdev) {}
#endif
-static void destroy_comp_eqs(struct mlx5_core_dev *dev)
+static void destroy_comp_eq(struct mlx5_core_dev *dev, struct mlx5_eq_comp *eq, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
- struct mlx5_eq_comp *eq, *n;
-
- list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) {
- list_del(&eq->list);
- mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
- if (destroy_unmap_eq(dev, &eq->core))
- mlx5_core_warn(dev, "failed to destroy comp EQ 0x%x\n",
- eq->core.eqn);
- tasklet_disable(&eq->tasklet_ctx.task);
- kfree(eq);
- }
- comp_irqs_release(dev);
- free_rmap(dev);
+
+ xa_erase(&table->comp_eqs, vecidx);
+ mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
+ if (destroy_unmap_eq(dev, &eq->core))
+ mlx5_core_warn(dev, "failed to destroy comp EQ 0x%x\n",
+ eq->core.eqn);
+ tasklet_disable(&eq->tasklet_ctx.task);
+ kfree(eq);
+ comp_irq_release(dev, vecidx);
+ table->curr_comp_eqs--;
}
static u16 comp_eq_depth_devlink_param_get(struct mlx5_core_dev *dev)
@@ -954,129 +987,149 @@ static u16 comp_eq_depth_devlink_param_get(struct mlx5_core_dev *dev)
return MLX5_COMP_EQ_SIZE;
}
-static int create_comp_eqs(struct mlx5_core_dev *dev)
+/* Must be called with EQ table comp_lock held */
+static int create_comp_eq(struct mlx5_core_dev *dev, u16 vecidx)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_eq_param param = {};
struct mlx5_eq_comp *eq;
- int ncomp_eqs;
+ struct mlx5_irq *irq;
int nent;
int err;
- int i;
- err = alloc_rmap(dev);
+ lockdep_assert_held(&table->comp_lock);
+ if (table->curr_comp_eqs == table->max_comp_eqs) {
+ mlx5_core_err(dev, "maximum number of vectors is allocated, %d\n",
+ table->max_comp_eqs);
+ return -ENOMEM;
+ }
+
+ err = comp_irq_request(dev, vecidx);
if (err)
return err;
- ncomp_eqs = comp_irqs_request(dev);
- if (ncomp_eqs < 0) {
- err = ncomp_eqs;
- goto err_irqs_req;
- }
-
- INIT_LIST_HEAD(&table->comp_eqs_list);
nent = comp_eq_depth_devlink_param_get(dev);
- for (i = 0; i < ncomp_eqs; i++) {
- struct mlx5_eq_param param = {};
+ eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, dev->priv.numa_node);
+ if (!eq) {
+ err = -ENOMEM;
+ goto clean_irq;
+ }
- eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, dev->priv.numa_node);
- if (!eq) {
- err = -ENOMEM;
- goto clean;
- }
+ INIT_LIST_HEAD(&eq->tasklet_ctx.list);
+ INIT_LIST_HEAD(&eq->tasklet_ctx.process_list);
+ spin_lock_init(&eq->tasklet_ctx.lock);
+ tasklet_setup(&eq->tasklet_ctx.task, mlx5_cq_tasklet_cb);
- INIT_LIST_HEAD(&eq->tasklet_ctx.list);
- INIT_LIST_HEAD(&eq->tasklet_ctx.process_list);
- spin_lock_init(&eq->tasklet_ctx.lock);
- tasklet_setup(&eq->tasklet_ctx.task, mlx5_cq_tasklet_cb);
-
- eq->irq_nb.notifier_call = mlx5_eq_comp_int;
- param = (struct mlx5_eq_param) {
- .irq = table->comp_irqs[i],
- .nent = nent,
- };
-
- err = create_map_eq(dev, &eq->core, &param);
- if (err)
- goto clean_eq;
- err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
- if (err) {
- destroy_unmap_eq(dev, &eq->core);
- goto clean_eq;
- }
+ irq = xa_load(&table->comp_irqs, vecidx);
+ eq->irq_nb.notifier_call = mlx5_eq_comp_int;
+ param = (struct mlx5_eq_param) {
+ .irq = irq,
+ .nent = nent,
+ };
- mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->core.eqn);
- /* add tail, to keep the list ordered, for mlx5_vector2eqn to work */
- list_add_tail(&eq->list, &table->comp_eqs_list);
+ err = create_map_eq(dev, &eq->core, &param);
+ if (err)
+ goto clean_eq;
+ err = mlx5_eq_enable(dev, &eq->core, &eq->irq_nb);
+ if (err) {
+ destroy_unmap_eq(dev, &eq->core);
+ goto clean_eq;
}
- table->num_comp_eqs = ncomp_eqs;
- return 0;
+ mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->core.eqn);
+ err = xa_err(xa_store(&table->comp_eqs, vecidx, eq, GFP_KERNEL));
+ if (err)
+ goto disable_eq;
+
+ table->curr_comp_eqs++;
+ return eq->core.eqn;
+disable_eq:
+ mlx5_eq_disable(dev, &eq->core, &eq->irq_nb);
clean_eq:
kfree(eq);
-clean:
- destroy_comp_eqs(dev);
-err_irqs_req:
- free_rmap(dev);
+clean_irq:
+ comp_irq_release(dev, vecidx);
return err;
}
-static int vector2eqnirqn(struct mlx5_core_dev *dev, int vector, int *eqn,
- unsigned int *irqn)
+int mlx5_comp_eqn_get(struct mlx5_core_dev *dev, u16 vecidx, int *eqn)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
struct mlx5_eq_comp *eq;
- int err = -ENOENT;
- int i = 0;
+ int ret = 0;
- list_for_each_entry(eq, &table->comp_eqs_list, list) {
- if (i++ == vector) {
- if (irqn)
- *irqn = eq->core.irqn;
- if (eqn)
- *eqn = eq->core.eqn;
- err = 0;
- break;
- }
+ mutex_lock(&table->comp_lock);
+ eq = xa_load(&table->comp_eqs, vecidx);
+ if (eq) {
+ *eqn = eq->core.eqn;
+ goto out;
}
- return err;
-}
+ ret = create_comp_eq(dev, vecidx);
+ if (ret < 0) {
+ mutex_unlock(&table->comp_lock);
+ return ret;
+ }
-int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn)
-{
- return vector2eqnirqn(dev, vector, eqn, NULL);
+ *eqn = ret;
+out:
+ mutex_unlock(&table->comp_lock);
+ return 0;
}
-EXPORT_SYMBOL(mlx5_vector2eqn);
+EXPORT_SYMBOL(mlx5_comp_eqn_get);
-int mlx5_vector2irqn(struct mlx5_core_dev *dev, int vector, unsigned int *irqn)
+int mlx5_comp_irqn_get(struct mlx5_core_dev *dev, int vector, unsigned int *irqn)
{
- return vector2eqnirqn(dev, vector, NULL, irqn);
+ struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_eq_comp *eq;
+ int eqn;
+ int err;
+
+ /* Allocate the EQ if not allocated yet */
+ err = mlx5_comp_eqn_get(dev, vector, &eqn);
+ if (err)
+ return err;
+
+ eq = xa_load(&table->comp_eqs, vector);
+ *irqn = eq->core.irqn;
+ return 0;
}
-unsigned int mlx5_comp_vectors_count(struct mlx5_core_dev *dev)
+unsigned int mlx5_comp_vectors_max(struct mlx5_core_dev *dev)
{
- return dev->priv.eq_table->num_comp_eqs;
+ return dev->priv.eq_table->max_comp_eqs;
}
-EXPORT_SYMBOL(mlx5_comp_vectors_count);
+EXPORT_SYMBOL(mlx5_comp_vectors_max);
-struct cpumask *
+static struct cpumask *
mlx5_comp_irq_get_affinity_mask(struct mlx5_core_dev *dev, int vector)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
struct mlx5_eq_comp *eq;
- int i = 0;
- list_for_each_entry(eq, &table->comp_eqs_list, list) {
- if (i++ == vector)
- return mlx5_irq_get_affinity_mask(eq->core.irq);
- }
+ eq = xa_load(&table->comp_eqs, vector);
+ if (eq)
+ return mlx5_irq_get_affinity_mask(eq->core.irq);
- WARN_ON_ONCE(1);
return NULL;
}
-EXPORT_SYMBOL(mlx5_comp_irq_get_affinity_mask);
+
+int mlx5_comp_vector_get_cpu(struct mlx5_core_dev *dev, int vector)
+{
+ struct cpumask *mask;
+ int cpu;
+
+ mask = mlx5_comp_irq_get_affinity_mask(dev, vector);
+ if (mask)
+ cpu = cpumask_first(mask);
+ else
+ cpu = mlx5_cpumask_default_spread(dev->priv.numa_node, vector);
+
+ return cpu;
+}
+EXPORT_SYMBOL(mlx5_comp_vector_get_cpu);
#ifdef CONFIG_RFS_ACCEL
struct cpu_rmap *mlx5_eq_table_get_rmap(struct mlx5_core_dev *dev)
@@ -1089,11 +1142,11 @@ struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn)
{
struct mlx5_eq_table *table = dev->priv.eq_table;
struct mlx5_eq_comp *eq;
+ unsigned long index;
- list_for_each_entry(eq, &table->comp_eqs_list, list) {
+ xa_for_each(&table->comp_eqs, index, eq)
if (eq->core.eqn == eqn)
return eq;
- }
return ERR_PTR(-ENOENT);
}
@@ -1101,11 +1154,7 @@ struct mlx5_eq_comp *mlx5_eqn2comp_eq(struct mlx5_core_dev *dev, int eqn)
/* This function should only be called after mlx5_cmd_force_teardown_hca */
void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev)
{
- struct mlx5_eq_table *table = dev->priv.eq_table;
-
- mutex_lock(&table->lock); /* sync with create/destroy_async_eq */
mlx5_irq_table_free_irqs(dev);
- mutex_unlock(&table->lock);
}
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
@@ -1148,22 +1197,22 @@ int mlx5_eq_table_create(struct mlx5_core_dev *dev)
struct mlx5_eq_table *eq_table = dev->priv.eq_table;
int err;
- eq_table->num_comp_eqs = get_num_eqs(dev);
+ eq_table->max_comp_eqs = get_num_eqs(dev);
err = create_async_eqs(dev);
if (err) {
mlx5_core_err(dev, "Failed to create async EQs\n");
goto err_async_eqs;
}
- err = create_comp_eqs(dev);
+ err = alloc_rmap(dev);
if (err) {
- mlx5_core_err(dev, "Failed to create completion EQs\n");
- goto err_comp_eqs;
+ mlx5_core_err(dev, "Failed to allocate rmap\n");
+ goto err_rmap;
}
return 0;
-err_comp_eqs:
+err_rmap:
destroy_async_eqs(dev);
err_async_eqs:
return err;
@@ -1171,7 +1220,14 @@ err_async_eqs:
void mlx5_eq_table_destroy(struct mlx5_core_dev *dev)
{
- destroy_comp_eqs(dev);
+ struct mlx5_eq_table *table = dev->priv.eq_table;
+ struct mlx5_eq_comp *eq;
+ unsigned long index;
+
+ xa_for_each(&table->comp_eqs, index, eq)
+ destroy_comp_eq(dev, eq, index);
+
+ free_rmap(dev);
destroy_async_eqs(dev);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
index f4fe1daa4afd..e36294b7ade2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
@@ -652,30 +652,30 @@ mlx5_esw_bridge_ingress_flow_peer_create(u16 vport_num, u16 esw_owner_vhca_id,
struct mlx5_esw_bridge_vlan *vlan, u32 counter_id,
struct mlx5_esw_bridge *bridge)
{
- struct mlx5_devcom *devcom = bridge->br_offloads->esw->dev->priv.devcom;
+ struct mlx5_devcom_comp_dev *devcom = bridge->br_offloads->esw->devcom, *pos;
struct mlx5_eswitch *tmp, *peer_esw = NULL;
static struct mlx5_flow_handle *handle;
- int i;
- if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
+ if (!mlx5_devcom_for_each_peer_begin(devcom))
return ERR_PTR(-ENODEV);
- mlx5_devcom_for_each_peer_entry(devcom,
- MLX5_DEVCOM_ESW_OFFLOADS,
- tmp, i) {
+ mlx5_devcom_for_each_peer_entry(devcom, tmp, pos) {
if (mlx5_esw_is_owner(tmp, vport_num, esw_owner_vhca_id)) {
peer_esw = tmp;
break;
}
}
+
if (!peer_esw) {
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
- return ERR_PTR(-ENODEV);
+ handle = ERR_PTR(-ENODEV);
+ goto out;
}
handle = mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id,
bridge, peer_esw);
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+
+out:
+ mlx5_devcom_for_each_peer_end(devcom);
return handle;
}
@@ -1391,8 +1391,8 @@ mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_ow
mlx5_fc_id(counter), bridge);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
- esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d)\n",
- vport_num, err);
+ esw_warn(esw->dev, "Failed to create ingress flow(vport=%u,err=%d,peer=%d)\n",
+ vport_num, err, peer);
goto err_ingress_flow_create;
}
entry->ingress_handle = handle;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
index 2455f8b93c1e..7a01714b3780 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
@@ -539,30 +539,29 @@ mlx5_esw_bridge_mcast_filter_flow_create(struct mlx5_esw_bridge_port *port)
static struct mlx5_flow_handle *
mlx5_esw_bridge_mcast_filter_flow_peer_create(struct mlx5_esw_bridge_port *port)
{
- struct mlx5_devcom *devcom = port->bridge->br_offloads->esw->dev->priv.devcom;
+ struct mlx5_devcom_comp_dev *devcom = port->bridge->br_offloads->esw->devcom, *pos;
struct mlx5_eswitch *tmp, *peer_esw = NULL;
static struct mlx5_flow_handle *handle;
- int i;
- if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
+ if (!mlx5_devcom_for_each_peer_begin(devcom))
return ERR_PTR(-ENODEV);
- mlx5_devcom_for_each_peer_entry(devcom,
- MLX5_DEVCOM_ESW_OFFLOADS,
- tmp, i) {
+ mlx5_devcom_for_each_peer_entry(devcom, tmp, pos) {
if (mlx5_esw_is_owner(tmp, port->vport_num, port->esw_owner_vhca_id)) {
peer_esw = tmp;
break;
}
}
+
if (!peer_esw) {
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
- return ERR_PTR(-ENODEV);
+ handle = ERR_PTR(-ENODEV);
+ goto out;
}
handle = mlx5_esw_bridge_mcast_flow_with_esw_create(port, peer_esw);
- mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+out:
+ mlx5_devcom_for_each_peer_end(devcom);
return handle;
}
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 fdf2be548e85..d8e739cbcbce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
@@ -16,39 +16,28 @@ mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_i
static bool mlx5_esw_devlink_port_supported(struct mlx5_eswitch *esw, u16 vport_num)
{
- return vport_num == MLX5_VPORT_UPLINK ||
- (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) ||
+ return (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) ||
mlx5_eswitch_is_vf_vport(esw, vport_num) ||
mlx5_core_is_ec_vf_vport(esw->dev, vport_num);
}
-static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 vport_num)
+static void mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(struct mlx5_eswitch *esw,
+ u16 vport_num,
+ struct devlink_port *dl_port)
{
struct mlx5_core_dev *dev = esw->dev;
- struct devlink_port_attrs attrs = {};
struct netdev_phys_item_id ppid = {};
- struct devlink_port *dl_port;
u32 controller_num = 0;
bool external;
u16 pfnum;
- dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
- if (!dl_port)
- return NULL;
-
mlx5_esw_get_port_parent_id(dev, &ppid);
pfnum = mlx5_get_dev_index(dev);
external = mlx5_core_is_ecpf_esw_manager(dev);
if (external)
controller_num = dev->priv.eswitch->offloads.host_number + 1;
- if (vport_num == MLX5_VPORT_UPLINK) {
- attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
- attrs.phys.port_number = pfnum;
- memcpy(attrs.switch_id.id, ppid.id, ppid.id_len);
- attrs.switch_id.id_len = ppid.id_len;
- devlink_port_attrs_set(dl_port, &attrs);
- } else if (vport_num == MLX5_VPORT_PF) {
+ if (vport_num == MLX5_VPORT_PF) {
memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len);
dl_port->attrs.switch_id.id_len = ppid.id_len;
devlink_port_attrs_pci_pf_set(dl_port, controller_num, pfnum, external);
@@ -63,91 +52,83 @@ static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16
devlink_port_attrs_pci_vf_set(dl_port, 0, pfnum,
vport_num - 1, false);
}
- return dl_port;
}
-static void mlx5_esw_dl_port_free(struct devlink_port *dl_port)
+int mlx5_esw_offloads_pf_vf_devlink_port_init(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
{
- kfree(dl_port);
-}
-
-static const struct devlink_port_ops mlx5_esw_dl_port_ops = {
- .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
- .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
- .port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
- .port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
- .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get,
- .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set,
-};
-
-int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num)
-{
- struct mlx5_core_dev *dev = esw->dev;
- struct devlink_port *dl_port;
- unsigned int dl_port_index;
- struct mlx5_vport *vport;
- struct devlink *devlink;
- int err;
+ struct mlx5_devlink_port *dl_port;
+ u16 vport_num = vport->vport;
if (!mlx5_esw_devlink_port_supported(esw, vport_num))
return 0;
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
- return PTR_ERR(vport);
-
- dl_port = mlx5_esw_dl_port_alloc(esw, vport_num);
+ dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
if (!dl_port)
return -ENOMEM;
- devlink = priv_to_devlink(dev);
- dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
- err = devl_port_register_with_ops(devlink, dl_port, dl_port_index,
- &mlx5_esw_dl_port_ops);
- if (err)
- goto reg_err;
-
- err = devl_rate_leaf_create(dl_port, vport, NULL);
- if (err)
- goto rate_err;
+ mlx5_esw_offloads_pf_vf_devlink_port_attrs_set(esw, vport_num,
+ &dl_port->dl_port);
vport->dl_port = dl_port;
+ mlx5_devlink_port_init(dl_port, vport);
return 0;
-
-rate_err:
- devl_port_unregister(dl_port);
-reg_err:
- mlx5_esw_dl_port_free(dl_port);
- return err;
}
-void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num)
+void mlx5_esw_offloads_pf_vf_devlink_port_cleanup(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport)
{
- struct mlx5_vport *vport;
-
- if (!mlx5_esw_devlink_port_supported(esw, vport_num))
+ if (!vport->dl_port)
return;
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
- return;
+ kfree(vport->dl_port);
+ vport->dl_port = NULL;
+}
- if (vport->dl_port->devlink_rate) {
- mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
- devl_rate_leaf_destroy(vport->dl_port);
- }
+static const struct devlink_port_ops mlx5_esw_pf_vf_dl_port_ops = {
+ .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get,
+ .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set,
+ .port_fn_roce_get = mlx5_devlink_port_fn_roce_get,
+ .port_fn_roce_set = mlx5_devlink_port_fn_roce_set,
+ .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get,
+ .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set,
+#ifdef CONFIG_XFRM_OFFLOAD
+ .port_fn_ipsec_crypto_get = mlx5_devlink_port_fn_ipsec_crypto_get,
+ .port_fn_ipsec_crypto_set = mlx5_devlink_port_fn_ipsec_crypto_set,
+ .port_fn_ipsec_packet_get = mlx5_devlink_port_fn_ipsec_packet_get,
+ .port_fn_ipsec_packet_set = mlx5_devlink_port_fn_ipsec_packet_set,
+#endif /* CONFIG_XFRM_OFFLOAD */
+};
- devl_port_unregister(vport->dl_port);
- mlx5_esw_dl_port_free(vport->dl_port);
- vport->dl_port = NULL;
+static void mlx5_esw_offloads_sf_devlink_port_attrs_set(struct mlx5_eswitch *esw,
+ struct devlink_port *dl_port,
+ u32 controller, u32 sfnum)
+{
+ struct mlx5_core_dev *dev = esw->dev;
+ struct netdev_phys_item_id ppid = {};
+ u16 pfnum;
+
+ pfnum = mlx5_get_dev_index(dev);
+ mlx5_esw_get_port_parent_id(dev, &ppid);
+ memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len);
+ dl_port->attrs.switch_id.id_len = ppid.id_len;
+ devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller);
}
-struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num)
+int mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ struct mlx5_devlink_port *dl_port,
+ u32 controller, u32 sfnum)
{
- struct mlx5_vport *vport;
+ mlx5_esw_offloads_sf_devlink_port_attrs_set(esw, &dl_port->dl_port, controller, sfnum);
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- return IS_ERR(vport) ? ERR_CAST(vport) : vport->dl_port;
+ vport->dl_port = dl_port;
+ mlx5_devlink_port_init(dl_port, vport);
+ return 0;
+}
+
+void mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ vport->dl_port = NULL;
}
static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
@@ -164,58 +145,62 @@ static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = {
#endif
};
-int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
- u16 vport_num, u32 controller, u32 sfnum)
+int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
struct mlx5_core_dev *dev = esw->dev;
- struct netdev_phys_item_id ppid = {};
+ const struct devlink_port_ops *ops;
+ struct mlx5_devlink_port *dl_port;
+ u16 vport_num = vport->vport;
unsigned int dl_port_index;
- struct mlx5_vport *vport;
struct devlink *devlink;
- u16 pfnum;
int err;
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
- return PTR_ERR(vport);
+ dl_port = vport->dl_port;
+ if (!dl_port)
+ return 0;
+
+ if (mlx5_esw_is_sf_vport(esw, vport_num))
+ ops = &mlx5_esw_dl_sf_port_ops;
+ else if (mlx5_eswitch_is_pf_vf_vport(esw, vport_num))
+ ops = &mlx5_esw_pf_vf_dl_port_ops;
+ else
+ ops = NULL;
- pfnum = mlx5_get_dev_index(dev);
- mlx5_esw_get_port_parent_id(dev, &ppid);
- memcpy(dl_port->attrs.switch_id.id, &ppid.id[0], ppid.id_len);
- dl_port->attrs.switch_id.id_len = ppid.id_len;
- devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller);
devlink = priv_to_devlink(dev);
dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num);
- err = devl_port_register_with_ops(devlink, dl_port, dl_port_index,
- &mlx5_esw_dl_sf_port_ops);
+ err = devl_port_register_with_ops(devlink, &dl_port->dl_port, dl_port_index, ops);
if (err)
return err;
- err = devl_rate_leaf_create(dl_port, vport, NULL);
+ err = devl_rate_leaf_create(&dl_port->dl_port, vport, NULL);
if (err)
goto rate_err;
- vport->dl_port = dl_port;
return 0;
rate_err:
- devl_port_unregister(dl_port);
+ devl_port_unregister(&dl_port->dl_port);
return err;
}
-void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num)
+void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
- struct mlx5_vport *vport;
+ struct mlx5_devlink_port *dl_port;
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
+ if (!vport->dl_port)
return;
+ dl_port = vport->dl_port;
- if (vport->dl_port->devlink_rate) {
- mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
- devl_rate_leaf_destroy(vport->dl_port);
- }
+ mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
+ devl_rate_leaf_destroy(&dl_port->dl_port);
- devl_port_unregister(vport->dl_port);
- vport->dl_port = NULL;
+ devl_port_unregister(&dl_port->dl_port);
+}
+
+struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_vport *vport;
+
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ return IS_ERR(vport) ? ERR_CAST(vport) : &vport->dl_port->dl_port;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec.c
new file mode 100644
index 000000000000..da10e04777cf
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include <linux/mlx5/device.h>
+#include <linux/mlx5/vport.h>
+#include "mlx5_core.h"
+#include "eswitch.h"
+
+static int esw_ipsec_vf_query_generic(struct mlx5_core_dev *dev, u16 vport_num, bool *result)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *hca_cap, *query_cap;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
+ return -EOPNOTSUPP;
+
+ if (!mlx5_esw_ipsec_vf_offload_supported(dev)) {
+ *result = false;
+ return 0;
+ }
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ err = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
+ if (err)
+ goto free;
+
+ hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ *result = MLX5_GET(cmd_hca_cap, hca_cap, ipsec_offload);
+free:
+ kvfree(query_cap);
+ return err;
+}
+
+enum esw_vport_ipsec_offload {
+ MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD,
+ MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD,
+};
+
+int mlx5_esw_ipsec_vf_offload_get(struct mlx5_core_dev *dev, struct mlx5_vport *vport)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *hca_cap, *query_cap;
+ bool ipsec_enabled;
+ int err;
+
+ /* Querying IPsec caps only makes sense when generic ipsec_offload
+ * HCA cap is enabled
+ */
+ err = esw_ipsec_vf_query_generic(dev, vport->vport, &ipsec_enabled);
+ if (err)
+ return err;
+
+ if (!ipsec_enabled) {
+ vport->info.ipsec_crypto_enabled = false;
+ vport->info.ipsec_packet_enabled = false;
+ return 0;
+ }
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ err = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
+ if (err)
+ goto free;
+
+ hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ vport->info.ipsec_crypto_enabled =
+ MLX5_GET(ipsec_cap, hca_cap, ipsec_crypto_offload);
+ vport->info.ipsec_packet_enabled =
+ MLX5_GET(ipsec_cap, hca_cap, ipsec_full_offload);
+free:
+ kvfree(query_cap);
+ return err;
+}
+
+static int esw_ipsec_vf_set_generic(struct mlx5_core_dev *dev, u16 vport_num, bool ipsec_ofld)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
+ void *hca_cap, *query_cap, *cap;
+ int ret;
+
+ if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
+ return -EOPNOTSUPP;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ hca_cap = kvzalloc(set_sz, GFP_KERNEL);
+ if (!hca_cap || !query_cap) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ ret = mlx5_vport_get_other_func_general_cap(dev, vport_num, query_cap);
+ if (ret)
+ goto free;
+
+ cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
+ memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
+ MLX5_UN_SZ_BYTES(hca_cap_union));
+ MLX5_SET(cmd_hca_cap, cap, ipsec_offload, ipsec_ofld);
+
+ MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
+ MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
+ MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport_num);
+
+ MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
+ MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1);
+ ret = mlx5_cmd_exec_in(dev, set_hca_cap, hca_cap);
+free:
+ kvfree(hca_cap);
+ kvfree(query_cap);
+ return ret;
+}
+
+static int esw_ipsec_vf_set_bytype(struct mlx5_core_dev *dev, struct mlx5_vport *vport,
+ bool enable, enum esw_vport_ipsec_offload type)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
+ void *hca_cap, *query_cap, *cap;
+ int ret;
+
+ if (!MLX5_CAP_GEN(dev, vhca_resource_manager))
+ return -EOPNOTSUPP;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ hca_cap = kvzalloc(set_sz, GFP_KERNEL);
+ if (!hca_cap || !query_cap) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ ret = mlx5_vport_get_other_func_cap(dev, vport->vport, query_cap, MLX5_CAP_IPSEC);
+ if (ret)
+ goto free;
+
+ cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
+ memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
+ MLX5_UN_SZ_BYTES(hca_cap_union));
+
+ switch (type) {
+ case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
+ MLX5_SET(ipsec_cap, cap, ipsec_crypto_offload, enable);
+ break;
+ case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
+ MLX5_SET(ipsec_cap, cap, ipsec_full_offload, enable);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto free;
+ }
+
+ MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
+ MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
+ MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport->vport);
+
+ MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
+ MLX5_SET_HCA_CAP_OP_MOD_IPSEC << 1);
+ ret = mlx5_cmd_exec_in(dev, set_hca_cap, hca_cap);
+free:
+ kvfree(hca_cap);
+ kvfree(query_cap);
+ return ret;
+}
+
+static int esw_ipsec_vf_crypto_aux_caps_set(struct mlx5_core_dev *dev, u16 vport_num, bool enable)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in);
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+ void *hca_cap, *query_cap, *cap;
+ int ret;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ hca_cap = kvzalloc(set_sz, GFP_KERNEL);
+ if (!hca_cap || !query_cap) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
+ if (ret)
+ goto free;
+
+ cap = MLX5_ADDR_OF(set_hca_cap_in, hca_cap, capability);
+ memcpy(cap, MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability),
+ MLX5_UN_SZ_BYTES(hca_cap_union));
+ MLX5_SET(per_protocol_networking_offload_caps, cap, insert_trailer, enable);
+ MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP);
+ MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1);
+ MLX5_SET(set_hca_cap_in, hca_cap, function_id, vport_num);
+ MLX5_SET(set_hca_cap_in, hca_cap, op_mod,
+ MLX5_SET_HCA_CAP_OP_MOD_ETHERNET_OFFLOADS << 1);
+ ret = mlx5_cmd_exec_in(esw->dev, set_hca_cap, hca_cap);
+free:
+ kvfree(hca_cap);
+ kvfree(query_cap);
+ return ret;
+}
+
+static int esw_ipsec_vf_offload_set_bytype(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ bool enable, enum esw_vport_ipsec_offload type)
+{
+ struct mlx5_core_dev *dev = esw->dev;
+ int err;
+
+ if (vport->vport == MLX5_VPORT_PF)
+ return -EOPNOTSUPP;
+
+ if (type == MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD) {
+ err = esw_ipsec_vf_crypto_aux_caps_set(dev, vport->vport, enable);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
+ if (err)
+ return err;
+ err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
+ if (err)
+ return err;
+ } else {
+ err = esw_ipsec_vf_set_bytype(dev, vport, enable, type);
+ if (err)
+ return err;
+ err = mlx5_esw_ipsec_vf_offload_get(dev, vport);
+ if (err)
+ return err;
+
+ /* The generic ipsec_offload cap can be disabled only if both
+ * ipsec_crypto_offload and ipsec_full_offload aren't enabled.
+ */
+ if (!vport->info.ipsec_crypto_enabled &&
+ !vport->info.ipsec_packet_enabled) {
+ err = esw_ipsec_vf_set_generic(dev, vport->vport, enable);
+ if (err)
+ return err;
+ }
+ }
+
+ switch (type) {
+ case MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD:
+ vport->info.ipsec_crypto_enabled = enable;
+ break;
+ case MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD:
+ vport->info.ipsec_packet_enabled = enable;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int esw_ipsec_offload_supported(struct mlx5_core_dev *dev, u16 vport_num)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *hca_cap, *query_cap;
+ int ret;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_GENERAL);
+ if (ret)
+ goto free;
+
+ hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ if (!MLX5_GET(cmd_hca_cap, hca_cap, log_max_dek))
+ ret = -EOPNOTSUPP;
+free:
+ kvfree(query_cap);
+ return ret;
+}
+
+bool mlx5_esw_ipsec_vf_offload_supported(struct mlx5_core_dev *dev)
+{
+ /* Old firmware doesn't support ipsec_offload capability for VFs. This
+ * can be detected by checking reformat_add_esp_trasport capability -
+ * when this cap isn't supported it means firmware cannot be trusted
+ * about what it reports for ipsec_offload cap.
+ */
+ return MLX5_CAP_FLOWTABLE_NIC_TX(dev, reformat_add_esp_trasport);
+}
+
+int mlx5_esw_ipsec_vf_crypto_offload_supported(struct mlx5_core_dev *dev,
+ u16 vport_num)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *hca_cap, *query_cap;
+ int err;
+
+ if (!mlx5_esw_ipsec_vf_offload_supported(dev))
+ return -EOPNOTSUPP;
+
+ err = esw_ipsec_offload_supported(dev, vport_num);
+ if (err)
+ return err;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ err = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_ETHERNET_OFFLOADS);
+ if (err)
+ goto free;
+
+ hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ if (!MLX5_GET(per_protocol_networking_offload_caps, hca_cap, swp))
+ goto free;
+
+free:
+ kvfree(query_cap);
+ return err;
+}
+
+int mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev *dev,
+ u16 vport_num)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *hca_cap, *query_cap;
+ int ret;
+
+ if (!mlx5_esw_ipsec_vf_offload_supported(dev))
+ return -EOPNOTSUPP;
+
+ ret = esw_ipsec_offload_supported(dev, vport_num);
+ if (ret)
+ return ret;
+
+ query_cap = kvzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ ret = mlx5_vport_get_other_func_cap(dev, vport_num, query_cap, MLX5_CAP_FLOW_TABLE);
+ if (ret)
+ goto out;
+
+ hca_cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ if (!MLX5_GET(flow_table_nic_cap, hca_cap, flow_table_properties_nic_receive.decap)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+out:
+ kvfree(query_cap);
+ return ret;
+}
+
+int mlx5_esw_ipsec_vf_crypto_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ bool enable)
+{
+ return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
+ MLX5_ESW_VPORT_IPSEC_CRYPTO_OFFLOAD);
+}
+
+int mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ bool enable)
+{
+ return esw_ipsec_vf_offload_set_bytype(esw, vport, enable,
+ MLX5_ESW_VPORT_IPSEC_PACKET_OFFLOAD);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
new file mode 100644
index 000000000000..095f31f380fa
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include "fs_core.h"
+#include "eswitch.h"
+#include "en_accel/ipsec.h"
+#include "esw/ipsec_fs.h"
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
+#include "en/tc_priv.h"
+#endif
+
+enum {
+ MLX5_ESW_IPSEC_RX_POL_FT_LEVEL,
+ MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL,
+ MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL,
+};
+
+enum {
+ MLX5_ESW_IPSEC_TX_POL_FT_LEVEL,
+ MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL,
+ MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL,
+};
+
+static void esw_ipsec_rx_status_drop_destroy(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx)
+{
+ mlx5_del_flow_rules(rx->status_drop.rule);
+ mlx5_destroy_flow_group(rx->status_drop.group);
+ mlx5_fc_destroy(ipsec->mdev, rx->status_drop_cnt);
+}
+
+static void esw_ipsec_rx_status_pass_destroy(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx)
+{
+ mlx5_del_flow_rules(rx->status.rule);
+ mlx5_chains_put_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
+}
+
+static int esw_ipsec_rx_status_drop_create(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_flow_table *ft = rx->ft.status;
+ struct mlx5_core_dev *mdev = ipsec->mdev;
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *rule;
+ struct mlx5_fc *flow_counter;
+ struct mlx5_flow_spec *spec;
+ struct mlx5_flow_group *g;
+ u32 *flow_group_in;
+ int err = 0;
+
+ flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!flow_group_in || !spec) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
+ MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
+ g = mlx5_create_flow_group(ft, flow_group_in);
+ if (IS_ERR(g)) {
+ err = PTR_ERR(g);
+ mlx5_core_err(mdev,
+ "Failed to add ipsec rx status drop flow group, err=%d\n", err);
+ goto err_out;
+ }
+
+ flow_counter = mlx5_fc_create(mdev, false);
+ if (IS_ERR(flow_counter)) {
+ err = PTR_ERR(flow_counter);
+ mlx5_core_err(mdev,
+ "Failed to add ipsec rx status drop rule counter, err=%d\n", err);
+ goto err_cnt;
+ }
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ dest.counter_id = mlx5_fc_id(flow_counter);
+ spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
+ rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev,
+ "Failed to add ipsec rx status drop rule, err=%d\n", err);
+ goto err_rule;
+ }
+
+ rx->status_drop.group = g;
+ rx->status_drop.rule = rule;
+ rx->status_drop_cnt = flow_counter;
+
+ kvfree(flow_group_in);
+ kvfree(spec);
+ return 0;
+
+err_rule:
+ mlx5_fc_destroy(mdev, flow_counter);
+err_cnt:
+ mlx5_destroy_flow_group(g);
+err_out:
+ kvfree(flow_group_in);
+ kvfree(spec);
+ return err;
+}
+
+static int esw_ipsec_rx_status_pass_create(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5_flow_destination *dest)
+{
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ int err;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ misc_parameters_2.ipsec_syndrome);
+ MLX5_SET(fte_match_param, spec->match_value,
+ misc_parameters_2.ipsec_syndrome, 0);
+ spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
+ flow_act.flags = FLOW_ACT_NO_APPEND;
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+ MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ rule = mlx5_add_flow_rules(rx->ft.status, spec, &flow_act, dest, 2);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_warn(ipsec->mdev,
+ "Failed to add ipsec rx status pass rule, err=%d\n", err);
+ goto err_rule;
+ }
+
+ rx->status.rule = rule;
+ kvfree(spec);
+ return 0;
+
+err_rule:
+ kvfree(spec);
+ return err;
+}
+
+void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx)
+{
+ esw_ipsec_rx_status_pass_destroy(ipsec, rx);
+ esw_ipsec_rx_status_drop_destroy(ipsec, rx);
+}
+
+int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5_flow_destination *dest)
+{
+ int err;
+
+ err = esw_ipsec_rx_status_drop_create(ipsec, rx);
+ if (err)
+ return err;
+
+ err = esw_ipsec_rx_status_pass_create(ipsec, rx, dest);
+ if (err)
+ goto err_pass_create;
+
+ return 0;
+
+err_pass_create:
+ esw_ipsec_rx_status_drop_destroy(ipsec, rx);
+ return err;
+}
+
+void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx_create_attr *attr)
+{
+ attr->prio = FDB_CRYPTO_INGRESS;
+ attr->pol_level = MLX5_ESW_IPSEC_RX_POL_FT_LEVEL;
+ attr->sa_level = MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL;
+ attr->status_level = MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL;
+ attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
+}
+
+int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
+ struct mlx5_flow_destination *dest)
+{
+ dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest->ft = mlx5_chains_get_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
+
+ return 0;
+}
+
+int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
+ struct mlx5_flow_act *flow_act)
+{
+ u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
+ struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
+ struct mlx5_core_dev *mdev = ipsec->mdev;
+ struct mlx5_modify_hdr *modify_hdr;
+ u32 mapped_id;
+ int err;
+
+ err = xa_alloc_bh(&ipsec->rx_esw->ipsec_obj_id_map, &mapped_id,
+ xa_mk_value(sa_entry->ipsec_obj_id),
+ XA_LIMIT(1, ESW_IPSEC_RX_MAPPED_ID_MASK), 0);
+ if (err)
+ return err;
+
+ /* reuse tunnel bits for ipsec,
+ * tun_id is always 0 and tun_opts is mapped to ipsec_obj_id.
+ */
+ MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
+ MLX5_SET(set_action_in, action, field,
+ MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
+ MLX5_SET(set_action_in, action, offset, ESW_ZONE_ID_BITS);
+ MLX5_SET(set_action_in, action, length,
+ ESW_TUN_ID_BITS + ESW_TUN_OPTS_BITS);
+ MLX5_SET(set_action_in, action, data, mapped_id);
+
+ modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_FDB,
+ 1, action);
+ if (IS_ERR(modify_hdr)) {
+ err = PTR_ERR(modify_hdr);
+ goto err_header_alloc;
+ }
+
+ sa_entry->rx_mapped_id = mapped_id;
+ flow_act->modify_hdr = modify_hdr;
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+
+ return 0;
+
+err_header_alloc:
+ xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map, mapped_id);
+ return err;
+}
+
+void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry)
+{
+ struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
+
+ if (sa_entry->rx_mapped_id)
+ xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map,
+ sa_entry->rx_mapped_id);
+}
+
+int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
+ u32 *ipsec_obj_id)
+{
+ struct mlx5e_ipsec *ipsec = priv->ipsec;
+ void *val;
+
+ val = xa_load(&ipsec->rx_esw->ipsec_obj_id_map, id);
+ if (!val)
+ return -ENOENT;
+
+ *ipsec_obj_id = xa_to_value(val);
+
+ return 0;
+}
+
+void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx_create_attr *attr)
+{
+ attr->prio = FDB_CRYPTO_EGRESS;
+ attr->pol_level = MLX5_ESW_IPSEC_TX_POL_FT_LEVEL;
+ attr->sa_level = MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL;
+ attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL;
+ attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
+}
+
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
+static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
+ struct mlx5e_tc_flow *flow)
+{
+ struct mlx5_esw_flow_attr *esw_attr;
+ struct mlx5_flow_attr *attr;
+ int err;
+
+ attr = flow->attr;
+ esw_attr = attr->esw_attr;
+ if (esw_attr->out_count - esw_attr->split_count > 1)
+ return 0;
+
+ err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
+ esw_attr->out_count - 1);
+
+ return err;
+}
+#endif
+
+void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
+{
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+ struct mlx5_eswitch_rep *rep;
+ struct mlx5e_rep_priv *rpriv;
+ struct rhashtable_iter iter;
+ struct mlx5e_tc_flow *flow;
+ unsigned long i;
+ int err;
+
+ xa_for_each(&esw->offloads.vport_reps, i, rep) {
+ rpriv = rep->rep_data[REP_ETH].priv;
+ if (!rpriv || !rpriv->netdev)
+ continue;
+
+ rhashtable_walk_enter(&rpriv->tc_ht, &iter);
+ rhashtable_walk_start(&iter);
+ while ((flow = rhashtable_walk_next(&iter)) != NULL) {
+ if (IS_ERR(flow))
+ continue;
+
+ err = mlx5_esw_ipsec_modify_flow_dests(esw, flow);
+ if (err)
+ mlx5_core_warn_once(mdev,
+ "Failed to modify flow dests for IPsec");
+ }
+ rhashtable_walk_stop(&iter);
+ rhashtable_walk_exit(&iter);
+ }
+#endif
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h
new file mode 100644
index 000000000000..0c90f7a8b0d3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_ESW_IPSEC_FS_H__
+#define __MLX5_ESW_IPSEC_FS_H__
+
+struct mlx5e_ipsec;
+struct mlx5e_ipsec_sa_entry;
+
+#ifdef CONFIG_MLX5_ESWITCH
+void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx);
+int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5_flow_destination *dest);
+void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx_create_attr *attr);
+int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
+ struct mlx5_flow_destination *dest);
+int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
+ struct mlx5_flow_act *flow_act);
+void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry);
+int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
+ u32 *ipsec_obj_id);
+void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx_create_attr *attr);
+void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev);
+#else
+static inline void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx) {}
+
+static inline int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx *rx,
+ struct mlx5_flow_destination *dest)
+{
+ return -EINVAL;
+}
+
+static inline void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_rx_create_attr *attr) {}
+
+static inline int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
+ struct mlx5_flow_destination *dest)
+{
+ return -EINVAL;
+}
+
+static inline int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
+ struct mlx5_flow_act *flow_act)
+{
+ return -EINVAL;
+}
+
+static inline void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry) {}
+
+static inline int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
+ u32 *ipsec_obj_id)
+{
+ return -EINVAL;
+}
+
+static inline void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
+ struct mlx5e_ipsec_tx_create_attr *attr) {}
+
+static inline void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev) {}
+#endif /* CONFIG_MLX5_ESWITCH */
+#endif /* __MLX5_ESW_IPSEC_FS_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
index 7c79476cc5f9..1887a24ee414 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
@@ -740,7 +740,7 @@ int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32
static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *name,
u64 *rate, struct netlink_ext_ack *extack)
{
- u32 link_speed_max, reminder;
+ u32 link_speed_max, remainder;
u64 value;
int err;
@@ -750,8 +750,8 @@ static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *
return err;
}
- value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &reminder);
- if (reminder) {
+ value = div_u64_rem(*rate, MLX5_LINKSPEED_UNIT, &remainder);
+ if (remainder) {
pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
name, *rate);
NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 243c455f1029..6cd7d6497e10 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -48,6 +48,7 @@
#include "devlink.h"
#include "ecpf.h"
#include "en/mod_hdr.h"
+#include "en_accel/ipsec.h"
enum {
MLX5_ACTION_NONE = 0,
@@ -77,18 +78,31 @@ static int mlx5_eswitch_check(const struct mlx5_core_dev *dev)
return 0;
}
-struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink)
+static struct mlx5_eswitch *__mlx5_devlink_eswitch_get(struct devlink *devlink, bool check)
{
struct mlx5_core_dev *dev = devlink_priv(devlink);
int err;
- err = mlx5_eswitch_check(dev);
- if (err)
- return ERR_PTR(err);
+ if (check) {
+ err = mlx5_eswitch_check(dev);
+ if (err)
+ return ERR_PTR(err);
+ }
return dev->priv.eswitch;
}
+struct mlx5_eswitch *__must_check
+mlx5_devlink_eswitch_get(struct devlink *devlink)
+{
+ return __mlx5_devlink_eswitch_get(devlink, true);
+}
+
+struct mlx5_eswitch *mlx5_devlink_eswitch_nocheck_get(struct devlink *devlink)
+{
+ return __mlx5_devlink_eswitch_get(devlink, false);
+}
+
struct mlx5_vport *__must_check
mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)
{
@@ -818,6 +832,8 @@ static int mlx5_esw_vport_caps_get(struct mlx5_eswitch *esw, struct mlx5_vport *
hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
vport->info.mig_enabled = MLX5_GET(cmd_hca_cap_2, hca_caps, migratable);
+
+ err = mlx5_esw_ipsec_vf_offload_get(esw->dev, vport);
out_free:
kfree(query_ctx);
return err;
@@ -882,16 +898,12 @@ static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport
esw_vport_cleanup_acl(esw, vport);
}
-int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
+int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
enum mlx5_eswitch_vport_event enabled_events)
{
- struct mlx5_vport *vport;
+ u16 vport_num = vport->vport;
int ret;
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
- return PTR_ERR(vport);
-
mutex_lock(&esw->state_lock);
WARN_ON(vport->enabled);
@@ -904,6 +916,9 @@ int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
/* Sync with current vport context */
vport->enabled_events = enabled_events;
vport->enabled = true;
+ if (vport->vport != MLX5_VPORT_PF &&
+ (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))
+ esw->enabled_ipsec_vf_count++;
/* Esw manager is trusted by default. Host PF (vport 0) is trusted as well
* in smartNIC as it's a vport group manager.
@@ -912,7 +927,7 @@ int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
(!vport_num && mlx5_core_is_ecpf(esw->dev)))
vport->info.trusted = true;
- if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
+ if (!mlx5_esw_is_manager_vport(esw, vport_num) &&
MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
ret = mlx5_esw_vport_vhca_id_set(esw, vport_num);
if (ret)
@@ -939,15 +954,12 @@ err_vhca_mapping:
return ret;
}
-void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
+void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
- struct mlx5_vport *vport;
-
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport))
- return;
+ u16 vport_num = vport->vport;
mutex_lock(&esw->state_lock);
+
if (!vport->enabled)
goto done;
@@ -957,12 +969,16 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
/* Disable events from this vport */
if (MLX5_CAP_GEN(esw->dev, log_max_l2_table))
- arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
+ arm_vport_context_events_cmd(esw->dev, vport_num, 0);
- if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
+ if (!mlx5_esw_is_manager_vport(esw, vport_num) &&
MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
mlx5_esw_vport_vhca_id_clear(esw, vport_num);
+ if (vport->vport != MLX5_VPORT_PF &&
+ (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))
+ esw->enabled_ipsec_vf_count--;
+
/* We don't assume VFs will cleanup after themselves.
* Calling vport change handler while vport is disabled will cleanup
* the vport resources.
@@ -1068,31 +1084,104 @@ static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw)
}
}
-/* Public E-Switch API */
-int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num,
- enum mlx5_eswitch_vport_event enabled_events)
+static int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ enum mlx5_eswitch_vport_event enabled_events)
{
int err;
- err = mlx5_esw_vport_enable(esw, vport_num, enabled_events);
+ err = mlx5_esw_vport_enable(esw, vport, enabled_events);
if (err)
return err;
- err = esw_offloads_load_rep(esw, vport_num);
+ err = mlx5_esw_offloads_load_rep(esw, vport);
if (err)
goto err_rep;
return err;
err_rep:
- mlx5_esw_vport_disable(esw, vport_num);
+ mlx5_esw_vport_disable(esw, vport);
+ return err;
+}
+
+static void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ mlx5_esw_offloads_unload_rep(esw, vport);
+ mlx5_esw_vport_disable(esw, vport);
+}
+
+static int mlx5_eswitch_load_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num,
+ enum mlx5_eswitch_vport_event enabled_events)
+{
+ struct mlx5_vport *vport;
+ int err;
+
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ err = mlx5_esw_offloads_init_pf_vf_rep(esw, vport);
+ if (err)
+ return err;
+
+ err = mlx5_eswitch_load_vport(esw, vport, enabled_events);
+ if (err)
+ goto err_load;
+ return 0;
+
+err_load:
+ mlx5_esw_offloads_cleanup_pf_vf_rep(esw, vport);
+ return err;
+}
+
+static void mlx5_eswitch_unload_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ struct mlx5_vport *vport;
+
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return;
+
+ mlx5_eswitch_unload_vport(esw, vport);
+ mlx5_esw_offloads_cleanup_pf_vf_rep(esw, vport);
+}
+
+int mlx5_eswitch_load_sf_vport(struct mlx5_eswitch *esw, u16 vport_num,
+ enum mlx5_eswitch_vport_event enabled_events,
+ struct mlx5_devlink_port *dl_port, u32 controller, u32 sfnum)
+{
+ struct mlx5_vport *vport;
+ int err;
+
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
+
+ err = mlx5_esw_offloads_init_sf_rep(esw, vport, dl_port, controller, sfnum);
+ if (err)
+ return err;
+
+ err = mlx5_eswitch_load_vport(esw, vport, enabled_events);
+ if (err)
+ goto err_load;
+
+ return 0;
+
+err_load:
+ mlx5_esw_offloads_cleanup_sf_rep(esw, vport);
return err;
}
-void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num)
+void mlx5_eswitch_unload_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)
{
- esw_offloads_unload_rep(esw, vport_num);
- mlx5_esw_vport_disable(esw, vport_num);
+ struct mlx5_vport *vport;
+
+ vport = mlx5_eswitch_get_vport(esw, vport_num);
+ if (IS_ERR(vport))
+ return;
+
+ mlx5_eswitch_unload_vport(esw, vport);
+ mlx5_esw_offloads_cleanup_sf_rep(esw, vport);
}
void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs)
@@ -1103,7 +1192,7 @@ void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs)
mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {
if (!vport->enabled)
continue;
- mlx5_eswitch_unload_vport(esw, vport->vport);
+ mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport);
}
}
@@ -1116,7 +1205,7 @@ static void mlx5_eswitch_unload_ec_vf_vports(struct mlx5_eswitch *esw,
mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) {
if (!vport->enabled)
continue;
- mlx5_eswitch_unload_vport(esw, vport->vport);
+ mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport);
}
}
@@ -1128,7 +1217,7 @@ int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs,
int err;
mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {
- err = mlx5_eswitch_load_vport(esw, vport->vport, enabled_events);
+ err = mlx5_eswitch_load_pf_vf_vport(esw, vport->vport, enabled_events);
if (err)
goto vf_err;
}
@@ -1148,7 +1237,7 @@ static int mlx5_eswitch_load_ec_vf_vports(struct mlx5_eswitch *esw, u16 num_ec_v
int err;
mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) {
- err = mlx5_eswitch_load_vport(esw, vport->vport, enabled_events);
+ err = mlx5_eswitch_load_pf_vf_vport(esw, vport->vport, enabled_events);
if (err)
goto vf_err;
}
@@ -1190,7 +1279,7 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
int ret;
/* Enable PF vport */
- ret = mlx5_eswitch_load_vport(esw, MLX5_VPORT_PF, enabled_events);
+ ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_PF, enabled_events);
if (ret)
return ret;
@@ -1201,7 +1290,7 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
/* Enable ECPF vport */
if (mlx5_ecpf_vport_exists(esw->dev)) {
- ret = mlx5_eswitch_load_vport(esw, MLX5_VPORT_ECPF, enabled_events);
+ ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_ECPF, enabled_events);
if (ret)
goto ecpf_err;
if (mlx5_core_ec_sriov_enabled(esw->dev)) {
@@ -1224,11 +1313,11 @@ vf_err:
mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs);
ec_vf_err:
if (mlx5_ecpf_vport_exists(esw->dev))
- mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF);
+ mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF);
ecpf_err:
host_pf_disable_hca(esw->dev);
pf_hca_err:
- mlx5_eswitch_unload_vport(esw, MLX5_VPORT_PF);
+ mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
return ret;
}
@@ -1242,11 +1331,11 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
if (mlx5_ecpf_vport_exists(esw->dev)) {
if (mlx5_core_ec_sriov_enabled(esw->dev))
mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_vfs);
- mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF);
+ mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF);
}
host_pf_disable_hca(esw->dev);
- mlx5_eswitch_unload_vport(esw, MLX5_VPORT_PF);
+ mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
}
static void mlx5_eswitch_get_devlink_param(struct mlx5_eswitch *esw)
@@ -1919,6 +2008,12 @@ bool mlx5_eswitch_is_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)
return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_VF);
}
+bool mlx5_eswitch_is_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)
+{
+ return vport_num == MLX5_VPORT_PF ||
+ mlx5_eswitch_is_vf_vport(esw, vport_num);
+}
+
bool mlx5_esw_is_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)
{
return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_SF);
@@ -2251,3 +2346,34 @@ struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw)
return mlx5_esw_allowed(esw) ? esw->dev : NULL;
}
EXPORT_SYMBOL(mlx5_eswitch_get_core_dev);
+
+bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+
+ if (!mlx5_esw_allowed(esw))
+ return true;
+
+ mutex_lock(&esw->state_lock);
+ if (esw->enabled_ipsec_vf_count) {
+ mutex_unlock(&esw->state_lock);
+ return false;
+ }
+
+ dev->num_ipsec_offloads++;
+ mutex_unlock(&esw->state_lock);
+ return true;
+}
+
+void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+
+ if (!mlx5_esw_allowed(esw))
+ /* Failure means no eswitch => core dev is not a PF */
+ return;
+
+ mutex_lock(&esw->state_lock);
+ dev->num_ipsec_offloads--;
+ mutex_unlock(&esw->state_lock);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index ae0dc8a3060d..37ab66e7b403 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -163,6 +163,8 @@ struct mlx5_vport_info {
u8 trusted: 1;
u8 roce_enabled: 1;
u8 mig_enabled: 1;
+ u8 ipsec_crypto_enabled: 1;
+ u8 ipsec_packet_enabled: 1;
};
/* Vport context events */
@@ -172,6 +174,29 @@ enum mlx5_eswitch_vport_event {
MLX5_VPORT_PROMISC_CHANGE = BIT(3),
};
+struct mlx5_vport;
+
+struct mlx5_devlink_port {
+ struct devlink_port dl_port;
+ struct mlx5_vport *vport;
+};
+
+static inline void mlx5_devlink_port_init(struct mlx5_devlink_port *dl_port,
+ struct mlx5_vport *vport)
+{
+ dl_port->vport = vport;
+}
+
+static inline struct mlx5_devlink_port *mlx5_devlink_port_get(struct devlink_port *dl_port)
+{
+ return container_of(dl_port, struct mlx5_devlink_port, dl_port);
+}
+
+static inline struct mlx5_vport *mlx5_devlink_port_vport_get(struct devlink_port *dl_port)
+{
+ return mlx5_devlink_port_get(dl_port)->vport;
+}
+
struct mlx5_vport {
struct mlx5_core_dev *dev;
struct hlist_head uc_list[MLX5_L2_ADDR_HASH_SIZE];
@@ -200,7 +225,7 @@ struct mlx5_vport {
bool enabled;
enum mlx5_eswitch_vport_event enabled_events;
int index;
- struct devlink_port *dl_port;
+ struct mlx5_devlink_port *dl_port;
};
struct mlx5_esw_indir_table;
@@ -254,6 +279,7 @@ struct mlx5_esw_offload {
struct mlx5_flow_group *vport_rx_group;
struct mlx5_flow_group *vport_rx_drop_group;
struct mlx5_flow_handle *vport_rx_drop_rule;
+ struct mlx5_flow_table *ft_ipsec_tx_pol;
struct xarray vport_reps;
struct list_head peer_flows[MLX5_MAX_PORTS];
struct mutex peer_mutex;
@@ -269,6 +295,7 @@ struct mlx5_esw_offload {
u8 inline_mode;
atomic64_t num_flows;
u64 num_block_encap;
+ u64 num_block_mode;
enum devlink_eswitch_encap_mode encap;
struct ida vport_metadata_ida;
unsigned int host_number; /* ECPF supports one external host */
@@ -354,6 +381,8 @@ struct mlx5_eswitch {
} params;
struct blocking_notifier_head n_head;
struct xarray paired;
+ struct mlx5_devcom_comp_dev *devcom;
+ u16 enabled_ipsec_vf_count;
};
void esw_offloads_disable(struct mlx5_eswitch *esw);
@@ -381,8 +410,9 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs);
void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf);
void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw);
void mlx5_eswitch_disable(struct mlx5_eswitch *esw);
-void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw);
+void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw, u64 key);
void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw);
+bool mlx5_esw_offloads_devcom_is_ready(struct mlx5_eswitch *esw);
int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
u16 vport, const u8 *mac);
int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
@@ -531,6 +561,16 @@ int mlx5_devlink_port_fn_migratable_get(struct devlink_port *port, bool *is_enab
struct netlink_ext_ack *extack);
int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable,
struct netlink_ext_ack *extack);
+#ifdef CONFIG_XFRM_OFFLOAD
+int mlx5_devlink_port_fn_ipsec_crypto_get(struct devlink_port *port, bool *is_enabled,
+ struct netlink_ext_ack *extack);
+int mlx5_devlink_port_fn_ipsec_crypto_set(struct devlink_port *port, bool enable,
+ struct netlink_ext_ack *extack);
+int mlx5_devlink_port_fn_ipsec_packet_get(struct devlink_port *port, bool *is_enabled,
+ struct netlink_ext_ack *extack);
+int mlx5_devlink_port_fn_ipsec_packet_set(struct devlink_port *port, bool enable,
+ struct netlink_ext_ack *extack);
+#endif /* CONFIG_XFRM_OFFLOAD */
void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type);
int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
@@ -671,11 +711,16 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
MLX5_CAP_GEN_2((esw->dev), ec_vf_vport_base) +\
(last) - 1)
-struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink);
+struct mlx5_eswitch *__must_check
+mlx5_devlink_eswitch_get(struct devlink *devlink);
+
+struct mlx5_eswitch *mlx5_devlink_eswitch_nocheck_get(struct devlink *devlink);
+
struct mlx5_vport *__must_check
mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num);
bool mlx5_eswitch_is_vf_vport(struct mlx5_eswitch *esw, u16 vport_num);
+bool mlx5_eswitch_is_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num);
bool mlx5_esw_is_sf_vport(struct mlx5_eswitch *esw, u16 vport_num);
int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data);
@@ -685,9 +730,9 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
enum mlx5_eswitch_vport_event enabled_events);
void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw);
-int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
+int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
enum mlx5_eswitch_vport_event enabled_events);
-void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num);
+void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
int
esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw,
@@ -725,31 +770,40 @@ void mlx5_esw_set_spec_source_port(struct mlx5_eswitch *esw,
u16 vport,
struct mlx5_flow_spec *spec);
-int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num);
-void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num);
+int mlx5_esw_offloads_init_pf_vf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+void mlx5_esw_offloads_cleanup_pf_vf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+
+int mlx5_esw_offloads_init_sf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ struct mlx5_devlink_port *dl_port,
+ u32 controller, u32 sfnum);
+void mlx5_esw_offloads_cleanup_sf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
-int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num);
-void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num);
+int mlx5_esw_offloads_load_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+void mlx5_esw_offloads_unload_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
-int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num,
- enum mlx5_eswitch_vport_event enabled_events);
-void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num);
+int mlx5_eswitch_load_sf_vport(struct mlx5_eswitch *esw, u16 vport_num,
+ enum mlx5_eswitch_vport_event enabled_events,
+ struct mlx5_devlink_port *dl_port, u32 controller, u32 sfnum);
+void mlx5_eswitch_unload_sf_vport(struct mlx5_eswitch *esw, u16 vport_num);
int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs,
enum mlx5_eswitch_vport_event enabled_events);
void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs);
-int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num);
-void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, u16 vport_num);
-struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num);
+int mlx5_esw_offloads_pf_vf_devlink_port_init(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
+void mlx5_esw_offloads_pf_vf_devlink_port_cleanup(struct mlx5_eswitch *esw,
+ struct mlx5_vport *vport);
+
+int mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ struct mlx5_devlink_port *dl_port,
+ u32 controller, u32 sfnum);
+void mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
-int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
- u16 vport_num, u32 controller, u32 sfnum);
-void mlx5_esw_devlink_sf_port_unregister(struct mlx5_eswitch *esw, u16 vport_num);
+int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
+struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num);
-int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
- u16 vport_num, u32 controller, u32 sfnum);
-void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num);
int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id);
int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num);
@@ -788,6 +842,9 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev);
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
+int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev);
+void mlx5_eswitch_unblock_mode(struct mlx5_core_dev *dev);
+
static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
{
if (mlx5_esw_allowed(esw))
@@ -809,6 +866,24 @@ mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw)
return esw->fdb_table.offloads.slow_fdb;
}
+int mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
+ struct mlx5_esw_flow_attr *esw_attr, int attr_idx);
+bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev);
+void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev);
+bool mlx5_esw_ipsec_vf_offload_supported(struct mlx5_core_dev *dev);
+int mlx5_esw_ipsec_vf_offload_get(struct mlx5_core_dev *dev,
+ struct mlx5_vport *vport);
+int mlx5_esw_ipsec_vf_crypto_offload_supported(struct mlx5_core_dev *dev,
+ u16 vport_num);
+int mlx5_esw_ipsec_vf_crypto_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ bool enable);
+int mlx5_esw_ipsec_vf_packet_offload_set(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ bool enable);
+int mlx5_esw_ipsec_vf_packet_offload_supported(struct mlx5_core_dev *dev,
+ u16 vport_num);
+void mlx5_esw_vport_ipsec_offload_enable(struct mlx5_eswitch *esw);
+void mlx5_esw_vport_ipsec_offload_disable(struct mlx5_eswitch *esw);
+
#else /* CONFIG_MLX5_ESWITCH */
/* eswitch API stubs */
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
@@ -816,8 +891,9 @@ static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) { return 0; }
static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) {}
static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {}
-static inline void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) {}
+static inline void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw, u64 key) {}
static inline void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) {}
+static inline bool mlx5_esw_offloads_devcom_is_ready(struct mlx5_eswitch *esw) { return false; }
static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; }
static inline
int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, u16 vport, int link_state) { return 0; }
@@ -866,6 +942,15 @@ static inline bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
{
}
+
+static inline int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev) { return 0; }
+static inline void mlx5_eswitch_unblock_mode(struct mlx5_core_dev *dev) {}
+static inline bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev)
+{
+ return false;
+}
+
+static inline void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev) {}
#endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_ESWITCH_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index e59380ee1ead..752fb0dfb111 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -375,7 +375,6 @@ esw_setup_indir_table(struct mlx5_flow_destination *dest,
struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw,
struct mlx5_flow_attr *attr,
- bool ignore_flow_lvl,
int *i)
{
struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
@@ -385,8 +384,7 @@ esw_setup_indir_table(struct mlx5_flow_destination *dest,
return -EOPNOTSUPP;
for (j = esw_attr->split_count; j < esw_attr->out_count; j++, (*i)++) {
- if (ignore_flow_lvl)
- flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
+ flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[*i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[*i].ft = mlx5_esw_indir_table_get(esw, attr,
@@ -424,10 +422,51 @@ esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 l
mlx5_chains_put_table(chains, chain, prio, level);
}
+static bool esw_same_vhca_id(struct mlx5_core_dev *mdev1, struct mlx5_core_dev *mdev2)
+{
+ return MLX5_CAP_GEN(mdev1, vhca_id) == MLX5_CAP_GEN(mdev2, vhca_id);
+}
+
+static bool esw_setup_uplink_fwd_ipsec_needed(struct mlx5_eswitch *esw,
+ struct mlx5_esw_flow_attr *esw_attr,
+ int attr_idx)
+{
+ if (esw->offloads.ft_ipsec_tx_pol &&
+ esw_attr->dests[attr_idx].rep &&
+ esw_attr->dests[attr_idx].rep->vport == MLX5_VPORT_UPLINK &&
+ /* To be aligned with software, encryption is needed only for tunnel device */
+ (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) &&
+ esw_attr->dests[attr_idx].rep != esw_attr->in_rep &&
+ esw_same_vhca_id(esw_attr->dests[attr_idx].mdev, esw->dev))
+ return true;
+
+ return false;
+}
+
+static bool esw_flow_dests_fwd_ipsec_check(struct mlx5_eswitch *esw,
+ struct mlx5_esw_flow_attr *esw_attr)
+{
+ int i;
+
+ if (!esw->offloads.ft_ipsec_tx_pol)
+ return true;
+
+ for (i = 0; i < esw_attr->split_count; i++)
+ if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i))
+ return false;
+
+ for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
+ if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i) &&
+ (esw_attr->out_count - esw_attr->split_count > 1))
+ return false;
+
+ return true;
+}
+
static void
-esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
- struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
- int attr_idx, int dest_idx, bool pkt_reformat)
+esw_setup_dest_fwd_vport(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
+ struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
+ int attr_idx, int dest_idx, bool pkt_reformat)
{
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
@@ -449,6 +488,33 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
}
}
+static void
+esw_setup_dest_fwd_ipsec(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
+ struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
+ int attr_idx, int dest_idx, bool pkt_reformat)
+{
+ dest[dest_idx].ft = esw->offloads.ft_ipsec_tx_pol;
+ dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ if (pkt_reformat &&
+ esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+ flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
+ }
+}
+
+static void
+esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
+ struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
+ int attr_idx, int dest_idx, bool pkt_reformat)
+{
+ if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
+ esw_setup_dest_fwd_ipsec(dest, flow_act, esw, esw_attr,
+ attr_idx, dest_idx, pkt_reformat);
+ else
+ esw_setup_dest_fwd_vport(dest, flow_act, esw, esw_attr,
+ attr_idx, dest_idx, pkt_reformat);
+}
+
static int
esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
@@ -469,6 +535,28 @@ esw_src_port_rewrite_supported(struct mlx5_eswitch *esw)
MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ignore_flow_level);
}
+static bool
+esw_dests_to_vf_pf_vports(struct mlx5_flow_destination *dests, int max_dest)
+{
+ bool vf_dest = false, pf_dest = false;
+ int i;
+
+ for (i = 0; i < max_dest; i++) {
+ if (dests[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT)
+ continue;
+
+ if (dests[i].vport.num == MLX5_VPORT_UPLINK)
+ pf_dest = true;
+ else
+ vf_dest = true;
+
+ if (vf_dest && pf_dest)
+ return true;
+ }
+
+ return false;
+}
+
static int
esw_setup_dests(struct mlx5_flow_destination *dest,
struct mlx5_flow_act *flow_act,
@@ -501,7 +589,7 @@ esw_setup_dests(struct mlx5_flow_destination *dest,
err = esw_setup_mtu_dest(dest, &attr->meter_attr, *i);
(*i)++;
} else if (esw_is_indir_table(esw, attr)) {
- err = esw_setup_indir_table(dest, flow_act, esw, attr, true, i);
+ err = esw_setup_indir_table(dest, flow_act, esw, attr, i);
} else if (esw_is_chain_src_port_rewrite(esw, esw_attr)) {
err = esw_setup_chain_src_port_rewrite(dest, flow_act, esw, chains, attr, i);
} else {
@@ -575,6 +663,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
return ERR_PTR(-EOPNOTSUPP);
+ if (!esw_flow_dests_fwd_ipsec_check(esw, esw_attr))
+ return ERR_PTR(-EOPNOTSUPP);
+
dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL);
if (!dest)
return ERR_PTR(-ENOMEM);
@@ -602,6 +693,15 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
rule = ERR_PTR(err);
goto err_create_goto_table;
}
+
+ /* Header rewrite with combined wire+loopback in FDB is not allowed */
+ if ((flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) &&
+ esw_dests_to_vf_pf_vports(dest, i)) {
+ esw_warn(esw->dev,
+ "FDB: Header rewrite with forwarding to both PF and VF is not allowed\n");
+ rule = ERR_PTR(-EINVAL);
+ goto err_esw_get;
+ }
}
if (esw_attr->decap_pkt_reformat)
@@ -884,6 +984,17 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw,
dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ if (rep->vport == MLX5_VPORT_UPLINK && on_esw->offloads.ft_ipsec_tx_pol) {
+ dest.ft = on_esw->offloads.ft_ipsec_tx_pol;
+ flow_act.flags = FLOW_ACT_IGNORE_FLOW_LEVEL;
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ } else {
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+ dest.vport.num = rep->vport;
+ dest.vport.vhca_id = MLX5_CAP_GEN(rep->esw->dev, vhca_id);
+ dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
+ }
+
if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) &&
rep->vport == MLX5_VPORT_UPLINK)
spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
@@ -2390,7 +2501,7 @@ static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
__esw_offloads_unload_rep(esw, rep, rep_type);
}
-int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num)
+static int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num)
{
struct mlx5_eswitch_rep *rep;
int rep_type;
@@ -2414,7 +2525,7 @@ err_reps:
return err;
}
-void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num)
+static void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num)
{
struct mlx5_eswitch_rep *rep;
int rep_type;
@@ -2424,39 +2535,63 @@ void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num)
__esw_offloads_unload_rep(esw, rep, rep_type);
}
-int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num)
+int mlx5_esw_offloads_init_pf_vf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ if (esw->mode != MLX5_ESWITCH_OFFLOADS)
+ return 0;
+
+ return mlx5_esw_offloads_pf_vf_devlink_port_init(esw, vport);
+}
+
+void mlx5_esw_offloads_cleanup_pf_vf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ if (esw->mode != MLX5_ESWITCH_OFFLOADS)
+ return;
+
+ mlx5_esw_offloads_pf_vf_devlink_port_cleanup(esw, vport);
+}
+
+int mlx5_esw_offloads_init_sf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
+ struct mlx5_devlink_port *dl_port,
+ u32 controller, u32 sfnum)
+{
+ return mlx5_esw_offloads_sf_devlink_port_init(esw, vport, dl_port, controller, sfnum);
+}
+
+void mlx5_esw_offloads_cleanup_sf_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
+{
+ mlx5_esw_offloads_sf_devlink_port_cleanup(esw, vport);
+}
+
+int mlx5_esw_offloads_load_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
int err;
if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return 0;
- if (vport_num != MLX5_VPORT_UPLINK) {
- err = mlx5_esw_offloads_devlink_port_register(esw, vport_num);
- if (err)
- return err;
- }
+ err = mlx5_esw_offloads_devlink_port_register(esw, vport);
+ if (err)
+ return err;
- err = mlx5_esw_offloads_rep_load(esw, vport_num);
+ err = mlx5_esw_offloads_rep_load(esw, vport->vport);
if (err)
goto load_err;
return err;
load_err:
- if (vport_num != MLX5_VPORT_UPLINK)
- mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
+ mlx5_esw_offloads_devlink_port_unregister(esw, vport);
return err;
}
-void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num)
+void mlx5_esw_offloads_unload_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
if (esw->mode != MLX5_ESWITCH_OFFLOADS)
return;
- mlx5_esw_offloads_rep_unload(esw, vport_num);
+ mlx5_esw_offloads_rep_unload(esw, vport->vport);
- if (vport_num != MLX5_VPORT_UPLINK)
- mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
+ mlx5_esw_offloads_devlink_port_unregister(esw, vport);
}
static int esw_set_slave_root_fdb(struct mlx5_core_dev *master,
@@ -2810,7 +2945,6 @@ static int mlx5_esw_offloads_devcom_event(int event,
void *event_data)
{
struct mlx5_eswitch *esw = my_data;
- struct mlx5_devcom *devcom = esw->dev->priv.devcom;
struct mlx5_eswitch *peer_esw = event_data;
u16 esw_i, peer_esw_i;
bool esw_paired;
@@ -2832,6 +2966,7 @@ static int mlx5_esw_offloads_devcom_event(int event,
err = mlx5_esw_offloads_set_ns_peer(esw, peer_esw, true);
if (err)
goto err_out;
+
err = mlx5_esw_offloads_pair(esw, peer_esw);
if (err)
goto err_peer;
@@ -2850,7 +2985,7 @@ static int mlx5_esw_offloads_devcom_event(int event,
esw->num_peers++;
peer_esw->num_peers++;
- mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
+ mlx5_devcom_comp_set_ready(esw->devcom, true);
break;
case ESW_OFFLOADS_DEVCOM_UNPAIR:
@@ -2860,7 +2995,7 @@ static int mlx5_esw_offloads_devcom_event(int event,
peer_esw->num_peers--;
esw->num_peers--;
if (!esw->num_peers && !peer_esw->num_peers)
- mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
+ mlx5_devcom_comp_set_ready(esw->devcom, false);
xa_erase(&peer_esw->paired, esw_i);
xa_erase(&esw->paired, peer_esw_i);
mlx5_esw_offloads_unpair(peer_esw, esw);
@@ -2885,9 +3020,8 @@ err_out:
return err;
}
-void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw)
+void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw, u64 key)
{
- struct mlx5_devcom *devcom = esw->dev->priv.devcom;
int i;
for (i = 0; i < MLX5_MAX_PORTS; i++)
@@ -2897,38 +3031,44 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw)
if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
return;
- if (!mlx5_lag_is_supported(esw->dev))
+ if ((MLX5_VPORT_MANAGER(esw->dev) || mlx5_core_is_ecpf_esw_manager(esw->dev)) &&
+ !mlx5_lag_is_supported(esw->dev))
return;
xa_init(&esw->paired);
- mlx5_devcom_register_component(devcom,
- MLX5_DEVCOM_ESW_OFFLOADS,
- mlx5_esw_offloads_devcom_event,
- esw);
-
esw->num_peers = 0;
- mlx5_devcom_send_event(devcom,
- MLX5_DEVCOM_ESW_OFFLOADS,
+ esw->devcom = mlx5_devcom_register_component(esw->dev->priv.devc,
+ MLX5_DEVCOM_ESW_OFFLOADS,
+ key,
+ mlx5_esw_offloads_devcom_event,
+ esw);
+ if (IS_ERR_OR_NULL(esw->devcom))
+ return;
+
+ mlx5_devcom_send_event(esw->devcom,
ESW_OFFLOADS_DEVCOM_PAIR,
- ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
+ ESW_OFFLOADS_DEVCOM_UNPAIR,
+ esw);
}
void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
{
- struct mlx5_devcom *devcom = esw->dev->priv.devcom;
-
- if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
- return;
-
- if (!mlx5_lag_is_supported(esw->dev))
+ if (IS_ERR_OR_NULL(esw->devcom))
return;
- mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
+ mlx5_devcom_send_event(esw->devcom,
ESW_OFFLOADS_DEVCOM_UNPAIR,
- ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
+ ESW_OFFLOADS_DEVCOM_UNPAIR,
+ esw);
- mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
+ mlx5_devcom_unregister_component(esw->devcom);
xa_destroy(&esw->paired);
+ esw->devcom = NULL;
+}
+
+bool mlx5_esw_offloads_devcom_is_ready(struct mlx5_eswitch *esw)
+{
+ return mlx5_devcom_comp_is_ready(esw->devcom);
}
bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
@@ -3355,7 +3495,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN;
/* Uplink vport rep must load first. */
- err = esw_offloads_load_rep(esw, MLX5_VPORT_UPLINK);
+ err = mlx5_esw_offloads_rep_load(esw, MLX5_VPORT_UPLINK);
if (err)
goto err_uplink;
@@ -3366,7 +3506,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
return 0;
err_vports:
- esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
+ mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
err_uplink:
esw_offloads_steering_cleanup(esw);
err_steering_init:
@@ -3404,7 +3544,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
void esw_offloads_disable(struct mlx5_eswitch *esw)
{
mlx5_eswitch_disable_pf_vf_vports(esw);
- esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
+ mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
esw_set_passing_vport_metadata(esw, false);
esw_offloads_steering_cleanup(esw);
mapping_destroy(esw->offloads.reg_c0_obj_pool);
@@ -3494,13 +3634,43 @@ static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink)
struct net *devl_net, *netdev_net;
struct mlx5_eswitch *esw;
- esw = mlx5_devlink_eswitch_get(devlink);
+ esw = mlx5_devlink_eswitch_nocheck_get(devlink);
netdev_net = dev_net(esw->dev->mlx5e_res.uplink_netdev);
devl_net = devlink_net(devlink);
return net_eq(devl_net, netdev_net);
}
+int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+ int err;
+
+ if (!mlx5_esw_allowed(esw))
+ return 0;
+
+ /* Take TC into account */
+ err = mlx5_esw_try_lock(esw);
+ if (err < 0)
+ return err;
+
+ esw->offloads.num_block_mode++;
+ mlx5_esw_unlock(esw);
+ return 0;
+}
+
+void mlx5_eswitch_unblock_mode(struct mlx5_core_dev *dev)
+{
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
+
+ if (!mlx5_esw_allowed(esw))
+ return;
+
+ down_write(&esw->mode_lock);
+ esw->offloads.num_block_mode--;
+ up_write(&esw->mode_lock);
+}
+
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack)
{
@@ -3534,6 +3704,13 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (cur_mlx5_mode == mlx5_mode)
goto unlock;
+ if (esw->offloads.num_block_mode) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can't change eswitch mode when IPsec SA and/or policies are configured");
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
+
mlx5_eswitch_disable_locked(esw);
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
@@ -3693,38 +3870,28 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
{
- struct devlink *devlink = priv_to_devlink(dev);
- struct mlx5_eswitch *esw;
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
- devl_lock(devlink);
- esw = mlx5_devlink_eswitch_get(devlink);
- if (IS_ERR(esw)) {
- devl_unlock(devlink);
- /* Failure means no eswitch => not possible to change encap */
+ if (!mlx5_esw_allowed(esw))
return true;
- }
down_write(&esw->mode_lock);
if (esw->mode != MLX5_ESWITCH_LEGACY &&
esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
up_write(&esw->mode_lock);
- devl_unlock(devlink);
return false;
}
esw->offloads.num_block_encap++;
up_write(&esw->mode_lock);
- devl_unlock(devlink);
return true;
}
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
{
- struct devlink *devlink = priv_to_devlink(dev);
- struct mlx5_eswitch *esw;
+ struct mlx5_eswitch *esw = dev->priv.eswitch;
- esw = mlx5_devlink_eswitch_get(devlink);
- if (IS_ERR(esw))
+ if (!mlx5_esw_allowed(esw))
return;
down_write(&esw->mode_lock);
@@ -3920,38 +4087,6 @@ u32 mlx5_eswitch_get_vport_metadata_for_match(struct mlx5_eswitch *esw,
}
EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);
-int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
- u16 vport_num, u32 controller, u32 sfnum)
-{
- int err;
-
- err = mlx5_esw_vport_enable(esw, vport_num, MLX5_VPORT_UC_ADDR_CHANGE);
- if (err)
- return err;
-
- err = mlx5_esw_devlink_sf_port_register(esw, dl_port, vport_num, controller, sfnum);
- if (err)
- goto devlink_err;
-
- err = mlx5_esw_offloads_rep_load(esw, vport_num);
- if (err)
- goto rep_err;
- return 0;
-
-rep_err:
- mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
-devlink_err:
- mlx5_esw_vport_disable(esw, vport_num);
- return err;
-}
-
-void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
-{
- mlx5_esw_offloads_rep_unload(esw, vport_num);
- mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
- mlx5_esw_vport_disable(esw, vport_num);
-}
-
static int mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch *esw, u16 vport_num, u16 *vhca_id)
{
int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
@@ -4040,35 +4175,12 @@ u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
}
EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_set);
-static bool
-is_port_function_supported(struct mlx5_eswitch *esw, u16 vport_num)
-{
- return vport_num == MLX5_VPORT_PF ||
- mlx5_eswitch_is_vf_vport(esw, vport_num) ||
- mlx5_esw_is_sf_vport(esw, vport_num);
-}
-
int mlx5_devlink_port_fn_hw_addr_get(struct devlink_port *port,
u8 *hw_addr, int *hw_addr_len,
struct netlink_ext_ack *extack)
{
- struct mlx5_eswitch *esw;
- struct mlx5_vport *vport;
- u16 vport_num;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw))
- return PTR_ERR(esw);
-
- vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
- if (!is_port_function_supported(esw, vport_num))
- return -EOPNOTSUPP;
-
- vport = mlx5_eswitch_get_vport(esw, vport_num);
- if (IS_ERR(vport)) {
- NL_SET_ERR_MSG_MOD(extack, "Invalid port");
- return PTR_ERR(vport);
- }
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
mutex_lock(&esw->state_lock);
ether_addr_copy(hw_addr, vport->info.mac);
@@ -4081,100 +4193,55 @@ int mlx5_devlink_port_fn_hw_addr_set(struct devlink_port *port,
const u8 *hw_addr, int hw_addr_len,
struct netlink_ext_ack *extack)
{
- struct mlx5_eswitch *esw;
- u16 vport_num;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw)) {
- NL_SET_ERR_MSG_MOD(extack, "Eswitch doesn't support set hw_addr");
- return PTR_ERR(esw);
- }
-
- vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
- if (!is_port_function_supported(esw, vport_num)) {
- NL_SET_ERR_MSG_MOD(extack, "Port doesn't support set hw_addr");
- return -EINVAL;
- }
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
- return mlx5_eswitch_set_vport_mac(esw, vport_num, hw_addr);
-}
-
-static struct mlx5_vport *
-mlx5_devlink_port_fn_get_vport(struct devlink_port *port, struct mlx5_eswitch *esw)
-{
- u16 vport_num;
-
- if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
- return ERR_PTR(-EOPNOTSUPP);
-
- vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
- if (!is_port_function_supported(esw, vport_num))
- return ERR_PTR(-EOPNOTSUPP);
-
- return mlx5_eswitch_get_vport(esw, vport_num);
+ return mlx5_eswitch_set_vport_mac(esw, vport->vport, hw_addr);
}
int mlx5_devlink_port_fn_migratable_get(struct devlink_port *port, bool *is_enabled,
struct netlink_ext_ack *extack)
{
- struct mlx5_eswitch *esw;
- struct mlx5_vport *vport;
- int err = -EOPNOTSUPP;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw))
- return PTR_ERR(esw);
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
if (!MLX5_CAP_GEN(esw->dev, migration)) {
NL_SET_ERR_MSG_MOD(extack, "Device doesn't support migration");
- return err;
+ return -EOPNOTSUPP;
}
- vport = mlx5_devlink_port_fn_get_vport(port, esw);
- if (IS_ERR(vport)) {
- NL_SET_ERR_MSG_MOD(extack, "Invalid port");
- return PTR_ERR(vport);
+ if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support VHCA management");
+ return -EOPNOTSUPP;
}
mutex_lock(&esw->state_lock);
- if (vport->enabled) {
- *is_enabled = vport->info.mig_enabled;
- err = 0;
- }
+ *is_enabled = vport->info.mig_enabled;
mutex_unlock(&esw->state_lock);
- return err;
+ return 0;
}
int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable,
struct netlink_ext_ack *extack)
{
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
- struct mlx5_eswitch *esw;
- struct mlx5_vport *vport;
void *query_ctx;
void *hca_caps;
- int err = -EOPNOTSUPP;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw))
- return PTR_ERR(esw);
+ int err;
if (!MLX5_CAP_GEN(esw->dev, migration)) {
NL_SET_ERR_MSG_MOD(extack, "Device doesn't support migration");
- return err;
+ return -EOPNOTSUPP;
}
- vport = mlx5_devlink_port_fn_get_vport(port, esw);
- if (IS_ERR(vport)) {
- NL_SET_ERR_MSG_MOD(extack, "Invalid port");
- return PTR_ERR(vport);
+ if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support VHCA management");
+ return -EOPNOTSUPP;
}
mutex_lock(&esw->state_lock);
- if (!vport->enabled) {
- NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
- goto out;
- }
if (vport->info.mig_enabled == enable) {
err = 0;
@@ -4216,56 +4283,37 @@ out:
int mlx5_devlink_port_fn_roce_get(struct devlink_port *port, bool *is_enabled,
struct netlink_ext_ack *extack)
{
- struct mlx5_eswitch *esw;
- struct mlx5_vport *vport;
- int err = -EOPNOTSUPP;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw))
- return PTR_ERR(esw);
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
- vport = mlx5_devlink_port_fn_get_vport(port, esw);
- if (IS_ERR(vport)) {
- NL_SET_ERR_MSG_MOD(extack, "Invalid port");
- return PTR_ERR(vport);
+ if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support VHCA management");
+ return -EOPNOTSUPP;
}
mutex_lock(&esw->state_lock);
- if (vport->enabled) {
- *is_enabled = vport->info.roce_enabled;
- err = 0;
- }
+ *is_enabled = vport->info.roce_enabled;
mutex_unlock(&esw->state_lock);
- return err;
+ return 0;
}
int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
struct netlink_ext_ack *extack)
{
+ struct mlx5_eswitch *esw = mlx5_devlink_eswitch_nocheck_get(port->devlink);
+ struct mlx5_vport *vport = mlx5_devlink_port_vport_get(port);
int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
- struct mlx5_eswitch *esw;
- struct mlx5_vport *vport;
- int err = -EOPNOTSUPP;
+ u16 vport_num = vport->vport;
void *query_ctx;
void *hca_caps;
- u16 vport_num;
-
- esw = mlx5_devlink_eswitch_get(port->devlink);
- if (IS_ERR(esw))
- return PTR_ERR(esw);
+ int err;
- vport = mlx5_devlink_port_fn_get_vport(port, esw);
- if (IS_ERR(vport)) {
- NL_SET_ERR_MSG_MOD(extack, "Invalid port");
- return PTR_ERR(vport);
+ if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support VHCA management");
+ return -EOPNOTSUPP;
}
- vport_num = vport->vport;
mutex_lock(&esw->state_lock);
- if (!vport->enabled) {
- NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
- goto out;
- }
if (vport->info.roce_enabled == enable) {
err = 0;
@@ -4303,3 +4351,188 @@ out:
mutex_unlock(&esw->state_lock);
return err;
}
+
+int
+mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
+ struct mlx5_esw_flow_attr *esw_attr, int attr_idx)
+{
+ struct mlx5_flow_destination new_dest = {};
+ struct mlx5_flow_destination old_dest = {};
+
+ if (!esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
+ return 0;
+
+ esw_setup_dest_fwd_ipsec(&old_dest, NULL, esw, esw_attr, attr_idx, 0, false);
+ esw_setup_dest_fwd_vport(&new_dest, NULL, esw, esw_attr, attr_idx, 0, false);
+
+ return mlx5_modify_rule_destination(rule, &new_dest, &old_dest);
+}
+
+#ifdef CONFIG_XFRM_OFFLOAD
+int mlx5_devlink_port_fn_ipsec_crypto_get(struct devlink_port *port, bool *is_enabled,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ int err = 0;
+
+ esw = mlx5_devlink_eswitch_get(port->devlink);
+ if (IS_ERR(esw))
+ return PTR_ERR(esw);
+
+ if (!mlx5_esw_ipsec_vf_offload_supported(esw->dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support IPSec crypto");
+ return -EOPNOTSUPP;
+ }
+
+ vport = mlx5_devlink_port_vport_get(port);
+
+ mutex_lock(&esw->state_lock);
+ if (!vport->enabled) {
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ *is_enabled = vport->info.ipsec_crypto_enabled;
+unlock:
+ mutex_unlock(&esw->state_lock);
+ return err;
+}
+
+int mlx5_devlink_port_fn_ipsec_crypto_set(struct devlink_port *port, bool enable,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ u16 vport_num;
+ int err;
+
+ esw = mlx5_devlink_eswitch_get(port->devlink);
+ if (IS_ERR(esw))
+ return PTR_ERR(esw);
+
+ vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
+ err = mlx5_esw_ipsec_vf_crypto_offload_supported(esw->dev, vport_num);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Device doesn't support IPsec crypto");
+ return err;
+ }
+
+ vport = mlx5_devlink_port_vport_get(port);
+
+ mutex_lock(&esw->state_lock);
+ if (!vport->enabled) {
+ err = -EOPNOTSUPP;
+ NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
+ goto unlock;
+ }
+
+ if (vport->info.ipsec_crypto_enabled == enable)
+ goto unlock;
+
+ if (!esw->enabled_ipsec_vf_count && esw->dev->num_ipsec_offloads) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ err = mlx5_esw_ipsec_vf_crypto_offload_set(esw, vport, enable);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to set IPsec crypto");
+ goto unlock;
+ }
+
+ vport->info.ipsec_crypto_enabled = enable;
+ if (enable)
+ esw->enabled_ipsec_vf_count++;
+ else
+ esw->enabled_ipsec_vf_count--;
+unlock:
+ mutex_unlock(&esw->state_lock);
+ return err;
+}
+
+int mlx5_devlink_port_fn_ipsec_packet_get(struct devlink_port *port, bool *is_enabled,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ int err = 0;
+
+ esw = mlx5_devlink_eswitch_get(port->devlink);
+ if (IS_ERR(esw))
+ return PTR_ERR(esw);
+
+ if (!mlx5_esw_ipsec_vf_offload_supported(esw->dev)) {
+ NL_SET_ERR_MSG_MOD(extack, "Device doesn't support IPsec packet");
+ return -EOPNOTSUPP;
+ }
+
+ vport = mlx5_devlink_port_vport_get(port);
+
+ mutex_lock(&esw->state_lock);
+ if (!vport->enabled) {
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ *is_enabled = vport->info.ipsec_packet_enabled;
+unlock:
+ mutex_unlock(&esw->state_lock);
+ return err;
+}
+
+int mlx5_devlink_port_fn_ipsec_packet_set(struct devlink_port *port,
+ bool enable,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw;
+ struct mlx5_vport *vport;
+ u16 vport_num;
+ int err;
+
+ esw = mlx5_devlink_eswitch_get(port->devlink);
+ if (IS_ERR(esw))
+ return PTR_ERR(esw);
+
+ vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
+ err = mlx5_esw_ipsec_vf_packet_offload_supported(esw->dev, vport_num);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Device doesn't support IPsec packet mode");
+ return err;
+ }
+
+ vport = mlx5_devlink_port_vport_get(port);
+ mutex_lock(&esw->state_lock);
+ if (!vport->enabled) {
+ err = -EOPNOTSUPP;
+ NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
+ goto unlock;
+ }
+
+ if (vport->info.ipsec_packet_enabled == enable)
+ goto unlock;
+
+ if (!esw->enabled_ipsec_vf_count && esw->dev->num_ipsec_offloads) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ err = mlx5_esw_ipsec_vf_packet_offload_set(esw, vport, enable);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed to set IPsec packet mode");
+ goto unlock;
+ }
+
+ vport->info.ipsec_packet_enabled = enable;
+ if (enable)
+ esw->enabled_ipsec_vf_count++;
+ else
+ esw->enabled_ipsec_vf_count--;
+unlock:
+ mutex_unlock(&esw->state_lock);
+ return err;
+}
+#endif /* CONFIG_XFRM_OFFLOAD */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
index 12abe991583a..c4de6bf8d1b6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
@@ -445,7 +445,7 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
goto err_cqwq;
}
- err = mlx5_vector2eqn(mdev, smp_processor_id(), &eqn);
+ err = mlx5_comp_eqn_get(mdev, smp_processor_id(), &eqn);
if (err) {
kvfree(in);
goto err_cqwq;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
index 39c03dcbd196..e5c1012921d2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
@@ -57,7 +57,7 @@ static const char * const mlx5_fpga_qp_error_strings[] = {
};
static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void)
{
- struct mlx5_fpga_device *fdev = NULL;
+ struct mlx5_fpga_device *fdev;
fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
if (!fdev)
@@ -252,7 +252,7 @@ out:
int mlx5_fpga_init(struct mlx5_core_dev *mdev)
{
- struct mlx5_fpga_device *fdev = NULL;
+ struct mlx5_fpga_device *fdev;
if (!MLX5_CAP_GEN(mdev, fpga)) {
mlx5_core_dbg(mdev, "FPGA capability not present\n");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
index 244cfd470903..a4b925331661 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
@@ -975,6 +975,7 @@ static int mlx5_cmd_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
max_actions = MLX5_CAP_ESW_INGRESS_ACL(dev, max_modify_header_actions);
table_type = FS_FT_ESW_INGRESS_ACL;
break;
+ case MLX5_FLOW_NAMESPACE_RDMA_TX_MACSEC:
case MLX5_FLOW_NAMESPACE_RDMA_TX:
max_actions = MLX5_CAP_FLOWTABLE_RDMA_TX(dev, max_modify_header_actions);
table_type = FS_FT_RDMA_TX;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index 6b069fa411c5..a13b9c2bd144 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -107,7 +107,7 @@
LEFTOVERS_NUM_PRIOS)
#define KERNEL_RX_MACSEC_NUM_PRIOS 1
-#define KERNEL_RX_MACSEC_NUM_LEVELS 2
+#define KERNEL_RX_MACSEC_NUM_LEVELS 3
#define KERNEL_RX_MACSEC_MIN_LEVEL (BY_PASS_MIN_LEVEL + KERNEL_RX_MACSEC_NUM_PRIOS)
#define ETHTOOL_PRIO_NUM_LEVELS 1
@@ -224,6 +224,7 @@ static struct init_tree_node egress_root_fs = {
enum {
RDMA_RX_IPSEC_PRIO,
+ RDMA_RX_MACSEC_PRIO,
RDMA_RX_COUNTERS_PRIO,
RDMA_RX_BYPASS_PRIO,
RDMA_RX_KERNEL_PRIO,
@@ -237,9 +238,13 @@ enum {
#define RDMA_RX_KERNEL_MIN_LEVEL (RDMA_RX_BYPASS_MIN_LEVEL + 1)
#define RDMA_RX_COUNTERS_MIN_LEVEL (RDMA_RX_KERNEL_MIN_LEVEL + 2)
+#define RDMA_RX_MACSEC_NUM_PRIOS 1
+#define RDMA_RX_MACSEC_PRIO_NUM_LEVELS 2
+#define RDMA_RX_MACSEC_MIN_LEVEL (RDMA_RX_COUNTERS_MIN_LEVEL + RDMA_RX_MACSEC_NUM_PRIOS)
+
static struct init_tree_node rdma_rx_root_fs = {
.type = FS_TYPE_NAMESPACE,
- .ar_size = 4,
+ .ar_size = 5,
.children = (struct init_tree_node[]) {
[RDMA_RX_IPSEC_PRIO] =
ADD_PRIO(0, RDMA_RX_IPSEC_MIN_LEVEL, 0,
@@ -247,6 +252,12 @@ static struct init_tree_node rdma_rx_root_fs = {
ADD_NS(MLX5_FLOW_TABLE_MISS_ACTION_DEF,
ADD_MULTIPLE_PRIO(RDMA_RX_IPSEC_NUM_PRIOS,
RDMA_RX_IPSEC_NUM_LEVELS))),
+ [RDMA_RX_MACSEC_PRIO] =
+ ADD_PRIO(0, RDMA_RX_MACSEC_MIN_LEVEL, 0,
+ FS_CHAINING_CAPS,
+ ADD_NS(MLX5_FLOW_TABLE_MISS_ACTION_DEF,
+ ADD_MULTIPLE_PRIO(RDMA_RX_MACSEC_NUM_PRIOS,
+ RDMA_RX_MACSEC_PRIO_NUM_LEVELS))),
[RDMA_RX_COUNTERS_PRIO] =
ADD_PRIO(0, RDMA_RX_COUNTERS_MIN_LEVEL, 0,
FS_CHAINING_CAPS,
@@ -270,6 +281,7 @@ static struct init_tree_node rdma_rx_root_fs = {
enum {
RDMA_TX_COUNTERS_PRIO,
RDMA_TX_IPSEC_PRIO,
+ RDMA_TX_MACSEC_PRIO,
RDMA_TX_BYPASS_PRIO,
};
@@ -280,9 +292,13 @@ enum {
#define RDMA_TX_IPSEC_PRIO_NUM_LEVELS 1
#define RDMA_TX_IPSEC_MIN_LEVEL (RDMA_TX_COUNTERS_MIN_LEVEL + RDMA_TX_IPSEC_NUM_PRIOS)
+#define RDMA_TX_MACSEC_NUM_PRIOS 1
+#define RDMA_TX_MACESC_PRIO_NUM_LEVELS 1
+#define RDMA_TX_MACSEC_MIN_LEVEL (RDMA_TX_COUNTERS_MIN_LEVEL + RDMA_TX_MACSEC_NUM_PRIOS)
+
static struct init_tree_node rdma_tx_root_fs = {
.type = FS_TYPE_NAMESPACE,
- .ar_size = 3,
+ .ar_size = 4,
.children = (struct init_tree_node[]) {
[RDMA_TX_COUNTERS_PRIO] =
ADD_PRIO(0, RDMA_TX_COUNTERS_MIN_LEVEL, 0,
@@ -296,7 +312,12 @@ static struct init_tree_node rdma_tx_root_fs = {
ADD_NS(MLX5_FLOW_TABLE_MISS_ACTION_DEF,
ADD_MULTIPLE_PRIO(RDMA_TX_IPSEC_NUM_PRIOS,
RDMA_TX_IPSEC_PRIO_NUM_LEVELS))),
-
+ [RDMA_TX_MACSEC_PRIO] =
+ ADD_PRIO(0, RDMA_TX_MACSEC_MIN_LEVEL, 0,
+ FS_CHAINING_CAPS,
+ ADD_NS(MLX5_FLOW_TABLE_MISS_ACTION_DEF,
+ ADD_MULTIPLE_PRIO(RDMA_TX_MACSEC_NUM_PRIOS,
+ RDMA_TX_MACESC_PRIO_NUM_LEVELS))),
[RDMA_TX_BYPASS_PRIO] =
ADD_PRIO(0, RDMA_TX_BYPASS_MIN_LEVEL, 0,
FS_CHAINING_CAPS_RDMA_TX,
@@ -1122,7 +1143,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handle,
}
for (i = 0; i < handle->num_rules; i++) {
- if (mlx5_flow_dests_cmp(new_dest, &handle->rule[i]->dest_attr))
+ if (mlx5_flow_dests_cmp(old_dest, &handle->rule[i]->dest_attr))
return _mlx5_modify_rule_destination(handle->rule[i],
new_dest);
}
@@ -2466,6 +2487,14 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
root_ns = steering->rdma_tx_root_ns;
prio = RDMA_TX_IPSEC_PRIO;
break;
+ case MLX5_FLOW_NAMESPACE_RDMA_RX_MACSEC:
+ root_ns = steering->rdma_rx_root_ns;
+ prio = RDMA_RX_MACSEC_PRIO;
+ break;
+ case MLX5_FLOW_NAMESPACE_RDMA_TX_MACSEC:
+ root_ns = steering->rdma_tx_root_ns;
+ prio = RDMA_TX_MACSEC_PRIO;
+ break;
default: /* Must be NIC RX */
WARN_ON(!is_nic_rx_ns(type));
root_ns = steering->root_ns;
@@ -3050,6 +3079,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
if (err)
goto out_err;
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_CRYPTO_INGRESS, 3);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
+ goto out_err;
+ }
+
err = create_fdb_fast_path(steering);
if (err)
goto out_err;
@@ -3072,6 +3107,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
goto out_err;
}
+ maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_CRYPTO_EGRESS, 3);
+ if (IS_ERR(maj_prio)) {
+ err = PTR_ERR(maj_prio);
+ goto out_err;
+ }
+
/* We put this priority last, knowing that nothing will get here
* unless explicitly forwarded to. This is possible because the
* slow path tables have catch all rules and nothing gets passed
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index fb2035a5ec99..58f4c0d0fafa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -143,90 +143,86 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
{
int err;
- err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
if (MLX5_CAP_GEN(dev, port_selection_cap)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_PORT_SELECTION);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_PORT_SELECTION, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, hca_cap_2)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL_2);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_GENERAL_2, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ETHERNET_OFFLOADS,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_IPOIB_ENHANCED_OFFLOADS,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, pg)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ODP);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ODP, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, atomic)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ATOMIC, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, roce)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ROCE, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, nic_flow_table) ||
MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_FLOW_TABLE, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_ESWITCH_MANAGER(dev)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ESWITCH_FLOW_TABLE,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
- err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH);
- if (err)
- return err;
- }
-
- if (MLX5_CAP_GEN(dev, vector_calc)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_VECTOR_CALC);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ESWITCH, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, qos)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_QOS);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_QOS, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, debug))
- mlx5_core_get_caps(dev, MLX5_CAP_DEBUG);
+ mlx5_core_get_caps_mode(dev, MLX5_CAP_DEBUG, HCA_CAP_OPMOD_GET_CUR);
if (MLX5_CAP_GEN(dev, pcam_reg))
mlx5_get_pcam_reg(dev);
if (MLX5_CAP_GEN(dev, mcam_reg)) {
mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_FIRST_128);
- mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9080_0x90FF);
mlx5_get_mcam_access_reg_group(dev, MLX5_MCAM_REGS_0x9100_0x917F);
}
@@ -234,57 +230,52 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
mlx5_get_qcam_reg(dev);
if (MLX5_CAP_GEN(dev, device_memory)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_MEM);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_DEV_MEM, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, event_cap)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_EVENT);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_DEV_EVENT, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, tls_tx) || MLX5_CAP_GEN(dev, tls_rx)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_TLS);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_TLS, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN_64(dev, general_obj_types) &
MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_VDPA_EMULATION, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, ipsec_offload)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_IPSEC);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_IPSEC, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, crypto)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_CRYPTO);
- if (err)
- return err;
- }
-
- if (MLX5_CAP_GEN(dev, shampo)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_SHAMPO);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_CRYPTO, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN_64(dev, general_obj_types) &
MLX5_GENERAL_OBJ_TYPES_CAP_MACSEC_OFFLOAD) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_MACSEC);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_MACSEC, HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, adv_virtualization)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ADV_VIRTUALIZATION);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ADV_VIRTUALIZATION,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
index 4804990b7f22..e87766f91150 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
@@ -127,17 +127,23 @@ static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev,
if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state))
goto out;
+ if (!reset_state)
+ return 0;
+
switch (reset_state) {
case MLX5_MFRL_REG_RESET_STATE_IN_NEGOTIATION:
case MLX5_MFRL_REG_RESET_STATE_RESET_IN_PROGRESS:
- NL_SET_ERR_MSG_MOD(extack, "Sync reset was already triggered");
+ NL_SET_ERR_MSG_MOD(extack, "Sync reset still in progress");
return -EBUSY;
- case MLX5_MFRL_REG_RESET_STATE_TIMEOUT:
- NL_SET_ERR_MSG_MOD(extack, "Sync reset got timeout");
+ case MLX5_MFRL_REG_RESET_STATE_NEG_TIMEOUT:
+ NL_SET_ERR_MSG_MOD(extack, "Sync reset negotiation timeout");
return -ETIMEDOUT;
case MLX5_MFRL_REG_RESET_STATE_NACK:
NL_SET_ERR_MSG_MOD(extack, "One of the hosts disabled reset");
return -EPERM;
+ case MLX5_MFRL_REG_RESET_STATE_UNLOAD_TIMEOUT:
+ NL_SET_ERR_MSG_MOD(extack, "Sync reset unload timeout");
+ return -ETIMEDOUT;
}
out:
@@ -151,7 +157,7 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {};
u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {};
- int err;
+ int err, rst_res;
set_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
@@ -164,13 +170,34 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
return 0;
clear_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags);
- if (err == -EREMOTEIO && MLX5_CAP_MCAM_FEATURE(dev, reset_state))
- return mlx5_fw_reset_get_reset_state_err(dev, extack);
+ if (err == -EREMOTEIO && MLX5_CAP_MCAM_FEATURE(dev, reset_state)) {
+ rst_res = mlx5_fw_reset_get_reset_state_err(dev, extack);
+ return rst_res ? rst_res : err;
+ }
NL_SET_ERR_MSG_MOD(extack, "Sync reset command failed");
return mlx5_cmd_check(dev, err, in, out);
}
+int mlx5_fw_reset_verify_fw_complete(struct mlx5_core_dev *dev,
+ struct netlink_ext_ack *extack)
+{
+ u8 rst_state;
+ int err;
+
+ err = mlx5_fw_reset_get_reset_state_err(dev, extack);
+ if (err)
+ return err;
+
+ rst_state = mlx5_get_fw_rst_state(dev);
+ if (!rst_state)
+ return 0;
+
+ mlx5_core_err(dev, "Sync reset did not complete, state=%d\n", rst_state);
+ NL_SET_ERR_MSG_MOD(extack, "Sync reset did not complete successfully");
+ return rst_state;
+}
+
int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev)
{
return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
index c57465595f7c..ea527d06a85f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h
@@ -12,6 +12,8 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel,
int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev);
int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev);
+int mlx5_fw_reset_verify_fw_complete(struct mlx5_core_dev *dev,
+ struct netlink_ext_ack *extack);
void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev);
void mlx5_fw_reset_events_stop(struct mlx5_core_dev *dev);
void mlx5_drain_fw_reset(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 187cb2c464f8..2fb2598b775e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -50,20 +50,6 @@ enum {
};
enum {
- MLX5_HEALTH_SYNDR_FW_ERR = 0x1,
- MLX5_HEALTH_SYNDR_IRISC_ERR = 0x7,
- MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR = 0x8,
- MLX5_HEALTH_SYNDR_CRC_ERR = 0x9,
- MLX5_HEALTH_SYNDR_FETCH_PCI_ERR = 0xa,
- MLX5_HEALTH_SYNDR_HW_FTL_ERR = 0xb,
- MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR = 0xc,
- MLX5_HEALTH_SYNDR_EQ_ERR = 0xd,
- MLX5_HEALTH_SYNDR_EQ_INV = 0xe,
- MLX5_HEALTH_SYNDR_FFSER_ERR = 0xf,
- MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10
-};
-
-enum {
MLX5_DROP_HEALTH_WORK,
};
@@ -357,27 +343,27 @@ static int mlx5_health_try_recover(struct mlx5_core_dev *dev)
static const char *hsynd_str(u8 synd)
{
switch (synd) {
- case MLX5_HEALTH_SYNDR_FW_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_FW_INTERNAL_ERR:
return "firmware internal error";
- case MLX5_HEALTH_SYNDR_IRISC_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_DEAD_IRISC:
return "irisc not responding";
- case MLX5_HEALTH_SYNDR_HW_UNRECOVERABLE_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_HW_FATAL_ERR:
return "unrecoverable hardware error";
- case MLX5_HEALTH_SYNDR_CRC_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_FW_CRC_ERR:
return "firmware CRC error";
- case MLX5_HEALTH_SYNDR_FETCH_PCI_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_ICM_FETCH_PCI_ERR:
return "ICM fetch PCI error";
- case MLX5_HEALTH_SYNDR_HW_FTL_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_ICM_PAGE_ERR:
return "HW fatal error\n";
- case MLX5_HEALTH_SYNDR_ASYNC_EQ_OVERRUN_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_ASYNCHRONOUS_EQ_BUF_OVERRUN:
return "async EQ buffer overrun";
- case MLX5_HEALTH_SYNDR_EQ_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_EQ_IN_ERR:
return "EQ error";
- case MLX5_HEALTH_SYNDR_EQ_INV:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_EQ_INV:
return "Invalid EQ referenced";
- case MLX5_HEALTH_SYNDR_FFSER_ERR:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_FFSER_ERR:
return "FFSER error";
- case MLX5_HEALTH_SYNDR_HIGH_TEMP:
+ case MLX5_INITIAL_SEG_HEALTH_SYNDROME_HIGH_TEMP_ERR:
return "High temperature";
default:
return "unrecognized error";
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/hwmon.c b/drivers/net/ethernet/mellanox/mlx5/core/hwmon.c
new file mode 100644
index 000000000000..353f81dccd1c
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/hwmon.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+
+#include <linux/hwmon.h>
+#include <linux/bitmap.h>
+#include <linux/mlx5/device.h>
+#include <linux/mlx5/mlx5_ifc.h>
+#include <linux/mlx5/port.h>
+#include "mlx5_core.h"
+#include "hwmon.h"
+
+#define CHANNELS_TYPE_NUM 2 /* chip channel and temp channel */
+#define CHIP_CONFIG_NUM 1
+
+/* module 0 is mapped to sensor_index 64 in MTMP register */
+#define to_mtmp_module_sensor_idx(idx) (64 + (idx))
+
+/* All temperatures retrieved in units of 0.125C. hwmon framework expect
+ * it in units of millidegrees C. Hence multiply values by 125.
+ */
+#define mtmp_temp_to_mdeg(temp) ((temp) * 125)
+
+struct temp_channel_desc {
+ u32 sensor_index;
+ char sensor_name[32];
+};
+
+/* chip_channel_config and channel_info arrays must be 0-terminated, hence + 1 */
+struct mlx5_hwmon {
+ struct mlx5_core_dev *mdev;
+ struct device *hwmon_dev;
+ struct hwmon_channel_info chip_info;
+ u32 chip_channel_config[CHIP_CONFIG_NUM + 1];
+ struct hwmon_channel_info temp_info;
+ u32 *temp_channel_config;
+ const struct hwmon_channel_info *channel_info[CHANNELS_TYPE_NUM + 1];
+ struct hwmon_chip_info chip;
+ struct temp_channel_desc *temp_channel_desc;
+ u32 asic_platform_scount;
+ u32 module_scount;
+};
+
+static int mlx5_hwmon_query_mtmp(struct mlx5_core_dev *mdev, u32 sensor_index, u32 *mtmp_out)
+{
+ u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+
+ MLX5_SET(mtmp_reg, mtmp_in, sensor_index, sensor_index);
+
+ return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
+ mtmp_out, MLX5_ST_SZ_BYTES(mtmp_reg),
+ MLX5_REG_MTMP, 0, 0);
+}
+
+static int mlx5_hwmon_reset_max_temp(struct mlx5_core_dev *mdev, int sensor_index)
+{
+ u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+ u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+
+ MLX5_SET(mtmp_reg, mtmp_in, sensor_index, sensor_index);
+ MLX5_SET(mtmp_reg, mtmp_in, mtr, 1);
+
+ return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
+ mtmp_out, sizeof(mtmp_out),
+ MLX5_REG_MTMP, 0, 0);
+}
+
+static int mlx5_hwmon_enable_max_temp(struct mlx5_core_dev *mdev, int sensor_index)
+{
+ u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+ u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+ int err;
+
+ err = mlx5_hwmon_query_mtmp(mdev, sensor_index, mtmp_in);
+ if (err)
+ return err;
+
+ MLX5_SET(mtmp_reg, mtmp_in, mte, 1);
+ return mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
+ mtmp_out, sizeof(mtmp_out),
+ MLX5_REG_MTMP, 0, 1);
+}
+
+static int mlx5_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
+ u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+ int err;
+
+ if (type != hwmon_temp)
+ return -EOPNOTSUPP;
+
+ err = mlx5_hwmon_query_mtmp(hwmon->mdev, hwmon->temp_channel_desc[channel].sensor_index,
+ mtmp_out);
+ if (err)
+ return err;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, temperature));
+ return 0;
+ case hwmon_temp_highest:
+ *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, max_temperature));
+ return 0;
+ case hwmon_temp_crit:
+ *val = mtmp_temp_to_mdeg(MLX5_GET(mtmp_reg, mtmp_out, temp_threshold_hi));
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int mlx5_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long val)
+{
+ struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
+
+ if (type != hwmon_temp || attr != hwmon_temp_reset_history)
+ return -EOPNOTSUPP;
+
+ return mlx5_hwmon_reset_max_temp(hwmon->mdev,
+ hwmon->temp_channel_desc[channel].sensor_index);
+}
+
+static umode_t mlx5_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ if (type != hwmon_temp)
+ return 0;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ case hwmon_temp_highest:
+ case hwmon_temp_crit:
+ case hwmon_temp_label:
+ return 0444;
+ case hwmon_temp_reset_history:
+ return 0200;
+ default:
+ return 0;
+ }
+}
+
+static int mlx5_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, const char **str)
+{
+ struct mlx5_hwmon *hwmon = dev_get_drvdata(dev);
+
+ if (type != hwmon_temp || attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = (const char *)hwmon->temp_channel_desc[channel].sensor_name;
+ return 0;
+}
+
+static const struct hwmon_ops mlx5_hwmon_ops = {
+ .read = mlx5_hwmon_read,
+ .read_string = mlx5_hwmon_read_string,
+ .is_visible = mlx5_hwmon_is_visible,
+ .write = mlx5_hwmon_write,
+};
+
+static int mlx5_hwmon_init_channels_names(struct mlx5_hwmon *hwmon)
+{
+ u32 i;
+
+ for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++) {
+ u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
+ char *sensor_name;
+ int err;
+
+ err = mlx5_hwmon_query_mtmp(hwmon->mdev, hwmon->temp_channel_desc[i].sensor_index,
+ mtmp_out);
+ if (err)
+ return err;
+
+ sensor_name = MLX5_ADDR_OF(mtmp_reg, mtmp_out, sensor_name_hi);
+ if (!*sensor_name) {
+ snprintf(hwmon->temp_channel_desc[i].sensor_name,
+ sizeof(hwmon->temp_channel_desc[i].sensor_name), "sensor%u",
+ hwmon->temp_channel_desc[i].sensor_index);
+ continue;
+ }
+
+ memcpy(&hwmon->temp_channel_desc[i].sensor_name, sensor_name,
+ MLX5_FLD_SZ_BYTES(mtmp_reg, sensor_name_hi) +
+ MLX5_FLD_SZ_BYTES(mtmp_reg, sensor_name_lo));
+ }
+
+ return 0;
+}
+
+static int mlx5_hwmon_get_module_sensor_index(struct mlx5_core_dev *mdev, u32 *module_index)
+{
+ int module_num;
+ int err;
+
+ err = mlx5_query_module_num(mdev, &module_num);
+ if (err)
+ return err;
+
+ *module_index = to_mtmp_module_sensor_idx(module_num);
+
+ return 0;
+}
+
+static int mlx5_hwmon_init_sensors_indexes(struct mlx5_hwmon *hwmon, u64 sensor_map)
+{
+ DECLARE_BITMAP(smap, BITS_PER_TYPE(sensor_map));
+ unsigned long bit_pos;
+ int err = 0;
+ int i = 0;
+
+ bitmap_from_u64(smap, sensor_map);
+
+ for_each_set_bit(bit_pos, smap, BITS_PER_TYPE(sensor_map)) {
+ hwmon->temp_channel_desc[i].sensor_index = bit_pos;
+ i++;
+ }
+
+ if (hwmon->module_scount)
+ err = mlx5_hwmon_get_module_sensor_index(hwmon->mdev,
+ &hwmon->temp_channel_desc[i].sensor_index);
+
+ return err;
+}
+
+static void mlx5_hwmon_channel_info_init(struct mlx5_hwmon *hwmon)
+{
+ int i;
+
+ hwmon->channel_info[0] = &hwmon->chip_info;
+ hwmon->channel_info[1] = &hwmon->temp_info;
+
+ hwmon->chip_channel_config[0] = HWMON_C_REGISTER_TZ;
+ hwmon->chip_info.config = (const u32 *)hwmon->chip_channel_config;
+ hwmon->chip_info.type = hwmon_chip;
+
+ for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++)
+ hwmon->temp_channel_config[i] = HWMON_T_INPUT | HWMON_T_HIGHEST | HWMON_T_CRIT |
+ HWMON_T_RESET_HISTORY | HWMON_T_LABEL;
+
+ hwmon->temp_info.config = (const u32 *)hwmon->temp_channel_config;
+ hwmon->temp_info.type = hwmon_temp;
+}
+
+static int mlx5_hwmon_is_module_mon_cap(struct mlx5_core_dev *mdev, bool *mon_cap)
+{
+ u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)];
+ u32 module_index;
+ int err;
+
+ err = mlx5_hwmon_get_module_sensor_index(mdev, &module_index);
+ if (err)
+ return err;
+
+ err = mlx5_hwmon_query_mtmp(mdev, module_index, mtmp_out);
+ if (err)
+ return err;
+
+ if (MLX5_GET(mtmp_reg, mtmp_out, temperature))
+ *mon_cap = true;
+
+ return 0;
+}
+
+static int mlx5_hwmon_get_sensors_count(struct mlx5_core_dev *mdev, u32 *asic_platform_scount)
+{
+ u32 mtcap_out[MLX5_ST_SZ_DW(mtcap_reg)] = {};
+ u32 mtcap_in[MLX5_ST_SZ_DW(mtcap_reg)] = {};
+ int err;
+
+ err = mlx5_core_access_reg(mdev, mtcap_in, sizeof(mtcap_in),
+ mtcap_out, sizeof(mtcap_out),
+ MLX5_REG_MTCAP, 0, 0);
+ if (err)
+ return err;
+
+ *asic_platform_scount = MLX5_GET(mtcap_reg, mtcap_out, sensor_count);
+
+ return 0;
+}
+
+static void mlx5_hwmon_free(struct mlx5_hwmon *hwmon)
+{
+ if (!hwmon)
+ return;
+
+ kfree(hwmon->temp_channel_config);
+ kfree(hwmon->temp_channel_desc);
+ kfree(hwmon);
+}
+
+static struct mlx5_hwmon *mlx5_hwmon_alloc(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_hwmon *hwmon;
+ bool mon_cap = false;
+ u32 sensors_count;
+ int err;
+
+ hwmon = kzalloc(sizeof(*mdev->hwmon), GFP_KERNEL);
+ if (!hwmon)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx5_hwmon_get_sensors_count(mdev, &hwmon->asic_platform_scount);
+ if (err)
+ goto err_free_hwmon;
+
+ /* check if module sensor has thermal mon cap. if yes, allocate channel desc for it */
+ err = mlx5_hwmon_is_module_mon_cap(mdev, &mon_cap);
+ if (err)
+ goto err_free_hwmon;
+
+ hwmon->module_scount = mon_cap ? 1 : 0;
+ sensors_count = hwmon->asic_platform_scount + hwmon->module_scount;
+ hwmon->temp_channel_desc = kcalloc(sensors_count, sizeof(*hwmon->temp_channel_desc),
+ GFP_KERNEL);
+ if (!hwmon->temp_channel_desc) {
+ err = -ENOMEM;
+ goto err_free_hwmon;
+ }
+
+ /* sensors configuration values array, must be 0-terminated hence, + 1 */
+ hwmon->temp_channel_config = kcalloc(sensors_count + 1, sizeof(*hwmon->temp_channel_config),
+ GFP_KERNEL);
+ if (!hwmon->temp_channel_config) {
+ err = -ENOMEM;
+ goto err_free_temp_channel_desc;
+ }
+
+ hwmon->mdev = mdev;
+
+ return hwmon;
+
+err_free_temp_channel_desc:
+ kfree(hwmon->temp_channel_desc);
+err_free_hwmon:
+ kfree(hwmon);
+ return ERR_PTR(err);
+}
+
+static int mlx5_hwmon_dev_init(struct mlx5_hwmon *hwmon)
+{
+ u32 mtcap_out[MLX5_ST_SZ_DW(mtcap_reg)] = {};
+ u32 mtcap_in[MLX5_ST_SZ_DW(mtcap_reg)] = {};
+ int err;
+ int i;
+
+ err = mlx5_core_access_reg(hwmon->mdev, mtcap_in, sizeof(mtcap_in),
+ mtcap_out, sizeof(mtcap_out),
+ MLX5_REG_MTCAP, 0, 0);
+ if (err)
+ return err;
+
+ mlx5_hwmon_channel_info_init(hwmon);
+ mlx5_hwmon_init_sensors_indexes(hwmon, MLX5_GET64(mtcap_reg, mtcap_out, sensor_map));
+ err = mlx5_hwmon_init_channels_names(hwmon);
+ if (err)
+ return err;
+
+ for (i = 0; i < hwmon->asic_platform_scount + hwmon->module_scount; i++) {
+ err = mlx5_hwmon_enable_max_temp(hwmon->mdev,
+ hwmon->temp_channel_desc[i].sensor_index);
+ if (err)
+ return err;
+ }
+
+ hwmon->chip.ops = &mlx5_hwmon_ops;
+ hwmon->chip.info = (const struct hwmon_channel_info **)hwmon->channel_info;
+
+ return 0;
+}
+
+int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev)
+{
+ struct device *dev = mdev->device;
+ struct mlx5_hwmon *hwmon;
+ int err;
+
+ if (!MLX5_CAP_MCAM_REG(mdev, mtmp))
+ return 0;
+
+ hwmon = mlx5_hwmon_alloc(mdev);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ err = mlx5_hwmon_dev_init(hwmon);
+ if (err)
+ goto err_free_hwmon;
+
+ hwmon->hwmon_dev = hwmon_device_register_with_info(dev, "mlx5",
+ hwmon,
+ &hwmon->chip,
+ NULL);
+ if (IS_ERR(hwmon->hwmon_dev)) {
+ err = PTR_ERR(hwmon->hwmon_dev);
+ goto err_free_hwmon;
+ }
+
+ mdev->hwmon = hwmon;
+ return 0;
+
+err_free_hwmon:
+ mlx5_hwmon_free(hwmon);
+ return err;
+}
+
+void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_hwmon *hwmon = mdev->hwmon;
+
+ if (!hwmon)
+ return;
+
+ hwmon_device_unregister(hwmon->hwmon_dev);
+ mlx5_hwmon_free(hwmon);
+ mdev->hwmon = NULL;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/hwmon.h b/drivers/net/ethernet/mellanox/mlx5/core/hwmon.h
new file mode 100644
index 000000000000..999654a9b9da
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/hwmon.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+ */
+#ifndef __MLX5_HWMON_H__
+#define __MLX5_HWMON_H__
+
+#include <linux/mlx5/driver.h>
+
+#if IS_ENABLED(CONFIG_HWMON)
+
+int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev);
+void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev);
+
+#else
+static inline int mlx5_hwmon_dev_register(struct mlx5_core_dev *mdev)
+{
+ return 0;
+}
+
+static inline void mlx5_hwmon_dev_unregister(struct mlx5_core_dev *mdev) {}
+
+#endif
+
+#endif /* __MLX5_HWMON_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c
index fa467335526e..047d5fed5f89 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c
@@ -156,67 +156,57 @@ unlock:
return least_loaded_irq;
}
-void mlx5_irq_affinity_irqs_release(struct mlx5_core_dev *dev, struct mlx5_irq **irqs,
- int num_irqs)
+void mlx5_irq_affinity_irq_release(struct mlx5_core_dev *dev, struct mlx5_irq *irq)
{
struct mlx5_irq_pool *pool = mlx5_irq_pool_get(dev);
- int i;
-
- for (i = 0; i < num_irqs; i++) {
- int cpu = cpumask_first(mlx5_irq_get_affinity_mask(irqs[i]));
+ int cpu;
- synchronize_irq(pci_irq_vector(pool->dev->pdev,
- mlx5_irq_get_index(irqs[i])));
- if (mlx5_irq_put(irqs[i]))
- if (pool->irqs_per_cpu)
- cpu_put(pool, cpu);
- }
+ cpu = cpumask_first(mlx5_irq_get_affinity_mask(irq));
+ synchronize_irq(pci_irq_vector(pool->dev->pdev,
+ mlx5_irq_get_index(irq)));
+ if (mlx5_irq_put(irq))
+ if (pool->irqs_per_cpu)
+ cpu_put(pool, cpu);
}
/**
- * mlx5_irq_affinity_irqs_request_auto - request one or more IRQs for mlx5 device.
- * @dev: mlx5 device that is requesting the IRQs.
- * @nirqs: number of IRQs to request.
- * @irqs: an output array of IRQs pointers.
+ * mlx5_irq_affinity_irq_request_auto - request one IRQ for mlx5 device.
+ * @dev: mlx5 device that is requesting the IRQ.
+ * @used_cpus: cpumask of bounded cpus by the device
+ * @vecidx: vector index to request an IRQ for.
*
* Each IRQ is bounded to at most 1 CPU.
- * This function is requesting IRQs according to the default assignment.
+ * This function is requesting an IRQ according to the default assignment.
* The default assignment policy is:
- * - in each iteration, request the least loaded IRQ which is not bound to any
+ * - request the least loaded IRQ which is not bound to any
* CPU of the previous IRQs requested.
*
- * This function returns the number of IRQs requested, (which might be smaller than
- * @nirqs), if successful, or a negative error code in case of an error.
+ * On success, this function updates used_cpus mask and returns an irq pointer.
+ * In case of an error, an appropriate error pointer is returned.
*/
-int mlx5_irq_affinity_irqs_request_auto(struct mlx5_core_dev *dev, int nirqs,
- struct mlx5_irq **irqs)
+struct mlx5_irq *mlx5_irq_affinity_irq_request_auto(struct mlx5_core_dev *dev,
+ struct cpumask *used_cpus, u16 vecidx)
{
struct mlx5_irq_pool *pool = mlx5_irq_pool_get(dev);
struct irq_affinity_desc af_desc = {};
struct mlx5_irq *irq;
- int i = 0;
+
+ if (!mlx5_irq_pool_is_sf_pool(pool))
+ return ERR_PTR(-ENOENT);
af_desc.is_managed = 1;
cpumask_copy(&af_desc.mask, cpu_online_mask);
- for (i = 0; i < nirqs; i++) {
- if (mlx5_irq_pool_is_sf_pool(pool))
- irq = mlx5_irq_affinity_request(pool, &af_desc);
- else
- /* In case SF pool doesn't exists, fallback to the PF IRQs.
- * The PF IRQs are already allocated and binded to CPU
- * at this point. Hence, only an index is needed.
- */
- irq = mlx5_irq_request(dev, i, NULL, NULL);
- if (IS_ERR(irq))
- break;
- irqs[i] = irq;
- cpumask_clear_cpu(cpumask_first(mlx5_irq_get_affinity_mask(irq)), &af_desc.mask);
- mlx5_core_dbg(pool->dev, "IRQ %u mapped to cpu %*pbl, %u EQs on this irq\n",
- pci_irq_vector(dev->pdev, mlx5_irq_get_index(irq)),
- cpumask_pr_args(mlx5_irq_get_affinity_mask(irq)),
- mlx5_irq_read_locked(irq) / MLX5_EQ_REFS_PER_IRQ);
- }
- if (!i)
- return PTR_ERR(irq);
- return i;
+ cpumask_andnot(&af_desc.mask, &af_desc.mask, used_cpus);
+ irq = mlx5_irq_affinity_request(pool, &af_desc);
+
+ if (IS_ERR(irq))
+ return irq;
+
+ cpumask_or(used_cpus, used_cpus, mlx5_irq_get_affinity_mask(irq));
+ mlx5_core_dbg(pool->dev, "IRQ %u mapped to cpu %*pbl, %u EQs on this irq\n",
+ pci_irq_vector(dev->pdev, mlx5_irq_get_index(irq)),
+ cpumask_pr_args(mlx5_irq_get_affinity_mask(irq)),
+ mlx5_irq_read_locked(irq) / MLX5_EQ_REFS_PER_IRQ);
+
+ return irq;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index f0a074b2fcdf..af3fac090b82 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -835,7 +835,7 @@ static bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev)
dev = ldev->pf[MLX5_LAG_P1].dev;
if (is_mdev_switchdev_mode(dev) &&
mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) &&
- mlx5_devcom_comp_is_ready(dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS) &&
+ mlx5_esw_offloads_devcom_is_ready(dev->priv.eswitch) &&
MLX5_CAP_ESW(dev, esw_shared_ingress_acl) &&
mlx5_eswitch_get_npeers(dev->priv.eswitch) == MLX5_CAP_GEN(dev, num_lag_ports) - 1)
return true;
@@ -1268,16 +1268,6 @@ recheck:
mlx5_ldev_put(ldev);
}
-bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
-{
- if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
- !MLX5_CAP_GEN(dev, lag_master) ||
- MLX5_CAP_GEN(dev, num_lag_ports) < 2 ||
- MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_MAX_PORTS)
- return false;
- return true;
-}
-
void mlx5_lag_add_mdev(struct mlx5_core_dev *dev)
{
int err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index a061b1873e27..481e92f39fe6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -74,8 +74,6 @@ struct mlx5_lag {
struct lag_mpesw lag_mpesw;
};
-bool mlx5_lag_is_supported(struct mlx5_core_dev *dev);
-
static inline struct mlx5_lag *
mlx5_lag_dev(struct mlx5_core_dev *dev)
{
@@ -115,4 +113,14 @@ void mlx5_lag_remove_devices(struct mlx5_lag *ldev);
int mlx5_deactivate_lag(struct mlx5_lag *ldev);
void mlx5_lag_add_devices(struct mlx5_lag *ldev);
+static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev)
+{
+ if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
+ !MLX5_CAP_GEN(dev, lag_master) ||
+ MLX5_CAP_GEN(dev, num_lag_ports) < 2 ||
+ MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_MAX_PORTS)
+ return false;
+ return true;
+}
+
#endif /* __MLX5_LAG_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
index 5a80fb7dbbca..40c7be124041 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
@@ -81,7 +81,7 @@ static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
int inlen, eqn;
int err;
- err = mlx5_vector2eqn(mdev, 0, &eqn);
+ err = mlx5_comp_eqn_get(mdev, 0, &eqn);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index 377372f0578a..aa29f09e8356 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -32,6 +32,7 @@
#include <linux/clocksource.h>
#include <linux/highmem.h>
+#include <linux/log2.h>
#include <linux/ptp_clock_kernel.h>
#include <rdma/mlx5-abi.h>
#include "lib/eq.h"
@@ -39,10 +40,6 @@
#include "clock.h"
enum {
- MLX5_CYCLES_SHIFT = 31
-};
-
-enum {
MLX5_PIN_MODE_IN = 0x0,
MLX5_PIN_MODE_OUT = 0x1,
};
@@ -93,6 +90,31 @@ static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev)
return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify);
}
+static u32 mlx5_ptp_shift_constant(u32 dev_freq_khz)
+{
+ /* Optimal shift constant leads to corrections above just 1 scaled ppm.
+ *
+ * Two sets of equations are needed to derive the optimal shift
+ * constant for the cyclecounter.
+ *
+ * dev_freq_khz * 1000 / 2^shift_constant = 1 scaled_ppm
+ * ppb = scaled_ppm * 1000 / 2^16
+ *
+ * Using the two equations together
+ *
+ * dev_freq_khz * 1000 / 1 scaled_ppm = 2^shift_constant
+ * dev_freq_khz * 2^16 / 1 ppb = 2^shift_constant
+ * dev_freq_khz = 2^(shift_constant - 16)
+ *
+ * then yields
+ *
+ * shift_constant = ilog2(dev_freq_khz) + 16
+ */
+
+ return min(ilog2(dev_freq_khz) + 16,
+ ilog2((U32_MAX / NSEC_PER_MSEC) * dev_freq_khz));
+}
+
static s32 mlx5_ptp_getmaxphase(struct ptp_clock_info *ptp)
{
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
@@ -909,7 +931,7 @@ static void mlx5_timecounter_init(struct mlx5_core_dev *mdev)
dev_freq = MLX5_CAP_GEN(mdev, device_frequency_khz);
timer->cycles.read = read_internal_timer;
- timer->cycles.shift = MLX5_CYCLES_SHIFT;
+ timer->cycles.shift = mlx5_ptp_shift_constant(dev_freq);
timer->cycles.mult = clocksource_khz2mult(dev_freq,
timer->cycles.shift);
timer->nominal_c_mult = timer->cycles.mult;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
index 78c94b22bdc0..00e67910e3ee 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
@@ -2,214 +2,274 @@
/* Copyright (c) 2018 Mellanox Technologies */
#include <linux/mlx5/vport.h>
+#include <linux/list.h>
#include "lib/devcom.h"
#include "mlx5_core.h"
-static LIST_HEAD(devcom_list);
+static LIST_HEAD(devcom_dev_list);
+static LIST_HEAD(devcom_comp_list);
+/* protect device list */
+static DEFINE_MUTEX(dev_list_lock);
+/* protect component list */
+static DEFINE_MUTEX(comp_list_lock);
-#define devcom_for_each_component(priv, comp, iter) \
- for (iter = 0; \
- comp = &(priv)->components[iter], iter < MLX5_DEVCOM_NUM_COMPONENTS; \
- iter++)
+#define devcom_for_each_component(iter) \
+ list_for_each_entry(iter, &devcom_comp_list, comp_list)
-struct mlx5_devcom_component {
- struct {
- void __rcu *data;
- } device[MLX5_DEVCOM_PORTS_SUPPORTED];
+struct mlx5_devcom_dev {
+ struct list_head list;
+ struct mlx5_core_dev *dev;
+ struct kref ref;
+};
+struct mlx5_devcom_comp {
+ struct list_head comp_list;
+ enum mlx5_devcom_component id;
+ u64 key;
+ struct list_head comp_dev_list_head;
mlx5_devcom_event_handler_t handler;
- struct rw_semaphore sem;
+ struct kref ref;
bool ready;
+ struct rw_semaphore sem;
};
-struct mlx5_devcom_list {
+struct mlx5_devcom_comp_dev {
struct list_head list;
-
- struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS];
- struct mlx5_core_dev *devs[MLX5_DEVCOM_PORTS_SUPPORTED];
+ struct mlx5_devcom_comp *comp;
+ struct mlx5_devcom_dev *devc;
+ void __rcu *data;
};
-struct mlx5_devcom {
- struct mlx5_devcom_list *priv;
- int idx;
-};
-
-static struct mlx5_devcom_list *mlx5_devcom_list_alloc(void)
+static bool devcom_dev_exists(struct mlx5_core_dev *dev)
{
- struct mlx5_devcom_component *comp;
- struct mlx5_devcom_list *priv;
- int i;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return NULL;
+ struct mlx5_devcom_dev *iter;
- devcom_for_each_component(priv, comp, i)
- init_rwsem(&comp->sem);
+ list_for_each_entry(iter, &devcom_dev_list, list)
+ if (iter->dev == dev)
+ return true;
- return priv;
+ return false;
}
-static struct mlx5_devcom *mlx5_devcom_alloc(struct mlx5_devcom_list *priv,
- u8 idx)
+static struct mlx5_devcom_dev *
+mlx5_devcom_dev_alloc(struct mlx5_core_dev *dev)
{
- struct mlx5_devcom *devcom;
+ struct mlx5_devcom_dev *devc;
- devcom = kzalloc(sizeof(*devcom), GFP_KERNEL);
- if (!devcom)
+ devc = kzalloc(sizeof(*devc), GFP_KERNEL);
+ if (!devc)
return NULL;
- devcom->priv = priv;
- devcom->idx = idx;
- return devcom;
+ devc->dev = dev;
+ kref_init(&devc->ref);
+ return devc;
}
-/* Must be called with intf_mutex held */
-struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev)
+struct mlx5_devcom_dev *
+mlx5_devcom_register_device(struct mlx5_core_dev *dev)
{
- struct mlx5_devcom_list *priv = NULL, *iter;
- struct mlx5_devcom *devcom = NULL;
- bool new_priv = false;
- u64 sguid0, sguid1;
- int idx, i;
-
- if (!mlx5_core_is_pf(dev))
- return NULL;
- if (MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_DEVCOM_PORTS_SUPPORTED)
- return NULL;
-
- mlx5_dev_list_lock();
- sguid0 = mlx5_query_nic_system_image_guid(dev);
- list_for_each_entry(iter, &devcom_list, list) {
- /* There is at least one device in iter */
- struct mlx5_core_dev *tmp_dev;
-
- idx = -1;
- for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) {
- if (iter->devs[i])
- tmp_dev = iter->devs[i];
- else
- idx = i;
- }
-
- if (idx == -1)
- continue;
-
- sguid1 = mlx5_query_nic_system_image_guid(tmp_dev);
- if (sguid0 != sguid1)
- continue;
-
- priv = iter;
- break;
- }
+ struct mlx5_devcom_dev *devc;
- if (!priv) {
- priv = mlx5_devcom_list_alloc();
- if (!priv) {
- devcom = ERR_PTR(-ENOMEM);
- goto out;
- }
+ mutex_lock(&dev_list_lock);
- idx = 0;
- new_priv = true;
+ if (devcom_dev_exists(dev)) {
+ devc = ERR_PTR(-EEXIST);
+ goto out;
}
- priv->devs[idx] = dev;
- devcom = mlx5_devcom_alloc(priv, idx);
- if (!devcom) {
- if (new_priv)
- kfree(priv);
- devcom = ERR_PTR(-ENOMEM);
+ devc = mlx5_devcom_dev_alloc(dev);
+ if (!devc) {
+ devc = ERR_PTR(-ENOMEM);
goto out;
}
- if (new_priv)
- list_add(&priv->list, &devcom_list);
+ list_add_tail(&devc->list, &devcom_dev_list);
out:
- mlx5_dev_list_unlock();
- return devcom;
+ mutex_unlock(&dev_list_lock);
+ return devc;
}
-/* Must be called with intf_mutex held */
-void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom)
+static void
+mlx5_devcom_dev_release(struct kref *ref)
{
- struct mlx5_devcom_list *priv;
- int i;
+ struct mlx5_devcom_dev *devc = container_of(ref, struct mlx5_devcom_dev, ref);
- if (IS_ERR_OR_NULL(devcom))
- return;
+ mutex_lock(&dev_list_lock);
+ list_del(&devc->list);
+ mutex_unlock(&dev_list_lock);
+ kfree(devc);
+}
- mlx5_dev_list_lock();
- priv = devcom->priv;
- priv->devs[devcom->idx] = NULL;
+void mlx5_devcom_unregister_device(struct mlx5_devcom_dev *devc)
+{
+ if (!IS_ERR_OR_NULL(devc))
+ kref_put(&devc->ref, mlx5_devcom_dev_release);
+}
- kfree(devcom);
+static struct mlx5_devcom_comp *
+mlx5_devcom_comp_alloc(u64 id, u64 key, mlx5_devcom_event_handler_t handler)
+{
+ struct mlx5_devcom_comp *comp;
- for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++)
- if (priv->devs[i])
- break;
+ comp = kzalloc(sizeof(*comp), GFP_KERNEL);
+ if (!comp)
+ return ERR_PTR(-ENOMEM);
- if (i != MLX5_DEVCOM_PORTS_SUPPORTED)
- goto out;
+ comp->id = id;
+ comp->key = key;
+ comp->handler = handler;
+ init_rwsem(&comp->sem);
+ kref_init(&comp->ref);
+ INIT_LIST_HEAD(&comp->comp_dev_list_head);
- list_del(&priv->list);
- kfree(priv);
-out:
- mlx5_dev_list_unlock();
+ return comp;
}
-void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- mlx5_devcom_event_handler_t handler,
- void *data)
+static void
+mlx5_devcom_comp_release(struct kref *ref)
{
- struct mlx5_devcom_component *comp;
+ struct mlx5_devcom_comp *comp = container_of(ref, struct mlx5_devcom_comp, ref);
- if (IS_ERR_OR_NULL(devcom))
- return;
+ mutex_lock(&comp_list_lock);
+ list_del(&comp->comp_list);
+ mutex_unlock(&comp_list_lock);
+ kfree(comp);
+}
+
+static struct mlx5_devcom_comp_dev *
+devcom_alloc_comp_dev(struct mlx5_devcom_dev *devc,
+ struct mlx5_devcom_comp *comp,
+ void *data)
+{
+ struct mlx5_devcom_comp_dev *devcom;
- WARN_ON(!data);
+ devcom = kzalloc(sizeof(*devcom), GFP_KERNEL);
+ if (!devcom)
+ return ERR_PTR(-ENOMEM);
+
+ kref_get(&devc->ref);
+ devcom->devc = devc;
+ devcom->comp = comp;
+ rcu_assign_pointer(devcom->data, data);
- comp = &devcom->priv->components[id];
down_write(&comp->sem);
- comp->handler = handler;
- rcu_assign_pointer(comp->device[devcom->idx].data, data);
+ list_add_tail(&devcom->list, &comp->comp_dev_list_head);
up_write(&comp->sem);
+
+ return devcom;
}
-void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id)
+static void
+devcom_free_comp_dev(struct mlx5_devcom_comp_dev *devcom)
{
- struct mlx5_devcom_component *comp;
-
- if (IS_ERR_OR_NULL(devcom))
- return;
+ struct mlx5_devcom_comp *comp = devcom->comp;
- comp = &devcom->priv->components[id];
down_write(&comp->sem);
- RCU_INIT_POINTER(comp->device[devcom->idx].data, NULL);
+ list_del(&devcom->list);
up_write(&comp->sem);
- synchronize_rcu();
+
+ kref_put(&devcom->devc->ref, mlx5_devcom_dev_release);
+ kfree(devcom);
+ kref_put(&comp->ref, mlx5_devcom_comp_release);
}
-int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
+static bool
+devcom_component_equal(struct mlx5_devcom_comp *devcom,
+ enum mlx5_devcom_component id,
+ u64 key)
+{
+ return devcom->id == id && devcom->key == key;
+}
+
+static struct mlx5_devcom_comp *
+devcom_component_get(struct mlx5_devcom_dev *devc,
+ enum mlx5_devcom_component id,
+ u64 key,
+ mlx5_devcom_event_handler_t handler)
+{
+ struct mlx5_devcom_comp *comp;
+
+ devcom_for_each_component(comp) {
+ if (devcom_component_equal(comp, id, key)) {
+ if (handler == comp->handler) {
+ kref_get(&comp->ref);
+ return comp;
+ }
+
+ mlx5_core_err(devc->dev,
+ "Cannot register existing devcom component with different handler\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ return NULL;
+}
+
+struct mlx5_devcom_comp_dev *
+mlx5_devcom_register_component(struct mlx5_devcom_dev *devc,
+ enum mlx5_devcom_component id,
+ u64 key,
+ mlx5_devcom_event_handler_t handler,
+ void *data)
+{
+ struct mlx5_devcom_comp_dev *devcom;
+ struct mlx5_devcom_comp *comp;
+
+ if (IS_ERR_OR_NULL(devc))
+ return NULL;
+
+ mutex_lock(&comp_list_lock);
+ comp = devcom_component_get(devc, id, key, handler);
+ if (IS_ERR(comp)) {
+ devcom = ERR_PTR(-EINVAL);
+ goto out_unlock;
+ }
+
+ if (!comp) {
+ comp = mlx5_devcom_comp_alloc(id, key, handler);
+ if (IS_ERR(comp)) {
+ devcom = ERR_CAST(comp);
+ goto out_unlock;
+ }
+ list_add_tail(&comp->comp_list, &devcom_comp_list);
+ }
+ mutex_unlock(&comp_list_lock);
+
+ devcom = devcom_alloc_comp_dev(devc, comp, data);
+ if (IS_ERR(devcom))
+ kref_put(&comp->ref, mlx5_devcom_comp_release);
+
+ return devcom;
+
+out_unlock:
+ mutex_unlock(&comp_list_lock);
+ return devcom;
+}
+
+void mlx5_devcom_unregister_component(struct mlx5_devcom_comp_dev *devcom)
+{
+ if (!IS_ERR_OR_NULL(devcom))
+ devcom_free_comp_dev(devcom);
+}
+
+int mlx5_devcom_send_event(struct mlx5_devcom_comp_dev *devcom,
int event, int rollback_event,
void *event_data)
{
- struct mlx5_devcom_component *comp;
- int err = -ENODEV, i;
+ struct mlx5_devcom_comp_dev *pos;
+ struct mlx5_devcom_comp *comp;
+ int err = 0;
+ void *data;
if (IS_ERR_OR_NULL(devcom))
- return err;
+ return -ENODEV;
- comp = &devcom->priv->components[id];
+ comp = devcom->comp;
down_write(&comp->sem);
- for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) {
- void *data = rcu_dereference_protected(comp->device[i].data,
- lockdep_is_held(&comp->sem));
+ list_for_each_entry(pos, &comp->comp_dev_list_head, list) {
+ data = rcu_dereference_protected(pos->data, lockdep_is_held(&comp->sem));
- if (i != devcom->idx && data) {
+ if (pos != devcom && data) {
err = comp->handler(event, data, event_data);
if (err)
goto rollback;
@@ -220,48 +280,43 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
return 0;
rollback:
- while (i--) {
- void *data = rcu_dereference_protected(comp->device[i].data,
- lockdep_is_held(&comp->sem));
+ if (list_entry_is_head(pos, &comp->comp_dev_list_head, list))
+ goto out;
+ pos = list_prev_entry(pos, list);
+ list_for_each_entry_from_reverse(pos, &comp->comp_dev_list_head, list) {
+ data = rcu_dereference_protected(pos->data, lockdep_is_held(&comp->sem));
- if (i != devcom->idx && data)
+ if (pos != devcom && data)
comp->handler(rollback_event, data, event_data);
}
-
+out:
up_write(&comp->sem);
return err;
}
-void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- bool ready)
+void mlx5_devcom_comp_set_ready(struct mlx5_devcom_comp_dev *devcom, bool ready)
{
- struct mlx5_devcom_component *comp;
-
- comp = &devcom->priv->components[id];
- WARN_ON(!rwsem_is_locked(&comp->sem));
+ WARN_ON(!rwsem_is_locked(&devcom->comp->sem));
- WRITE_ONCE(comp->ready, ready);
+ WRITE_ONCE(devcom->comp->ready, ready);
}
-bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id)
+bool mlx5_devcom_comp_is_ready(struct mlx5_devcom_comp_dev *devcom)
{
if (IS_ERR_OR_NULL(devcom))
return false;
- return READ_ONCE(devcom->priv->components[id].ready);
+ return READ_ONCE(devcom->comp->ready);
}
-bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id)
+bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom_comp_dev *devcom)
{
- struct mlx5_devcom_component *comp;
+ struct mlx5_devcom_comp *comp;
if (IS_ERR_OR_NULL(devcom))
return false;
- comp = &devcom->priv->components[id];
+ comp = devcom->comp;
down_read(&comp->sem);
if (!READ_ONCE(comp->ready)) {
up_read(&comp->sem);
@@ -271,74 +326,60 @@ bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom *devcom,
return true;
}
-void mlx5_devcom_for_each_peer_end(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id)
+void mlx5_devcom_for_each_peer_end(struct mlx5_devcom_comp_dev *devcom)
{
- struct mlx5_devcom_component *comp = &devcom->priv->components[id];
-
- up_read(&comp->sem);
+ up_read(&devcom->comp->sem);
}
-void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- int *i)
+void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom_comp_dev *devcom,
+ struct mlx5_devcom_comp_dev **pos)
{
- struct mlx5_devcom_component *comp;
- void *ret;
- int idx;
+ struct mlx5_devcom_comp *comp = devcom->comp;
+ struct mlx5_devcom_comp_dev *tmp;
+ void *data;
- comp = &devcom->priv->components[id];
+ tmp = list_prepare_entry(*pos, &comp->comp_dev_list_head, list);
- if (*i == MLX5_DEVCOM_PORTS_SUPPORTED)
- return NULL;
- for (idx = *i; idx < MLX5_DEVCOM_PORTS_SUPPORTED; idx++) {
- if (idx != devcom->idx) {
- ret = rcu_dereference_protected(comp->device[idx].data,
- lockdep_is_held(&comp->sem));
- if (ret)
+ list_for_each_entry_continue(tmp, &comp->comp_dev_list_head, list) {
+ if (tmp != devcom) {
+ data = rcu_dereference_protected(tmp->data, lockdep_is_held(&comp->sem));
+ if (data)
break;
}
}
- if (idx == MLX5_DEVCOM_PORTS_SUPPORTED) {
- *i = idx;
+ if (list_entry_is_head(tmp, &comp->comp_dev_list_head, list))
return NULL;
- }
- *i = idx + 1;
- return ret;
+ *pos = tmp;
+ return data;
}
-void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- int *i)
+void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom_comp_dev *devcom,
+ struct mlx5_devcom_comp_dev **pos)
{
- struct mlx5_devcom_component *comp;
- void *ret;
- int idx;
+ struct mlx5_devcom_comp *comp = devcom->comp;
+ struct mlx5_devcom_comp_dev *tmp;
+ void *data;
- comp = &devcom->priv->components[id];
+ tmp = list_prepare_entry(*pos, &comp->comp_dev_list_head, list);
- if (*i == MLX5_DEVCOM_PORTS_SUPPORTED)
- return NULL;
- for (idx = *i; idx < MLX5_DEVCOM_PORTS_SUPPORTED; idx++) {
- if (idx != devcom->idx) {
+ list_for_each_entry_continue(tmp, &comp->comp_dev_list_head, list) {
+ if (tmp != devcom) {
/* This can change concurrently, however 'data' pointer will remain
* valid for the duration of RCU read section.
*/
if (!READ_ONCE(comp->ready))
return NULL;
- ret = rcu_dereference(comp->device[idx].data);
- if (ret)
+ data = rcu_dereference(tmp->data);
+ if (data)
break;
}
}
- if (idx == MLX5_DEVCOM_PORTS_SUPPORTED) {
- *i = idx;
+ if (list_entry_is_head(tmp, &comp->comp_dev_list_head, list))
return NULL;
- }
- *i = idx + 1;
- return ret;
+ *pos = tmp;
+ return data;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
index d953a01b8eaa..8389ac0af708 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
@@ -6,11 +6,8 @@
#include <linux/mlx5/driver.h>
-#define MLX5_DEVCOM_PORTS_SUPPORTED 4
-
-enum mlx5_devcom_components {
+enum mlx5_devcom_component {
MLX5_DEVCOM_ESW_OFFLOADS,
-
MLX5_DEVCOM_NUM_COMPONENTS,
};
@@ -18,45 +15,40 @@ typedef int (*mlx5_devcom_event_handler_t)(int event,
void *my_data,
void *event_data);
-struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev);
-void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom);
+struct mlx5_devcom_dev *mlx5_devcom_register_device(struct mlx5_core_dev *dev);
+void mlx5_devcom_unregister_device(struct mlx5_devcom_dev *devc);
-void mlx5_devcom_register_component(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- mlx5_devcom_event_handler_t handler,
- void *data);
-void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id);
+struct mlx5_devcom_comp_dev *
+mlx5_devcom_register_component(struct mlx5_devcom_dev *devc,
+ enum mlx5_devcom_component id,
+ u64 key,
+ mlx5_devcom_event_handler_t handler,
+ void *data);
+void mlx5_devcom_unregister_component(struct mlx5_devcom_comp_dev *devcom);
-int mlx5_devcom_send_event(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
+int mlx5_devcom_send_event(struct mlx5_devcom_comp_dev *devcom,
int event, int rollback_event,
void *event_data);
-void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id,
- bool ready);
-bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id);
-
-bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id);
-void mlx5_devcom_for_each_peer_end(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id);
-void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id, int *i);
-
-#define mlx5_devcom_for_each_peer_entry(devcom, id, data, i) \
- for (i = 0, data = mlx5_devcom_get_next_peer_data(devcom, id, &i); \
- data; \
- data = mlx5_devcom_get_next_peer_data(devcom, id, &i))
-
-void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom *devcom,
- enum mlx5_devcom_components id, int *i);
-
-#define mlx5_devcom_for_each_peer_entry_rcu(devcom, id, data, i) \
- for (i = 0, data = mlx5_devcom_get_next_peer_data_rcu(devcom, id, &i); \
- data; \
- data = mlx5_devcom_get_next_peer_data_rcu(devcom, id, &i))
-
-#endif
+void mlx5_devcom_comp_set_ready(struct mlx5_devcom_comp_dev *devcom, bool ready);
+bool mlx5_devcom_comp_is_ready(struct mlx5_devcom_comp_dev *devcom);
+
+bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom_comp_dev *devcom);
+void mlx5_devcom_for_each_peer_end(struct mlx5_devcom_comp_dev *devcom);
+void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom_comp_dev *devcom,
+ struct mlx5_devcom_comp_dev **pos);
+
+#define mlx5_devcom_for_each_peer_entry(devcom, data, pos) \
+ for (pos = NULL, data = mlx5_devcom_get_next_peer_data(devcom, &pos); \
+ data; \
+ data = mlx5_devcom_get_next_peer_data(devcom, &pos))
+
+void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom_comp_dev *devcom,
+ struct mlx5_devcom_comp_dev **pos);
+
+#define mlx5_devcom_for_each_peer_entry_rcu(devcom, data, pos) \
+ for (pos = NULL, data = mlx5_devcom_get_next_peer_data_rcu(devcom, &pos); \
+ data; \
+ data = mlx5_devcom_get_next_peer_data_rcu(devcom, &pos))
+
+#endif /* __LIB_MLX5_DEVCOM_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
index d3d628b862f3..69a75459775d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
@@ -104,6 +104,6 @@ void mlx5_core_eq_free_irqs(struct mlx5_core_dev *dev);
struct cpu_rmap *mlx5_eq_table_get_rmap(struct mlx5_core_dev *dev);
#endif
-int mlx5_vector2irqn(struct mlx5_core_dev *dev, int vector, unsigned int *irqn);
+int mlx5_comp_irqn_get(struct mlx5_core_dev *dev, int vector, unsigned int *irqn);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c
index 4047629a876b..30564d9b00e9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c
@@ -40,7 +40,7 @@ struct mlx5_hv_vhca_agent {
struct mlx5_hv_vhca *mlx5_hv_vhca_create(struct mlx5_core_dev *dev)
{
- struct mlx5_hv_vhca *hv_vhca = NULL;
+ struct mlx5_hv_vhca *hv_vhca;
hv_vhca = kzalloc(sizeof(*hv_vhca), GFP_KERNEL);
if (!hv_vhca)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
new file mode 100644
index 000000000000..4a078113e292
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
@@ -0,0 +1,2411 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <net/macsec.h>
+#include <linux/mlx5/qp.h>
+#include <linux/if_vlan.h>
+#include <linux/mlx5/fs_helpers.h>
+#include <linux/mlx5/macsec.h>
+#include "fs_core.h"
+#include "lib/macsec_fs.h"
+#include "mlx5_core.h"
+
+/* MACsec TX flow steering */
+#define CRYPTO_NUM_MAXSEC_FTE BIT(15)
+#define CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE 1
+
+#define TX_CRYPTO_TABLE_LEVEL 0
+#define TX_CRYPTO_TABLE_NUM_GROUPS 3
+#define TX_CRYPTO_TABLE_MKE_GROUP_SIZE 1
+#define TX_CRYPTO_TABLE_SA_GROUP_SIZE \
+ (CRYPTO_NUM_MAXSEC_FTE - (TX_CRYPTO_TABLE_MKE_GROUP_SIZE + \
+ CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE))
+#define TX_CHECK_TABLE_LEVEL 1
+#define TX_CHECK_TABLE_NUM_FTE 2
+#define RX_CRYPTO_TABLE_LEVEL 0
+#define RX_CHECK_TABLE_LEVEL 1
+#define RX_ROCE_TABLE_LEVEL 2
+#define RX_CHECK_TABLE_NUM_FTE 3
+#define RX_ROCE_TABLE_NUM_FTE 2
+#define RX_CRYPTO_TABLE_NUM_GROUPS 3
+#define RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE \
+ ((CRYPTO_NUM_MAXSEC_FTE - CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE) / 2)
+#define RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE \
+ (CRYPTO_NUM_MAXSEC_FTE - RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE)
+#define RX_NUM_OF_RULES_PER_SA 2
+
+#define RDMA_RX_ROCE_IP_TABLE_LEVEL 0
+#define RDMA_RX_ROCE_MACSEC_OP_TABLE_LEVEL 1
+
+#define MLX5_MACSEC_TAG_LEN 8 /* SecTAG length with ethertype and without the optional SCI */
+#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK 0x23
+#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET 0x8
+#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET 0x5
+#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT (0x1 << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET)
+#define MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI 0x8
+#define MLX5_SECTAG_HEADER_SIZE_WITH_SCI (MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI + MACSEC_SCI_LEN)
+
+/* MACsec RX flow steering */
+#define MLX5_ETH_WQE_FT_META_MACSEC_MASK 0x3E
+
+/* MACsec fs_id handling for steering */
+#define macsec_fs_set_tx_fs_id(fs_id) (MLX5_ETH_WQE_FT_META_MACSEC | (fs_id) << 2)
+#define macsec_fs_set_rx_fs_id(fs_id) ((fs_id) | BIT(30))
+
+struct mlx5_sectag_header {
+ __be16 ethertype;
+ u8 tci_an;
+ u8 sl;
+ u32 pn;
+ u8 sci[MACSEC_SCI_LEN]; /* optional */
+} __packed;
+
+struct mlx5_roce_macsec_tx_rule {
+ u32 fs_id;
+ u16 gid_idx;
+ struct list_head entry;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_modify_hdr *meta_modhdr;
+};
+
+struct mlx5_macsec_tx_rule {
+ struct mlx5_flow_handle *rule;
+ struct mlx5_pkt_reformat *pkt_reformat;
+ u32 fs_id;
+};
+
+struct mlx5_macsec_flow_table {
+ int num_groups;
+ struct mlx5_flow_table *t;
+ struct mlx5_flow_group **g;
+};
+
+struct mlx5_macsec_tables {
+ struct mlx5_macsec_flow_table ft_crypto;
+ struct mlx5_flow_handle *crypto_miss_rule;
+
+ struct mlx5_flow_table *ft_check;
+ struct mlx5_flow_group *ft_check_group;
+ struct mlx5_fc *check_miss_rule_counter;
+ struct mlx5_flow_handle *check_miss_rule;
+ struct mlx5_fc *check_rule_counter;
+
+ u32 refcnt;
+};
+
+struct mlx5_fs_id {
+ u32 id;
+ refcount_t refcnt;
+ sci_t sci;
+ struct rhash_head hash;
+};
+
+struct mlx5_macsec_device {
+ struct list_head macsec_devices_list_entry;
+ void *macdev;
+ struct xarray tx_id_xa;
+ struct xarray rx_id_xa;
+};
+
+struct mlx5_macsec_tx {
+ struct mlx5_flow_handle *crypto_mke_rule;
+ struct mlx5_flow_handle *check_rule;
+
+ struct ida tx_halloc;
+
+ struct mlx5_macsec_tables tables;
+
+ struct mlx5_flow_table *ft_rdma_tx;
+};
+
+struct mlx5_roce_macsec_rx_rule {
+ u32 fs_id;
+ u16 gid_idx;
+ struct mlx5_flow_handle *op;
+ struct mlx5_flow_handle *ip;
+ struct list_head entry;
+};
+
+struct mlx5_macsec_rx_rule {
+ struct mlx5_flow_handle *rule[RX_NUM_OF_RULES_PER_SA];
+ struct mlx5_modify_hdr *meta_modhdr;
+};
+
+struct mlx5_macsec_miss {
+ struct mlx5_flow_group *g;
+ struct mlx5_flow_handle *rule;
+};
+
+struct mlx5_macsec_rx_roce {
+ /* Flow table/rules in NIC domain, to check if it's a RoCE packet */
+ struct mlx5_flow_group *g;
+ struct mlx5_flow_table *ft;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_modify_hdr *copy_modify_hdr;
+ struct mlx5_macsec_miss nic_miss;
+
+ /* Flow table/rule in RDMA domain, to check dgid */
+ struct mlx5_flow_table *ft_ip_check;
+ struct mlx5_flow_table *ft_macsec_op_check;
+ struct mlx5_macsec_miss miss;
+};
+
+struct mlx5_macsec_rx {
+ struct mlx5_flow_handle *check_rule[2];
+ struct mlx5_pkt_reformat *check_rule_pkt_reformat[2];
+
+ struct mlx5_macsec_tables tables;
+ struct mlx5_macsec_rx_roce roce;
+};
+
+union mlx5_macsec_rule {
+ struct mlx5_macsec_tx_rule tx_rule;
+ struct mlx5_macsec_rx_rule rx_rule;
+};
+
+static const struct rhashtable_params rhash_sci = {
+ .key_len = sizeof_field(struct mlx5_fs_id, sci),
+ .key_offset = offsetof(struct mlx5_fs_id, sci),
+ .head_offset = offsetof(struct mlx5_fs_id, hash),
+ .automatic_shrinking = true,
+ .min_size = 1,
+};
+
+static const struct rhashtable_params rhash_fs_id = {
+ .key_len = sizeof_field(struct mlx5_fs_id, id),
+ .key_offset = offsetof(struct mlx5_fs_id, id),
+ .head_offset = offsetof(struct mlx5_fs_id, hash),
+ .automatic_shrinking = true,
+ .min_size = 1,
+};
+
+struct mlx5_macsec_fs {
+ struct mlx5_core_dev *mdev;
+ struct mlx5_macsec_tx *tx_fs;
+ struct mlx5_macsec_rx *rx_fs;
+
+ /* Stats manage */
+ struct mlx5_macsec_stats stats;
+
+ /* Tx sci -> fs id mapping handling */
+ struct rhashtable sci_hash; /* sci -> mlx5_fs_id */
+
+ /* RX fs_id -> mlx5_fs_id mapping handling */
+ struct rhashtable fs_id_hash; /* fs_id -> mlx5_fs_id */
+
+ /* TX & RX fs_id lists per macsec device */
+ struct list_head macsec_devices_list;
+};
+
+static void macsec_fs_destroy_groups(struct mlx5_macsec_flow_table *ft)
+{
+ int i;
+
+ for (i = ft->num_groups - 1; i >= 0; i--) {
+ if (!IS_ERR_OR_NULL(ft->g[i]))
+ mlx5_destroy_flow_group(ft->g[i]);
+ ft->g[i] = NULL;
+ }
+ ft->num_groups = 0;
+}
+
+static void macsec_fs_destroy_flow_table(struct mlx5_macsec_flow_table *ft)
+{
+ macsec_fs_destroy_groups(ft);
+ kfree(ft->g);
+ mlx5_destroy_flow_table(ft->t);
+ ft->t = NULL;
+}
+
+static void macsec_fs_tx_destroy(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_macsec_tables *tx_tables;
+
+ if (mlx5_is_macsec_roce_supported(macsec_fs->mdev))
+ mlx5_destroy_flow_table(tx_fs->ft_rdma_tx);
+
+ tx_tables = &tx_fs->tables;
+
+ /* Tx check table */
+ if (tx_fs->check_rule) {
+ mlx5_del_flow_rules(tx_fs->check_rule);
+ tx_fs->check_rule = NULL;
+ }
+
+ if (tx_tables->check_miss_rule) {
+ mlx5_del_flow_rules(tx_tables->check_miss_rule);
+ tx_tables->check_miss_rule = NULL;
+ }
+
+ if (tx_tables->ft_check_group) {
+ mlx5_destroy_flow_group(tx_tables->ft_check_group);
+ tx_tables->ft_check_group = NULL;
+ }
+
+ if (tx_tables->ft_check) {
+ mlx5_destroy_flow_table(tx_tables->ft_check);
+ tx_tables->ft_check = NULL;
+ }
+
+ /* Tx crypto table */
+ if (tx_fs->crypto_mke_rule) {
+ mlx5_del_flow_rules(tx_fs->crypto_mke_rule);
+ tx_fs->crypto_mke_rule = NULL;
+ }
+
+ if (tx_tables->crypto_miss_rule) {
+ mlx5_del_flow_rules(tx_tables->crypto_miss_rule);
+ tx_tables->crypto_miss_rule = NULL;
+ }
+
+ macsec_fs_destroy_flow_table(&tx_tables->ft_crypto);
+}
+
+static int macsec_fs_tx_create_crypto_table_groups(struct mlx5_macsec_flow_table *ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ int mclen = MLX5_ST_SZ_BYTES(fte_match_param);
+ int ix = 0;
+ u32 *in;
+ int err;
+ u8 *mc;
+
+ ft->g = kcalloc(TX_CRYPTO_TABLE_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
+ if (!ft->g)
+ return -ENOMEM;
+ in = kvzalloc(inlen, GFP_KERNEL);
+
+ if (!in) {
+ kfree(ft->g);
+ ft->g = NULL;
+ return -ENOMEM;
+ }
+
+ mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ /* Flow Group for MKE match */
+ MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
+ MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
+
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += TX_CRYPTO_TABLE_MKE_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ /* Flow Group for SA rules */
+ memset(in, 0, inlen);
+ memset(mc, 0, mclen);
+ MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS_2);
+ MLX5_SET(fte_match_param, mc, misc_parameters_2.metadata_reg_a,
+ MLX5_ETH_WQE_FT_META_MACSEC_MASK);
+
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += TX_CRYPTO_TABLE_SA_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ /* Flow Group for l2 traps */
+ memset(in, 0, inlen);
+ memset(mc, 0, mclen);
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ kvfree(in);
+ return 0;
+
+err:
+ err = PTR_ERR(ft->g[ft->num_groups]);
+ ft->g[ft->num_groups] = NULL;
+ kvfree(in);
+
+ return err;
+}
+
+static struct mlx5_flow_table
+ *macsec_fs_auto_group_table_create(struct mlx5_flow_namespace *ns, int flags,
+ int level, int max_fte)
+{
+ struct mlx5_flow_table_attr ft_attr = {};
+ struct mlx5_flow_table *fdb = NULL;
+
+ /* reserve entry for the match all miss group and rule */
+ ft_attr.autogroup.num_reserved_entries = 1;
+ ft_attr.autogroup.max_num_groups = 1;
+ ft_attr.prio = 0;
+ ft_attr.flags = flags;
+ ft_attr.level = level;
+ ft_attr.max_fte = max_fte;
+
+ fdb = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
+
+ return fdb;
+}
+
+enum {
+ RDMA_TX_MACSEC_LEVEL = 0,
+};
+
+static int macsec_fs_tx_roce_create(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_table *ft;
+ int err;
+
+ if (!mlx5_is_macsec_roce_supported(mdev)) {
+ mlx5_core_dbg(mdev, "Failed to init RoCE MACsec, capabilities not supported\n");
+ return 0;
+ }
+
+ ns = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_MACSEC);
+ if (!ns)
+ return -ENOMEM;
+
+ /* Tx RoCE crypto table */
+ ft = macsec_fs_auto_group_table_create(ns, 0, RDMA_TX_MACSEC_LEVEL, CRYPTO_NUM_MAXSEC_FTE);
+ if (IS_ERR(ft)) {
+ err = PTR_ERR(ft);
+ mlx5_core_err(mdev, "Failed to create MACsec RoCE Tx crypto table err(%d)\n", err);
+ return err;
+ }
+ tx_fs->ft_rdma_tx = ft;
+
+ return 0;
+}
+
+static int macsec_fs_tx_create(struct mlx5_macsec_fs *macsec_fs)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_flow_table_attr ft_attr = {};
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_macsec_tables *tx_tables;
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_macsec_flow_table *ft_crypto;
+ struct mlx5_flow_table *flow_table;
+ struct mlx5_flow_group *flow_group;
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ u32 *flow_group_in;
+ int err;
+
+ ns = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_EGRESS_MACSEC);
+ if (!ns)
+ return -ENOMEM;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+ if (!flow_group_in) {
+ err = -ENOMEM;
+ goto out_spec;
+ }
+
+ tx_tables = &tx_fs->tables;
+ ft_crypto = &tx_tables->ft_crypto;
+
+ /* Tx crypto table */
+ ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
+ ft_attr.level = TX_CRYPTO_TABLE_LEVEL;
+ ft_attr.max_fte = CRYPTO_NUM_MAXSEC_FTE;
+
+ flow_table = mlx5_create_flow_table(ns, &ft_attr);
+ if (IS_ERR(flow_table)) {
+ err = PTR_ERR(flow_table);
+ mlx5_core_err(mdev, "Failed to create MACsec Tx crypto table err(%d)\n", err);
+ goto out_flow_group;
+ }
+ ft_crypto->t = flow_table;
+
+ /* Tx crypto table groups */
+ err = macsec_fs_tx_create_crypto_table_groups(ft_crypto);
+ if (err) {
+ mlx5_core_err(mdev,
+ "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
+ err);
+ goto err;
+ }
+
+ /* Tx crypto table MKE rule - MKE packets shouldn't be offloaded */
+ spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
+ MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ETH_P_PAE);
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
+
+ rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, NULL, 0);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add MACsec TX MKE rule, err=%d\n", err);
+ goto err;
+ }
+ tx_fs->crypto_mke_rule = rule;
+
+ /* Tx crypto table Default miss rule */
+ memset(&flow_act, 0, sizeof(flow_act));
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
+ rule = mlx5_add_flow_rules(ft_crypto->t, NULL, &flow_act, NULL, 0);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add MACsec Tx table default miss rule %d\n", err);
+ goto err;
+ }
+ tx_tables->crypto_miss_rule = rule;
+
+ /* Tx check table */
+ flow_table = macsec_fs_auto_group_table_create(ns, 0, TX_CHECK_TABLE_LEVEL,
+ TX_CHECK_TABLE_NUM_FTE);
+ if (IS_ERR(flow_table)) {
+ err = PTR_ERR(flow_table);
+ mlx5_core_err(mdev, "Fail to create MACsec TX check table, err(%d)\n", err);
+ goto err;
+ }
+ tx_tables->ft_check = flow_table;
+
+ /* Tx check table Default miss group/rule */
+ memset(flow_group_in, 0, inlen);
+ MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1);
+ MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1);
+ flow_group = mlx5_create_flow_group(tx_tables->ft_check, flow_group_in);
+ if (IS_ERR(flow_group)) {
+ err = PTR_ERR(flow_group);
+ mlx5_core_err(mdev,
+ "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
+ err);
+ goto err;
+ }
+ tx_tables->ft_check_group = flow_group;
+
+ /* Tx check table default drop rule */
+ memset(&dest, 0, sizeof(struct mlx5_flow_destination));
+ memset(&flow_act, 0, sizeof(flow_act));
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ dest.counter_id = mlx5_fc_id(tx_tables->check_miss_rule_counter);
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ rule = mlx5_add_flow_rules(tx_tables->ft_check, NULL, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to added MACsec tx check drop rule, err(%d)\n", err);
+ goto err;
+ }
+ tx_tables->check_miss_rule = rule;
+
+ /* Tx check table rule */
+ memset(spec, 0, sizeof(struct mlx5_flow_spec));
+ memset(&dest, 0, sizeof(struct mlx5_flow_destination));
+ memset(&flow_act, 0, sizeof(flow_act));
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 0);
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
+
+ flow_act.flags = FLOW_ACT_NO_APPEND;
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW | MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ dest.counter_id = mlx5_fc_id(tx_tables->check_rule_counter);
+ rule = mlx5_add_flow_rules(tx_tables->ft_check, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add MACsec check rule, err=%d\n", err);
+ goto err;
+ }
+ tx_fs->check_rule = rule;
+
+ err = macsec_fs_tx_roce_create(macsec_fs);
+ if (err)
+ goto err;
+
+ kvfree(flow_group_in);
+ kvfree(spec);
+ return 0;
+
+err:
+ macsec_fs_tx_destroy(macsec_fs);
+out_flow_group:
+ kvfree(flow_group_in);
+out_spec:
+ kvfree(spec);
+ return err;
+}
+
+static int macsec_fs_tx_ft_get(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_macsec_tables *tx_tables;
+ int err = 0;
+
+ tx_tables = &tx_fs->tables;
+ if (tx_tables->refcnt)
+ goto out;
+
+ err = macsec_fs_tx_create(macsec_fs);
+ if (err)
+ return err;
+
+out:
+ tx_tables->refcnt++;
+ return err;
+}
+
+static void macsec_fs_tx_ft_put(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tables *tx_tables = &macsec_fs->tx_fs->tables;
+
+ if (--tx_tables->refcnt)
+ return;
+
+ macsec_fs_tx_destroy(macsec_fs);
+}
+
+static int macsec_fs_tx_setup_fte(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_flow_spec *spec,
+ struct mlx5_flow_act *flow_act,
+ u32 macsec_obj_id,
+ u32 *fs_id)
+{
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ int err = 0;
+ u32 id;
+
+ err = ida_alloc_range(&tx_fs->tx_halloc, 1,
+ MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES,
+ GFP_KERNEL);
+ if (err < 0)
+ return err;
+
+ id = err;
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
+
+ /* Metadata match */
+ MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_a,
+ MLX5_ETH_WQE_FT_META_MACSEC_MASK);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_a,
+ macsec_fs_set_tx_fs_id(id));
+
+ *fs_id = id;
+ flow_act->crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_MACSEC;
+ flow_act->crypto.obj_id = macsec_obj_id;
+
+ mlx5_core_dbg(macsec_fs->mdev, "Tx fte: macsec obj_id %u, fs_id %u\n", macsec_obj_id, id);
+ return 0;
+}
+
+static void macsec_fs_tx_create_sectag_header(const struct macsec_context *ctx,
+ char *reformatbf,
+ size_t *reformat_size)
+{
+ const struct macsec_secy *secy = ctx->secy;
+ bool sci_present = macsec_send_sci(secy);
+ struct mlx5_sectag_header sectag = {};
+ const struct macsec_tx_sc *tx_sc;
+
+ tx_sc = &secy->tx_sc;
+ sectag.ethertype = htons(ETH_P_MACSEC);
+
+ if (sci_present) {
+ sectag.tci_an |= MACSEC_TCI_SC;
+ memcpy(&sectag.sci, &secy->sci,
+ sizeof(sectag.sci));
+ } else {
+ if (tx_sc->end_station)
+ sectag.tci_an |= MACSEC_TCI_ES;
+ if (tx_sc->scb)
+ sectag.tci_an |= MACSEC_TCI_SCB;
+ }
+
+ /* With GCM, C/E clear for !encrypt, both set for encrypt */
+ if (tx_sc->encrypt)
+ sectag.tci_an |= MACSEC_TCI_CONFID;
+ else if (secy->icv_len != MACSEC_DEFAULT_ICV_LEN)
+ sectag.tci_an |= MACSEC_TCI_C;
+
+ sectag.tci_an |= tx_sc->encoding_sa;
+
+ *reformat_size = MLX5_MACSEC_TAG_LEN + (sci_present ? MACSEC_SCI_LEN : 0);
+
+ memcpy(reformatbf, &sectag, *reformat_size);
+}
+
+static bool macsec_fs_is_macsec_device_empty(struct mlx5_macsec_device *macsec_device)
+{
+ if (xa_empty(&macsec_device->tx_id_xa) &&
+ xa_empty(&macsec_device->rx_id_xa))
+ return true;
+
+ return false;
+}
+
+static void macsec_fs_id_del(struct list_head *macsec_devices_list, u32 fs_id,
+ void *macdev, struct rhashtable *hash_table, bool is_tx)
+{
+ const struct rhashtable_params *rhash = (is_tx) ? &rhash_sci : &rhash_fs_id;
+ struct mlx5_macsec_device *iter, *macsec_device = NULL;
+ struct mlx5_fs_id *fs_id_found;
+ struct xarray *fs_id_xa;
+
+ list_for_each_entry(iter, macsec_devices_list, macsec_devices_list_entry) {
+ if (iter->macdev == macdev) {
+ macsec_device = iter;
+ break;
+ }
+ }
+ WARN_ON(!macsec_device);
+
+ fs_id_xa = (is_tx) ? &macsec_device->tx_id_xa :
+ &macsec_device->rx_id_xa;
+ xa_lock(fs_id_xa);
+ fs_id_found = xa_load(fs_id_xa, fs_id);
+ WARN_ON(!fs_id_found);
+
+ if (!refcount_dec_and_test(&fs_id_found->refcnt)) {
+ xa_unlock(fs_id_xa);
+ return;
+ }
+
+ if (fs_id_found->id) {
+ /* Make sure ongoing datapath readers sees a valid SA */
+ rhashtable_remove_fast(hash_table, &fs_id_found->hash, *rhash);
+ fs_id_found->id = 0;
+ }
+ xa_unlock(fs_id_xa);
+
+ xa_erase(fs_id_xa, fs_id);
+
+ kfree(fs_id_found);
+
+ if (macsec_fs_is_macsec_device_empty(macsec_device)) {
+ list_del(&macsec_device->macsec_devices_list_entry);
+ kfree(macsec_device);
+ }
+}
+
+static int macsec_fs_id_add(struct list_head *macsec_devices_list, u32 fs_id,
+ void *macdev, struct rhashtable *hash_table, sci_t sci,
+ bool is_tx)
+{
+ const struct rhashtable_params *rhash = (is_tx) ? &rhash_sci : &rhash_fs_id;
+ struct mlx5_macsec_device *iter, *macsec_device = NULL;
+ struct mlx5_fs_id *fs_id_iter;
+ struct xarray *fs_id_xa;
+ int err;
+
+ if (!is_tx) {
+ rcu_read_lock();
+ fs_id_iter = rhashtable_lookup(hash_table, &fs_id, rhash_fs_id);
+ if (fs_id_iter) {
+ refcount_inc(&fs_id_iter->refcnt);
+ rcu_read_unlock();
+ return 0;
+ }
+ rcu_read_unlock();
+ }
+
+ fs_id_iter = kzalloc(sizeof(*fs_id_iter), GFP_KERNEL);
+ if (!fs_id_iter)
+ return -ENOMEM;
+
+ list_for_each_entry(iter, macsec_devices_list, macsec_devices_list_entry) {
+ if (iter->macdev == macdev) {
+ macsec_device = iter;
+ break;
+ }
+ }
+
+ if (!macsec_device) { /* first time adding a SA to that device */
+ macsec_device = kzalloc(sizeof(*macsec_device), GFP_KERNEL);
+ if (!macsec_device) {
+ err = -ENOMEM;
+ goto err_alloc_dev;
+ }
+ macsec_device->macdev = macdev;
+ xa_init(&macsec_device->tx_id_xa);
+ xa_init(&macsec_device->rx_id_xa);
+ list_add(&macsec_device->macsec_devices_list_entry, macsec_devices_list);
+ }
+
+ fs_id_xa = (is_tx) ? &macsec_device->tx_id_xa :
+ &macsec_device->rx_id_xa;
+ fs_id_iter->id = fs_id;
+ refcount_set(&fs_id_iter->refcnt, 1);
+ fs_id_iter->sci = sci;
+ err = xa_err(xa_store(fs_id_xa, fs_id, fs_id_iter, GFP_KERNEL));
+ if (err)
+ goto err_store_id;
+
+ err = rhashtable_insert_fast(hash_table, &fs_id_iter->hash, *rhash);
+ if (err)
+ goto err_hash_insert;
+
+ return 0;
+
+err_hash_insert:
+ xa_erase(fs_id_xa, fs_id);
+err_store_id:
+ if (macsec_fs_is_macsec_device_empty(macsec_device)) {
+ list_del(&macsec_device->macsec_devices_list_entry);
+ kfree(macsec_device);
+ }
+err_alloc_dev:
+ kfree(fs_id_iter);
+ return err;
+}
+
+static void macsec_fs_tx_del_rule(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_macsec_tx_rule *tx_rule,
+ void *macdev)
+{
+ macsec_fs_id_del(&macsec_fs->macsec_devices_list, tx_rule->fs_id, macdev,
+ &macsec_fs->sci_hash, true);
+
+ if (tx_rule->rule) {
+ mlx5_del_flow_rules(tx_rule->rule);
+ tx_rule->rule = NULL;
+ }
+
+ if (tx_rule->pkt_reformat) {
+ mlx5_packet_reformat_dealloc(macsec_fs->mdev, tx_rule->pkt_reformat);
+ tx_rule->pkt_reformat = NULL;
+ }
+
+ if (tx_rule->fs_id) {
+ ida_free(&macsec_fs->tx_fs->tx_halloc, tx_rule->fs_id);
+ tx_rule->fs_id = 0;
+ }
+
+ kfree(tx_rule);
+
+ macsec_fs_tx_ft_put(macsec_fs);
+}
+
+#define MLX5_REFORMAT_PARAM_ADD_MACSEC_OFFSET_4_BYTES 1
+
+static union mlx5_macsec_rule *
+macsec_fs_tx_add_rule(struct mlx5_macsec_fs *macsec_fs,
+ const struct macsec_context *macsec_ctx,
+ struct mlx5_macsec_rule_attrs *attrs, u32 *fs_id)
+{
+ char reformatbf[MLX5_MACSEC_TAG_LEN + MACSEC_SCI_LEN];
+ struct mlx5_pkt_reformat_params reformat_params = {};
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ union mlx5_macsec_rule *macsec_rule = NULL;
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_macsec_tables *tx_tables;
+ struct mlx5_macsec_tx_rule *tx_rule;
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ size_t reformat_size;
+ int err = 0;
+
+ tx_tables = &tx_fs->tables;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return NULL;
+
+ err = macsec_fs_tx_ft_get(macsec_fs);
+ if (err)
+ goto out_spec;
+
+ macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL);
+ if (!macsec_rule) {
+ macsec_fs_tx_ft_put(macsec_fs);
+ goto out_spec;
+ }
+
+ tx_rule = &macsec_rule->tx_rule;
+
+ /* Tx crypto table crypto rule */
+ macsec_fs_tx_create_sectag_header(macsec_ctx, reformatbf, &reformat_size);
+
+ reformat_params.type = MLX5_REFORMAT_TYPE_ADD_MACSEC;
+ reformat_params.size = reformat_size;
+ reformat_params.data = reformatbf;
+
+ if (is_vlan_dev(macsec_ctx->netdev))
+ reformat_params.param_0 = MLX5_REFORMAT_PARAM_ADD_MACSEC_OFFSET_4_BYTES;
+
+ flow_act.pkt_reformat = mlx5_packet_reformat_alloc(mdev,
+ &reformat_params,
+ MLX5_FLOW_NAMESPACE_EGRESS_MACSEC);
+ if (IS_ERR(flow_act.pkt_reformat)) {
+ err = PTR_ERR(flow_act.pkt_reformat);
+ mlx5_core_err(mdev, "Failed to allocate MACsec Tx reformat context err=%d\n", err);
+ goto err;
+ }
+ tx_rule->pkt_reformat = flow_act.pkt_reformat;
+
+ err = macsec_fs_tx_setup_fte(macsec_fs, spec, &flow_act, attrs->macsec_obj_id, fs_id);
+ if (err) {
+ mlx5_core_err(mdev,
+ "Failed to add packet reformat for MACsec TX crypto rule, err=%d\n",
+ err);
+ goto err;
+ }
+
+ tx_rule->fs_id = *fs_id;
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+ MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT |
+ MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest.ft = tx_tables->ft_check;
+ rule = mlx5_add_flow_rules(tx_tables->ft_crypto.t, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add MACsec TX crypto rule, err=%d\n", err);
+ goto err;
+ }
+ tx_rule->rule = rule;
+
+ err = macsec_fs_id_add(&macsec_fs->macsec_devices_list, *fs_id, macsec_ctx->secy->netdev,
+ &macsec_fs->sci_hash, attrs->sci, true);
+ if (err) {
+ mlx5_core_err(mdev, "Failed to save fs_id, err=%d\n", err);
+ goto err;
+ }
+
+ goto out_spec;
+
+err:
+ macsec_fs_tx_del_rule(macsec_fs, tx_rule, macsec_ctx->secy->netdev);
+ macsec_rule = NULL;
+out_spec:
+ kvfree(spec);
+
+ return macsec_rule;
+}
+
+static void macsec_fs_tx_cleanup(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_macsec_tables *tx_tables;
+
+ if (!tx_fs)
+ return;
+
+ tx_tables = &tx_fs->tables;
+ if (tx_tables->refcnt) {
+ mlx5_core_err(mdev,
+ "Can't destroy MACsec offload tx_fs, refcnt(%u) isn't 0\n",
+ tx_tables->refcnt);
+ return;
+ }
+
+ ida_destroy(&tx_fs->tx_halloc);
+
+ if (tx_tables->check_miss_rule_counter) {
+ mlx5_fc_destroy(mdev, tx_tables->check_miss_rule_counter);
+ tx_tables->check_miss_rule_counter = NULL;
+ }
+
+ if (tx_tables->check_rule_counter) {
+ mlx5_fc_destroy(mdev, tx_tables->check_rule_counter);
+ tx_tables->check_rule_counter = NULL;
+ }
+
+ kfree(tx_fs);
+ macsec_fs->tx_fs = NULL;
+}
+
+static int macsec_fs_tx_init(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_macsec_tables *tx_tables;
+ struct mlx5_macsec_tx *tx_fs;
+ struct mlx5_fc *flow_counter;
+ int err;
+
+ tx_fs = kzalloc(sizeof(*tx_fs), GFP_KERNEL);
+ if (!tx_fs)
+ return -ENOMEM;
+
+ tx_tables = &tx_fs->tables;
+
+ flow_counter = mlx5_fc_create(mdev, false);
+ if (IS_ERR(flow_counter)) {
+ err = PTR_ERR(flow_counter);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec Tx encrypt flow counter, err(%d)\n",
+ err);
+ goto err_encrypt_counter;
+ }
+ tx_tables->check_rule_counter = flow_counter;
+
+ flow_counter = mlx5_fc_create(mdev, false);
+ if (IS_ERR(flow_counter)) {
+ err = PTR_ERR(flow_counter);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec Tx drop flow counter, err(%d)\n",
+ err);
+ goto err_drop_counter;
+ }
+ tx_tables->check_miss_rule_counter = flow_counter;
+
+ ida_init(&tx_fs->tx_halloc);
+ INIT_LIST_HEAD(&macsec_fs->macsec_devices_list);
+
+ macsec_fs->tx_fs = tx_fs;
+
+ return 0;
+
+err_drop_counter:
+ mlx5_fc_destroy(mdev, tx_tables->check_rule_counter);
+ tx_tables->check_rule_counter = NULL;
+
+err_encrypt_counter:
+ kfree(tx_fs);
+ macsec_fs->tx_fs = NULL;
+
+ return err;
+}
+
+static void macsec_fs_rx_roce_miss_destroy(struct mlx5_macsec_miss *miss)
+{
+ mlx5_del_flow_rules(miss->rule);
+ mlx5_destroy_flow_group(miss->g);
+}
+
+static void macsec_fs_rdma_rx_destroy(struct mlx5_macsec_rx_roce *roce, struct mlx5_core_dev *mdev)
+{
+ if (!mlx5_is_macsec_roce_supported(mdev))
+ return;
+
+ mlx5_del_flow_rules(roce->nic_miss.rule);
+ mlx5_del_flow_rules(roce->rule);
+ mlx5_modify_header_dealloc(mdev, roce->copy_modify_hdr);
+ mlx5_destroy_flow_group(roce->nic_miss.g);
+ mlx5_destroy_flow_group(roce->g);
+ mlx5_destroy_flow_table(roce->ft);
+
+ macsec_fs_rx_roce_miss_destroy(&roce->miss);
+ mlx5_destroy_flow_table(roce->ft_macsec_op_check);
+ mlx5_destroy_flow_table(roce->ft_ip_check);
+}
+
+static void macsec_fs_rx_destroy(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_macsec_tables *rx_tables;
+ int i;
+
+ /* Rx check table */
+ for (i = 1; i >= 0; --i) {
+ if (rx_fs->check_rule[i]) {
+ mlx5_del_flow_rules(rx_fs->check_rule[i]);
+ rx_fs->check_rule[i] = NULL;
+ }
+
+ if (rx_fs->check_rule_pkt_reformat[i]) {
+ mlx5_packet_reformat_dealloc(macsec_fs->mdev,
+ rx_fs->check_rule_pkt_reformat[i]);
+ rx_fs->check_rule_pkt_reformat[i] = NULL;
+ }
+ }
+
+ rx_tables = &rx_fs->tables;
+
+ if (rx_tables->check_miss_rule) {
+ mlx5_del_flow_rules(rx_tables->check_miss_rule);
+ rx_tables->check_miss_rule = NULL;
+ }
+
+ if (rx_tables->ft_check_group) {
+ mlx5_destroy_flow_group(rx_tables->ft_check_group);
+ rx_tables->ft_check_group = NULL;
+ }
+
+ if (rx_tables->ft_check) {
+ mlx5_destroy_flow_table(rx_tables->ft_check);
+ rx_tables->ft_check = NULL;
+ }
+
+ /* Rx crypto table */
+ if (rx_tables->crypto_miss_rule) {
+ mlx5_del_flow_rules(rx_tables->crypto_miss_rule);
+ rx_tables->crypto_miss_rule = NULL;
+ }
+
+ macsec_fs_destroy_flow_table(&rx_tables->ft_crypto);
+
+ macsec_fs_rdma_rx_destroy(&macsec_fs->rx_fs->roce, macsec_fs->mdev);
+}
+
+static int macsec_fs_rx_create_crypto_table_groups(struct mlx5_macsec_flow_table *ft)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ int mclen = MLX5_ST_SZ_BYTES(fte_match_param);
+ int ix = 0;
+ u32 *in;
+ int err;
+ u8 *mc;
+
+ ft->g = kcalloc(RX_CRYPTO_TABLE_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
+ if (!ft->g)
+ return -ENOMEM;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in) {
+ kfree(ft->g);
+ return -ENOMEM;
+ }
+
+ mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+
+ /* Flow group for SA rule with SCI */
+ MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS |
+ MLX5_MATCH_MISC_PARAMETERS_5);
+ MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
+
+ MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0,
+ MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK <<
+ MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+ MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_2);
+ MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_3);
+
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ /* Flow group for SA rule without SCI */
+ memset(in, 0, inlen);
+ memset(mc, 0, mclen);
+ MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS |
+ MLX5_MATCH_MISC_PARAMETERS_5);
+ MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_15_0);
+ MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype);
+
+ MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0,
+ MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ /* Flow Group for l2 traps */
+ memset(in, 0, inlen);
+ memset(mc, 0, mclen);
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
+ if (IS_ERR(ft->g[ft->num_groups]))
+ goto err;
+ ft->num_groups++;
+
+ kvfree(in);
+ return 0;
+
+err:
+ err = PTR_ERR(ft->g[ft->num_groups]);
+ ft->g[ft->num_groups] = NULL;
+ kvfree(in);
+
+ return err;
+}
+
+static int macsec_fs_rx_create_check_decap_rule(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_flow_destination *dest,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_spec *spec,
+ int reformat_param_size)
+{
+ int rule_index = (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI) ? 0 : 1;
+ u8 mlx5_reformat_buf[MLX5_SECTAG_HEADER_SIZE_WITH_SCI];
+ struct mlx5_pkt_reformat_params reformat_params = {};
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_flow_destination roce_dest[2];
+ struct mlx5_macsec_tables *rx_tables;
+ struct mlx5_flow_handle *rule;
+ int err = 0, dstn = 0;
+
+ rx_tables = &rx_fs->tables;
+
+ /* Rx check table decap 16B rule */
+ memset(dest, 0, sizeof(*dest));
+ memset(flow_act, 0, sizeof(*flow_act));
+ memset(spec, 0, sizeof(*spec));
+
+ reformat_params.type = MLX5_REFORMAT_TYPE_DEL_MACSEC;
+ reformat_params.size = reformat_param_size;
+ reformat_params.data = mlx5_reformat_buf;
+ flow_act->pkt_reformat = mlx5_packet_reformat_alloc(mdev,
+ &reformat_params,
+ MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
+ if (IS_ERR(flow_act->pkt_reformat)) {
+ err = PTR_ERR(flow_act->pkt_reformat);
+ mlx5_core_err(mdev, "Failed to allocate MACsec Rx reformat context err=%d\n", err);
+ return err;
+ }
+ rx_fs->check_rule_pkt_reformat[rule_index] = flow_act->pkt_reformat;
+
+ spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
+ /* MACsec syndrome match */
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.macsec_syndrome);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.macsec_syndrome, 0);
+ /* ASO return reg syndrome match */
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 0);
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5;
+ /* Sectag TCI SC present bit*/
+ MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0,
+ MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+
+ if (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI)
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0,
+ MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT <<
+ MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+
+ flow_act->flags = FLOW_ACT_NO_APPEND;
+
+ if (rx_fs->roce.ft) {
+ flow_act->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ roce_dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ roce_dest[dstn].ft = rx_fs->roce.ft;
+ dstn++;
+ } else {
+ flow_act->action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
+ }
+
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
+ MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ roce_dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ roce_dest[dstn].counter_id = mlx5_fc_id(rx_tables->check_rule_counter);
+ rule = mlx5_add_flow_rules(rx_tables->ft_check, spec, flow_act, roce_dest, dstn + 1);
+
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add MACsec Rx check rule, err=%d\n", err);
+ return err;
+ }
+
+ rx_fs->check_rule[rule_index] = rule;
+
+ return 0;
+}
+
+static int macsec_fs_rx_roce_miss_create(struct mlx5_core_dev *mdev,
+ struct mlx5_macsec_rx_roce *roce)
+{
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_group *flow_group;
+ struct mlx5_flow_handle *rule;
+ u32 *flow_group_in;
+ int err;
+
+ flow_group_in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
+ if (!flow_group_in)
+ return -ENOMEM;
+
+ /* IP check ft has no miss rule since we use default miss action which is go to next PRIO */
+ MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index,
+ roce->ft_macsec_op_check->max_fte - 1);
+ MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
+ roce->ft_macsec_op_check->max_fte - 1);
+ flow_group = mlx5_create_flow_group(roce->ft_macsec_op_check, flow_group_in);
+ if (IS_ERR(flow_group)) {
+ err = PTR_ERR(flow_group);
+ mlx5_core_err(mdev,
+ "Failed to create miss flow group for MACsec RoCE operation check table err(%d)\n",
+ err);
+ goto err_macsec_op_miss_group;
+ }
+ roce->miss.g = flow_group;
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+ rule = mlx5_add_flow_rules(roce->ft_macsec_op_check, NULL, &flow_act, NULL, 0);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add miss rule to MACsec RoCE operation check table err(%d)\n",
+ err);
+ goto err_macsec_op_rule;
+ }
+ roce->miss.rule = rule;
+
+ kvfree(flow_group_in);
+ return 0;
+
+err_macsec_op_rule:
+ mlx5_destroy_flow_group(roce->miss.g);
+err_macsec_op_miss_group:
+ kvfree(flow_group_in);
+ return err;
+}
+
+#define MLX5_RX_ROCE_GROUP_SIZE BIT(0)
+
+static int macsec_fs_rx_roce_jump_to_rdma_groups_create(struct mlx5_core_dev *mdev,
+ struct mlx5_macsec_rx_roce *roce)
+{
+ struct mlx5_flow_group *g;
+ void *outer_headers_c;
+ int ix = 0;
+ u32 *in;
+ int err;
+ u8 *mc;
+
+ in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
+ if (!in)
+ return -ENOMEM;
+
+ mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
+ outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
+ MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
+ MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
+
+ MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += MLX5_RX_ROCE_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ g = mlx5_create_flow_group(roce->ft, in);
+ if (IS_ERR(g)) {
+ err = PTR_ERR(g);
+ mlx5_core_err(mdev, "Failed to create main flow group for MACsec RoCE NIC UDP table err(%d)\n",
+ err);
+ goto err_udp_group;
+ }
+ roce->g = g;
+
+ memset(in, 0, MLX5_ST_SZ_BYTES(create_flow_group_in));
+ MLX5_SET_CFG(in, start_flow_index, ix);
+ ix += MLX5_RX_ROCE_GROUP_SIZE;
+ MLX5_SET_CFG(in, end_flow_index, ix - 1);
+ g = mlx5_create_flow_group(roce->ft, in);
+ if (IS_ERR(g)) {
+ err = PTR_ERR(g);
+ mlx5_core_err(mdev, "Failed to create miss flow group for MACsec RoCE NIC UDP table err(%d)\n",
+ err);
+ goto err_udp_miss_group;
+ }
+ roce->nic_miss.g = g;
+
+ kvfree(in);
+ return 0;
+
+err_udp_miss_group:
+ mlx5_destroy_flow_group(roce->g);
+err_udp_group:
+ kvfree(in);
+ return err;
+}
+
+static int macsec_fs_rx_roce_jump_to_rdma_rules_create(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_macsec_rx_roce *roce)
+{
+ u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_flow_destination dst = {};
+ struct mlx5_modify_hdr *modify_hdr;
+ MLX5_DECLARE_FLOW_ACT(flow_act);
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ int err;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
+ MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_UDP);
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport);
+ MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, ROCE_V2_UDP_DPORT);
+
+ MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
+ MLX5_SET(copy_action_in, action, src_field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
+ MLX5_SET(copy_action_in, action, src_offset, 0);
+ MLX5_SET(copy_action_in, action, length, 32);
+ MLX5_SET(copy_action_in, action, dst_field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_5);
+ MLX5_SET(copy_action_in, action, dst_offset, 0);
+
+ modify_hdr = mlx5_modify_header_alloc(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC,
+ 1, action);
+
+ if (IS_ERR(modify_hdr)) {
+ err = PTR_ERR(modify_hdr);
+ mlx5_core_err(mdev,
+ "Failed to alloc macsec copy modify_header_id err(%d)\n", err);
+ goto err_alloc_hdr;
+ }
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ flow_act.modify_hdr = modify_hdr;
+ dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
+ dst.ft = roce->ft_ip_check;
+ rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add rule to MACsec RoCE NIC UDP table err(%d)\n",
+ err);
+ goto err_add_rule;
+ }
+ roce->rule = rule;
+ roce->copy_modify_hdr = modify_hdr;
+
+ memset(&flow_act, 0, sizeof(flow_act));
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
+ rule = mlx5_add_flow_rules(roce->ft, NULL, &flow_act, NULL, 0);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to add miss rule to MACsec RoCE NIC UDP table err(%d)\n",
+ err);
+ goto err_add_rule2;
+ }
+ roce->nic_miss.rule = rule;
+
+ kvfree(spec);
+ return 0;
+
+err_add_rule2:
+ mlx5_del_flow_rules(roce->rule);
+err_add_rule:
+ mlx5_modify_header_dealloc(macsec_fs->mdev, modify_hdr);
+err_alloc_hdr:
+ kvfree(spec);
+ return err;
+}
+
+static int macsec_fs_rx_roce_jump_to_rdma_create(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_macsec_rx_roce *roce)
+{
+ int err;
+
+ err = macsec_fs_rx_roce_jump_to_rdma_groups_create(macsec_fs->mdev, roce);
+ if (err)
+ return err;
+
+ err = macsec_fs_rx_roce_jump_to_rdma_rules_create(macsec_fs, roce);
+ if (err)
+ goto err;
+
+ return 0;
+err:
+ mlx5_destroy_flow_group(roce->nic_miss.g);
+ mlx5_destroy_flow_group(roce->g);
+ return err;
+}
+
+static int macsec_fs_rx_roce_create(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_flow_table_attr ft_attr = {};
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_table *ft;
+ int err = 0;
+
+ if (!mlx5_is_macsec_roce_supported(macsec_fs->mdev)) {
+ mlx5_core_dbg(mdev, "Failed to init RoCE MACsec, capabilities not supported\n");
+ return 0;
+ }
+
+ ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_RDMA_RX_MACSEC);
+ if (!ns)
+ return -ENOMEM;
+
+ ft = macsec_fs_auto_group_table_create(ns, 0, RDMA_RX_ROCE_IP_TABLE_LEVEL,
+ CRYPTO_NUM_MAXSEC_FTE);
+ if (IS_ERR(ft)) {
+ err = PTR_ERR(ft);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec IP check RoCE table err(%d)\n", err);
+ return err;
+ }
+ rx_fs->roce.ft_ip_check = ft;
+
+ ft = macsec_fs_auto_group_table_create(ns, 0, RDMA_RX_ROCE_MACSEC_OP_TABLE_LEVEL,
+ CRYPTO_NUM_MAXSEC_FTE);
+ if (IS_ERR(ft)) {
+ err = PTR_ERR(ft);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec operation check RoCE table err(%d)\n",
+ err);
+ goto err_macsec_op;
+ }
+ rx_fs->roce.ft_macsec_op_check = ft;
+
+ err = macsec_fs_rx_roce_miss_create(mdev, &rx_fs->roce);
+ if (err)
+ goto err_miss_create;
+
+ ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
+ if (!ns) {
+ err = -EOPNOTSUPP;
+ goto err_ns;
+ }
+
+ ft_attr.level = RX_ROCE_TABLE_LEVEL;
+ ft_attr.max_fte = RX_ROCE_TABLE_NUM_FTE;
+ ft = mlx5_create_flow_table(ns, &ft_attr);
+ if (IS_ERR(ft)) {
+ err = PTR_ERR(ft);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec jump to RX RoCE, NIC table err(%d)\n", err);
+ goto err_ns;
+ }
+ rx_fs->roce.ft = ft;
+
+ err = macsec_fs_rx_roce_jump_to_rdma_create(macsec_fs, &rx_fs->roce);
+ if (err)
+ goto err_udp_ft;
+
+ return 0;
+
+err_udp_ft:
+ mlx5_destroy_flow_table(rx_fs->roce.ft);
+err_ns:
+ macsec_fs_rx_roce_miss_destroy(&rx_fs->roce.miss);
+err_miss_create:
+ mlx5_destroy_flow_table(rx_fs->roce.ft_macsec_op_check);
+err_macsec_op:
+ mlx5_destroy_flow_table(rx_fs->roce.ft_ip_check);
+ return err;
+}
+
+static int macsec_fs_rx_create(struct mlx5_macsec_fs *macsec_fs)
+{
+ int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_macsec_flow_table *ft_crypto;
+ struct mlx5_flow_table_attr ft_attr = {};
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_macsec_tables *rx_tables;
+ struct mlx5_flow_table *flow_table;
+ struct mlx5_flow_group *flow_group;
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_namespace *ns;
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ u32 *flow_group_in;
+ int err;
+
+ ns = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC);
+ if (!ns)
+ return -ENOMEM;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+ if (!flow_group_in) {
+ err = -ENOMEM;
+ goto free_spec;
+ }
+
+ rx_tables = &rx_fs->tables;
+ ft_crypto = &rx_tables->ft_crypto;
+
+ err = macsec_fs_rx_roce_create(macsec_fs);
+ if (err)
+ goto out_flow_group;
+
+ /* Rx crypto table */
+ ft_attr.level = RX_CRYPTO_TABLE_LEVEL;
+ ft_attr.max_fte = CRYPTO_NUM_MAXSEC_FTE;
+
+ flow_table = mlx5_create_flow_table(ns, &ft_attr);
+ if (IS_ERR(flow_table)) {
+ err = PTR_ERR(flow_table);
+ mlx5_core_err(mdev, "Failed to create MACsec Rx crypto table err(%d)\n", err);
+ goto err;
+ }
+ ft_crypto->t = flow_table;
+
+ /* Rx crypto table groups */
+ err = macsec_fs_rx_create_crypto_table_groups(ft_crypto);
+ if (err) {
+ mlx5_core_err(mdev,
+ "Failed to create default flow group for MACsec Tx crypto table err(%d)\n",
+ err);
+ goto err;
+ }
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
+ rule = mlx5_add_flow_rules(ft_crypto->t, NULL, &flow_act, NULL, 0);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev,
+ "Failed to add MACsec Rx crypto table default miss rule %d\n",
+ err);
+ goto err;
+ }
+ rx_tables->crypto_miss_rule = rule;
+
+ /* Rx check table */
+ flow_table = macsec_fs_auto_group_table_create(ns,
+ MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT,
+ RX_CHECK_TABLE_LEVEL,
+ RX_CHECK_TABLE_NUM_FTE);
+ if (IS_ERR(flow_table)) {
+ err = PTR_ERR(flow_table);
+ mlx5_core_err(mdev, "Fail to create MACsec RX check table, err(%d)\n", err);
+ goto err;
+ }
+ rx_tables->ft_check = flow_table;
+
+ /* Rx check table Default miss group/rule */
+ MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1);
+ MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1);
+ flow_group = mlx5_create_flow_group(rx_tables->ft_check, flow_group_in);
+ if (IS_ERR(flow_group)) {
+ err = PTR_ERR(flow_group);
+ mlx5_core_err(mdev,
+ "Failed to create default flow group for MACsec Rx check table err(%d)\n",
+ err);
+ goto err;
+ }
+ rx_tables->ft_check_group = flow_group;
+
+ /* Rx check table default drop rule */
+ memset(&flow_act, 0, sizeof(flow_act));
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ dest.counter_id = mlx5_fc_id(rx_tables->check_miss_rule_counter);
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ rule = mlx5_add_flow_rules(rx_tables->ft_check, NULL, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev, "Failed to added MACsec Rx check drop rule, err(%d)\n", err);
+ goto err;
+ }
+ rx_tables->check_miss_rule = rule;
+
+ /* Rx check table decap rules */
+ err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec,
+ MLX5_SECTAG_HEADER_SIZE_WITH_SCI);
+ if (err)
+ goto err;
+
+ err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec,
+ MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI);
+ if (err)
+ goto err;
+
+ goto out_flow_group;
+
+err:
+ macsec_fs_rx_destroy(macsec_fs);
+out_flow_group:
+ kvfree(flow_group_in);
+free_spec:
+ kvfree(spec);
+ return err;
+}
+
+static int macsec_fs_rx_ft_get(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
+ int err = 0;
+
+ if (rx_tables->refcnt)
+ goto out;
+
+ err = macsec_fs_rx_create(macsec_fs);
+ if (err)
+ return err;
+
+out:
+ rx_tables->refcnt++;
+ return err;
+}
+
+static void macsec_fs_rx_ft_put(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
+
+ if (--rx_tables->refcnt)
+ return;
+
+ macsec_fs_rx_destroy(macsec_fs);
+}
+
+static void macsec_fs_rx_del_rule(struct mlx5_macsec_fs *macsec_fs,
+ struct mlx5_macsec_rx_rule *rx_rule,
+ void *macdev, u32 fs_id)
+{
+ int i;
+
+ macsec_fs_id_del(&macsec_fs->macsec_devices_list, fs_id, macdev,
+ &macsec_fs->fs_id_hash, false);
+
+ for (i = 0; i < RX_NUM_OF_RULES_PER_SA; ++i) {
+ if (rx_rule->rule[i]) {
+ mlx5_del_flow_rules(rx_rule->rule[i]);
+ rx_rule->rule[i] = NULL;
+ }
+ }
+
+ if (rx_rule->meta_modhdr) {
+ mlx5_modify_header_dealloc(macsec_fs->mdev, rx_rule->meta_modhdr);
+ rx_rule->meta_modhdr = NULL;
+ }
+
+ kfree(rx_rule);
+
+ macsec_fs_rx_ft_put(macsec_fs);
+}
+
+static void macsec_fs_rx_setup_fte(struct mlx5_flow_spec *spec,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_macsec_rule_attrs *attrs,
+ bool sci_present)
+{
+ u8 tci_an = (sci_present << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET) | attrs->assoc_num;
+ struct mlx5_flow_act_crypto_params *crypto_params = &flow_act->crypto;
+ __be32 *sci_p = (__be32 *)(&attrs->sci);
+
+ spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
+
+ /* MACsec ethertype */
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype);
+ MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ETH_P_MACSEC);
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5;
+
+ /* Sectag AN + TCI SC present bit*/
+ MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0,
+ MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0,
+ tci_an << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET);
+
+ if (sci_present) {
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ misc_parameters_5.macsec_tag_2);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_2,
+ be32_to_cpu(sci_p[0]));
+
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ misc_parameters_5.macsec_tag_3);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_3,
+ be32_to_cpu(sci_p[1]));
+ } else {
+ /* When SCI isn't present in the Sectag, need to match the source */
+ /* MAC address only if the SCI contains the default MACsec PORT */
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16);
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0);
+ memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.smac_47_16),
+ sci_p, ETH_ALEN);
+ }
+
+ crypto_params->type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_MACSEC;
+ crypto_params->obj_id = attrs->macsec_obj_id;
+}
+
+static union mlx5_macsec_rule *
+macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,
+ const struct macsec_context *macsec_ctx,
+ struct mlx5_macsec_rule_attrs *attrs,
+ u32 fs_id)
+{
+ u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ union mlx5_macsec_rule *macsec_rule = NULL;
+ struct mlx5_modify_hdr *modify_hdr = NULL;
+ struct mlx5_macsec_flow_table *ft_crypto;
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_macsec_tables *rx_tables;
+ struct mlx5_macsec_rx_rule *rx_rule;
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *rule;
+ struct mlx5_flow_spec *spec;
+ int err = 0;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return NULL;
+
+ err = macsec_fs_rx_ft_get(macsec_fs);
+ if (err)
+ goto out_spec;
+
+ macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL);
+ if (!macsec_rule) {
+ macsec_fs_rx_ft_put(macsec_fs);
+ goto out_spec;
+ }
+
+ rx_rule = &macsec_rule->rx_rule;
+ rx_tables = &rx_fs->tables;
+ ft_crypto = &rx_tables->ft_crypto;
+
+ /* Set bit[31 - 30] macsec marker - 0x01 */
+ /* Set bit[15-0] fs id */
+ MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
+ MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
+ MLX5_SET(set_action_in, action, data, macsec_fs_set_rx_fs_id(fs_id));
+ MLX5_SET(set_action_in, action, offset, 0);
+ MLX5_SET(set_action_in, action, length, 32);
+
+ modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC,
+ 1, action);
+ if (IS_ERR(modify_hdr)) {
+ err = PTR_ERR(modify_hdr);
+ mlx5_core_err(mdev, "Fail to alloc MACsec set modify_header_id err=%d\n", err);
+ modify_hdr = NULL;
+ goto err;
+ }
+ rx_rule->meta_modhdr = modify_hdr;
+
+ /* Rx crypto table with SCI rule */
+ macsec_fs_rx_setup_fte(spec, &flow_act, attrs, true);
+
+ flow_act.modify_hdr = modify_hdr;
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+ MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
+ MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest.ft = rx_tables->ft_check;
+ rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev,
+ "Failed to add SA with SCI rule to Rx crypto rule, err=%d\n",
+ err);
+ goto err;
+ }
+ rx_rule->rule[0] = rule;
+
+ /* Rx crypto table without SCI rule */
+ if ((cpu_to_be64((__force u64)attrs->sci) & 0xFFFF) == ntohs(MACSEC_PORT_ES)) {
+ memset(spec, 0, sizeof(struct mlx5_flow_spec));
+ memset(&dest, 0, sizeof(struct mlx5_flow_destination));
+ memset(&flow_act, 0, sizeof(flow_act));
+
+ macsec_fs_rx_setup_fte(spec, &flow_act, attrs, false);
+
+ flow_act.modify_hdr = modify_hdr;
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+ MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
+ MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ dest.ft = rx_tables->ft_check;
+ rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1);
+ if (IS_ERR(rule)) {
+ err = PTR_ERR(rule);
+ mlx5_core_err(mdev,
+ "Failed to add SA without SCI rule to Rx crypto rule, err=%d\n",
+ err);
+ goto err;
+ }
+ rx_rule->rule[1] = rule;
+ }
+
+ err = macsec_fs_id_add(&macsec_fs->macsec_devices_list, fs_id, macsec_ctx->secy->netdev,
+ &macsec_fs->fs_id_hash, attrs->sci, false);
+ if (err) {
+ mlx5_core_err(mdev, "Failed to save fs_id, err=%d\n", err);
+ goto err;
+ }
+
+ kvfree(spec);
+ return macsec_rule;
+
+err:
+ macsec_fs_rx_del_rule(macsec_fs, rx_rule, macsec_ctx->secy->netdev, fs_id);
+ macsec_rule = NULL;
+out_spec:
+ kvfree(spec);
+ return macsec_rule;
+}
+
+static int macsec_fs_rx_init(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_macsec_tables *rx_tables;
+ struct mlx5_macsec_rx *rx_fs;
+ struct mlx5_fc *flow_counter;
+ int err;
+
+ rx_fs = kzalloc(sizeof(*rx_fs), GFP_KERNEL);
+ if (!rx_fs)
+ return -ENOMEM;
+
+ flow_counter = mlx5_fc_create(mdev, false);
+ if (IS_ERR(flow_counter)) {
+ err = PTR_ERR(flow_counter);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec Rx encrypt flow counter, err(%d)\n",
+ err);
+ goto err_encrypt_counter;
+ }
+
+ rx_tables = &rx_fs->tables;
+ rx_tables->check_rule_counter = flow_counter;
+
+ flow_counter = mlx5_fc_create(mdev, false);
+ if (IS_ERR(flow_counter)) {
+ err = PTR_ERR(flow_counter);
+ mlx5_core_err(mdev,
+ "Failed to create MACsec Rx drop flow counter, err(%d)\n",
+ err);
+ goto err_drop_counter;
+ }
+ rx_tables->check_miss_rule_counter = flow_counter;
+
+ macsec_fs->rx_fs = rx_fs;
+
+ return 0;
+
+err_drop_counter:
+ mlx5_fc_destroy(mdev, rx_tables->check_rule_counter);
+ rx_tables->check_rule_counter = NULL;
+
+err_encrypt_counter:
+ kfree(rx_fs);
+ macsec_fs->rx_fs = NULL;
+
+ return err;
+}
+
+static void macsec_fs_rx_cleanup(struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_macsec_tables *rx_tables;
+
+ if (!rx_fs)
+ return;
+
+ rx_tables = &rx_fs->tables;
+
+ if (rx_tables->refcnt) {
+ mlx5_core_err(mdev,
+ "Can't destroy MACsec offload rx_fs, refcnt(%u) isn't 0\n",
+ rx_tables->refcnt);
+ return;
+ }
+
+ if (rx_tables->check_miss_rule_counter) {
+ mlx5_fc_destroy(mdev, rx_tables->check_miss_rule_counter);
+ rx_tables->check_miss_rule_counter = NULL;
+ }
+
+ if (rx_tables->check_rule_counter) {
+ mlx5_fc_destroy(mdev, rx_tables->check_rule_counter);
+ rx_tables->check_rule_counter = NULL;
+ }
+
+ kfree(rx_fs);
+ macsec_fs->rx_fs = NULL;
+}
+
+static void set_ipaddr_spec_v4(struct sockaddr_in *in, struct mlx5_flow_spec *spec, bool is_dst_ip)
+{
+ MLX5_SET(fte_match_param, spec->match_value,
+ outer_headers.ip_version, MLX5_FS_IPV4_VERSION);
+
+ if (is_dst_ip) {
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
+ memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
+ &in->sin_addr.s_addr, 4);
+ } else {
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
+ memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4),
+ &in->sin_addr.s_addr, 4);
+ }
+}
+
+static void set_ipaddr_spec_v6(struct sockaddr_in6 *in6, struct mlx5_flow_spec *spec,
+ bool is_dst_ip)
+{
+ MLX5_SET(fte_match_param, spec->match_value,
+ outer_headers.ip_version, MLX5_FS_IPV6_VERSION);
+
+ if (is_dst_ip) {
+ memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+ 0xff, 16);
+ memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+ &in6->sin6_addr, 16);
+ } else {
+ memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
+ 0xff, 16);
+ memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
+ &in6->sin6_addr, 16);
+ }
+}
+
+static void set_ipaddr_spec(const struct sockaddr *addr,
+ struct mlx5_flow_spec *spec, bool is_dst_ip)
+{
+ struct sockaddr_in6 *in6;
+
+ spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
+ outer_headers.ip_version);
+
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in *in = (struct sockaddr_in *)addr;
+
+ set_ipaddr_spec_v4(in, spec, is_dst_ip);
+ return;
+ }
+
+ in6 = (struct sockaddr_in6 *)addr;
+ set_ipaddr_spec_v6(in6, spec, is_dst_ip);
+}
+
+static void macsec_fs_del_roce_rule_rx(struct mlx5_roce_macsec_rx_rule *rx_rule)
+{
+ mlx5_del_flow_rules(rx_rule->op);
+ mlx5_del_flow_rules(rx_rule->ip);
+ list_del(&rx_rule->entry);
+ kfree(rx_rule);
+}
+
+static void macsec_fs_del_roce_rules_rx(struct mlx5_macsec_fs *macsec_fs, u32 fs_id,
+ struct list_head *rx_rules_list)
+{
+ struct mlx5_roce_macsec_rx_rule *rx_rule, *next;
+
+ if (!mlx5_is_macsec_roce_supported(macsec_fs->mdev))
+ return;
+
+ list_for_each_entry_safe(rx_rule, next, rx_rules_list, entry) {
+ if (rx_rule->fs_id == fs_id)
+ macsec_fs_del_roce_rule_rx(rx_rule);
+ }
+}
+
+static void macsec_fs_del_roce_rule_tx(struct mlx5_core_dev *mdev,
+ struct mlx5_roce_macsec_tx_rule *tx_rule)
+{
+ mlx5_del_flow_rules(tx_rule->rule);
+ mlx5_modify_header_dealloc(mdev, tx_rule->meta_modhdr);
+ list_del(&tx_rule->entry);
+ kfree(tx_rule);
+}
+
+static void macsec_fs_del_roce_rules_tx(struct mlx5_macsec_fs *macsec_fs, u32 fs_id,
+ struct list_head *tx_rules_list)
+{
+ struct mlx5_roce_macsec_tx_rule *tx_rule, *next;
+
+ if (!mlx5_is_macsec_roce_supported(macsec_fs->mdev))
+ return;
+
+ list_for_each_entry_safe(tx_rule, next, tx_rules_list, entry) {
+ if (tx_rule->fs_id == fs_id)
+ macsec_fs_del_roce_rule_tx(macsec_fs->mdev, tx_rule);
+ }
+}
+
+void mlx5_macsec_fs_get_stats_fill(struct mlx5_macsec_fs *macsec_fs, void *macsec_stats)
+{
+ struct mlx5_macsec_stats *stats = (struct mlx5_macsec_stats *)macsec_stats;
+ struct mlx5_macsec_tables *tx_tables = &macsec_fs->tx_fs->tables;
+ struct mlx5_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+
+ if (tx_tables->check_rule_counter)
+ mlx5_fc_query(mdev, tx_tables->check_rule_counter,
+ &stats->macsec_tx_pkts, &stats->macsec_tx_bytes);
+
+ if (tx_tables->check_miss_rule_counter)
+ mlx5_fc_query(mdev, tx_tables->check_miss_rule_counter,
+ &stats->macsec_tx_pkts_drop, &stats->macsec_tx_bytes_drop);
+
+ if (rx_tables->check_rule_counter)
+ mlx5_fc_query(mdev, rx_tables->check_rule_counter,
+ &stats->macsec_rx_pkts, &stats->macsec_rx_bytes);
+
+ if (rx_tables->check_miss_rule_counter)
+ mlx5_fc_query(mdev, rx_tables->check_miss_rule_counter,
+ &stats->macsec_rx_pkts_drop, &stats->macsec_rx_bytes_drop);
+}
+
+struct mlx5_macsec_stats *mlx5_macsec_fs_get_stats(struct mlx5_macsec_fs *macsec_fs)
+{
+ if (!macsec_fs)
+ return NULL;
+
+ return &macsec_fs->stats;
+}
+
+u32 mlx5_macsec_fs_get_fs_id_from_hashtable(struct mlx5_macsec_fs *macsec_fs, sci_t *sci)
+{
+ struct mlx5_fs_id *mlx5_fs_id;
+ u32 fs_id = 0;
+
+ rcu_read_lock();
+ mlx5_fs_id = rhashtable_lookup(&macsec_fs->sci_hash, sci, rhash_sci);
+ if (mlx5_fs_id)
+ fs_id = mlx5_fs_id->id;
+ rcu_read_unlock();
+
+ return fs_id;
+}
+
+union mlx5_macsec_rule *
+mlx5_macsec_fs_add_rule(struct mlx5_macsec_fs *macsec_fs,
+ const struct macsec_context *macsec_ctx,
+ struct mlx5_macsec_rule_attrs *attrs,
+ u32 *sa_fs_id)
+{
+ struct mlx5_macsec_event_data data = {.macsec_fs = macsec_fs,
+ .macdev = macsec_ctx->secy->netdev,
+ .is_tx =
+ (attrs->action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT)
+ };
+ union mlx5_macsec_rule *macsec_rule;
+ u32 tx_new_fs_id;
+
+ macsec_rule = (attrs->action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ?
+ macsec_fs_tx_add_rule(macsec_fs, macsec_ctx, attrs, &tx_new_fs_id) :
+ macsec_fs_rx_add_rule(macsec_fs, macsec_ctx, attrs, *sa_fs_id);
+
+ data.fs_id = (data.is_tx) ? tx_new_fs_id : *sa_fs_id;
+ if (macsec_rule)
+ blocking_notifier_call_chain(&macsec_fs->mdev->macsec_nh,
+ MLX5_DRIVER_EVENT_MACSEC_SA_ADDED,
+ &data);
+
+ return macsec_rule;
+}
+
+void mlx5_macsec_fs_del_rule(struct mlx5_macsec_fs *macsec_fs,
+ union mlx5_macsec_rule *macsec_rule,
+ int action, void *macdev, u32 sa_fs_id)
+{
+ struct mlx5_macsec_event_data data = {.macsec_fs = macsec_fs,
+ .macdev = macdev,
+ .is_tx = (action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT)
+ };
+
+ data.fs_id = (data.is_tx) ? macsec_rule->tx_rule.fs_id : sa_fs_id;
+ blocking_notifier_call_chain(&macsec_fs->mdev->macsec_nh,
+ MLX5_DRIVER_EVENT_MACSEC_SA_DELETED,
+ &data);
+
+ (action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ?
+ macsec_fs_tx_del_rule(macsec_fs, &macsec_rule->tx_rule, macdev) :
+ macsec_fs_rx_del_rule(macsec_fs, &macsec_rule->rx_rule, macdev, sa_fs_id);
+}
+
+static int mlx5_macsec_fs_add_roce_rule_rx(struct mlx5_macsec_fs *macsec_fs, u32 fs_id, u16 gid_idx,
+ const struct sockaddr *addr,
+ struct list_head *rx_rules_list)
+{
+ struct mlx5_macsec_rx *rx_fs = macsec_fs->rx_fs;
+ struct mlx5_roce_macsec_rx_rule *rx_rule;
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *new_rule;
+ struct mlx5_flow_spec *spec;
+ int err = 0;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ rx_rule = kzalloc(sizeof(*rx_rule), GFP_KERNEL);
+ if (!rx_rule) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ set_ipaddr_spec(addr, spec, true);
+
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ dest.ft = rx_fs->roce.ft_macsec_op_check;
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+ new_rule = mlx5_add_flow_rules(rx_fs->roce.ft_ip_check, spec, &flow_act,
+ &dest, 1);
+ if (IS_ERR(new_rule)) {
+ err = PTR_ERR(new_rule);
+ goto ip_rule_err;
+ }
+ rx_rule->ip = new_rule;
+
+ memset(&flow_act, 0, sizeof(flow_act));
+ memset(spec, 0, sizeof(*spec));
+
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
+ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_5);
+ MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_5,
+ macsec_fs_set_rx_fs_id(fs_id));
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
+ new_rule = mlx5_add_flow_rules(rx_fs->roce.ft_macsec_op_check, spec, &flow_act,
+ NULL, 0);
+ if (IS_ERR(new_rule)) {
+ err = PTR_ERR(new_rule);
+ goto op_rule_err;
+ }
+ rx_rule->op = new_rule;
+ rx_rule->gid_idx = gid_idx;
+ rx_rule->fs_id = fs_id;
+ list_add_tail(&rx_rule->entry, rx_rules_list);
+
+ goto out;
+
+op_rule_err:
+ mlx5_del_flow_rules(rx_rule->ip);
+ rx_rule->ip = NULL;
+ip_rule_err:
+ kfree(rx_rule);
+out:
+ kvfree(spec);
+ return err;
+}
+
+static int mlx5_macsec_fs_add_roce_rule_tx(struct mlx5_macsec_fs *macsec_fs, u32 fs_id, u16 gid_idx,
+ const struct sockaddr *addr,
+ struct list_head *tx_rules_list)
+{
+ u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
+ struct mlx5_macsec_tx *tx_fs = macsec_fs->tx_fs;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_modify_hdr *modify_hdr = NULL;
+ struct mlx5_roce_macsec_tx_rule *tx_rule;
+ struct mlx5_flow_destination dest = {};
+ struct mlx5_flow_act flow_act = {};
+ struct mlx5_flow_handle *new_rule;
+ struct mlx5_flow_spec *spec;
+ int err = 0;
+
+ spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+
+ tx_rule = kzalloc(sizeof(*tx_rule), GFP_KERNEL);
+ if (!tx_rule) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ set_ipaddr_spec(addr, spec, false);
+
+ MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
+ MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_A);
+ MLX5_SET(set_action_in, action, data, macsec_fs_set_tx_fs_id(fs_id));
+ MLX5_SET(set_action_in, action, offset, 0);
+ MLX5_SET(set_action_in, action, length, 32);
+
+ modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_MACSEC,
+ 1, action);
+ if (IS_ERR(modify_hdr)) {
+ err = PTR_ERR(modify_hdr);
+ mlx5_core_err(mdev, "Fail to alloc ROCE MACsec set modify_header_id err=%d\n",
+ err);
+ modify_hdr = NULL;
+ goto modify_hdr_err;
+ }
+ tx_rule->meta_modhdr = modify_hdr;
+
+ flow_act.modify_hdr = modify_hdr;
+ flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
+
+ dest.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
+ dest.ft = tx_fs->tables.ft_crypto.t;
+ new_rule = mlx5_add_flow_rules(tx_fs->ft_rdma_tx, spec, &flow_act, &dest, 1);
+ if (IS_ERR(new_rule)) {
+ err = PTR_ERR(new_rule);
+ mlx5_core_err(mdev, "Failed to add ROCE TX rule, err=%d\n", err);
+ goto rule_err;
+ }
+ tx_rule->rule = new_rule;
+ tx_rule->gid_idx = gid_idx;
+ tx_rule->fs_id = fs_id;
+ list_add_tail(&tx_rule->entry, tx_rules_list);
+
+ goto out;
+
+rule_err:
+ mlx5_modify_header_dealloc(mdev, tx_rule->meta_modhdr);
+modify_hdr_err:
+ kfree(tx_rule);
+out:
+ kvfree(spec);
+ return err;
+}
+
+void mlx5_macsec_del_roce_rule(u16 gid_idx, struct mlx5_macsec_fs *macsec_fs,
+ struct list_head *tx_rules_list, struct list_head *rx_rules_list)
+{
+ struct mlx5_roce_macsec_rx_rule *rx_rule, *next_rx;
+ struct mlx5_roce_macsec_tx_rule *tx_rule, *next_tx;
+
+ list_for_each_entry_safe(tx_rule, next_tx, tx_rules_list, entry) {
+ if (tx_rule->gid_idx == gid_idx)
+ macsec_fs_del_roce_rule_tx(macsec_fs->mdev, tx_rule);
+ }
+
+ list_for_each_entry_safe(rx_rule, next_rx, rx_rules_list, entry) {
+ if (rx_rule->gid_idx == gid_idx)
+ macsec_fs_del_roce_rule_rx(rx_rule);
+ }
+}
+EXPORT_SYMBOL_GPL(mlx5_macsec_del_roce_rule);
+
+int mlx5_macsec_add_roce_rule(void *macdev, const struct sockaddr *addr, u16 gid_idx,
+ struct list_head *tx_rules_list, struct list_head *rx_rules_list,
+ struct mlx5_macsec_fs *macsec_fs)
+{
+ struct mlx5_macsec_device *iter, *macsec_device = NULL;
+ struct mlx5_core_dev *mdev = macsec_fs->mdev;
+ struct mlx5_fs_id *fs_id_iter;
+ unsigned long index = 0;
+ int err;
+
+ list_for_each_entry(iter, &macsec_fs->macsec_devices_list, macsec_devices_list_entry) {
+ if (iter->macdev == macdev) {
+ macsec_device = iter;
+ break;
+ }
+ }
+
+ if (!macsec_device)
+ return 0;
+
+ xa_for_each(&macsec_device->tx_id_xa, index, fs_id_iter) {
+ err = mlx5_macsec_fs_add_roce_rule_tx(macsec_fs, fs_id_iter->id, gid_idx, addr,
+ tx_rules_list);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to add roce TX rule\n");
+ goto out;
+ }
+ }
+
+ index = 0;
+ xa_for_each(&macsec_device->rx_id_xa, index, fs_id_iter) {
+ err = mlx5_macsec_fs_add_roce_rule_rx(macsec_fs, fs_id_iter->id, gid_idx, addr,
+ rx_rules_list);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to add roce TX rule\n");
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ mlx5_macsec_del_roce_rule(gid_idx, macsec_fs, tx_rules_list, rx_rules_list);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_macsec_add_roce_rule);
+
+void mlx5_macsec_add_roce_sa_rules(u32 fs_id, const struct sockaddr *addr, u16 gid_idx,
+ struct list_head *tx_rules_list,
+ struct list_head *rx_rules_list,
+ struct mlx5_macsec_fs *macsec_fs, bool is_tx)
+{
+ (is_tx) ?
+ mlx5_macsec_fs_add_roce_rule_tx(macsec_fs, fs_id, gid_idx, addr,
+ tx_rules_list) :
+ mlx5_macsec_fs_add_roce_rule_rx(macsec_fs, fs_id, gid_idx, addr,
+ rx_rules_list);
+}
+EXPORT_SYMBOL_GPL(mlx5_macsec_add_roce_sa_rules);
+
+void mlx5_macsec_del_roce_sa_rules(u32 fs_id, struct mlx5_macsec_fs *macsec_fs,
+ struct list_head *tx_rules_list,
+ struct list_head *rx_rules_list, bool is_tx)
+{
+ (is_tx) ?
+ macsec_fs_del_roce_rules_tx(macsec_fs, fs_id, tx_rules_list) :
+ macsec_fs_del_roce_rules_rx(macsec_fs, fs_id, rx_rules_list);
+}
+EXPORT_SYMBOL_GPL(mlx5_macsec_del_roce_sa_rules);
+
+void mlx5_macsec_fs_cleanup(struct mlx5_macsec_fs *macsec_fs)
+{
+ macsec_fs_rx_cleanup(macsec_fs);
+ macsec_fs_tx_cleanup(macsec_fs);
+ rhashtable_destroy(&macsec_fs->fs_id_hash);
+ rhashtable_destroy(&macsec_fs->sci_hash);
+ kfree(macsec_fs);
+}
+
+struct mlx5_macsec_fs *
+mlx5_macsec_fs_init(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_macsec_fs *macsec_fs;
+ int err;
+
+ macsec_fs = kzalloc(sizeof(*macsec_fs), GFP_KERNEL);
+ if (!macsec_fs)
+ return NULL;
+
+ macsec_fs->mdev = mdev;
+
+ err = rhashtable_init(&macsec_fs->sci_hash, &rhash_sci);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to init SCI hash table, err=%d\n",
+ err);
+ goto err_hash;
+ }
+
+ err = rhashtable_init(&macsec_fs->fs_id_hash, &rhash_fs_id);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to init FS_ID hash table, err=%d\n",
+ err);
+ goto sci_hash_cleanup;
+ }
+
+ err = macsec_fs_tx_init(macsec_fs);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to init tx_fs, err=%d\n", err);
+ goto fs_id_hash_cleanup;
+ }
+
+ err = macsec_fs_rx_init(macsec_fs);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to init tx_fs, err=%d\n", err);
+ goto tx_cleanup;
+ }
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&mdev->macsec_nh);
+
+ return macsec_fs;
+
+tx_cleanup:
+ macsec_fs_tx_cleanup(macsec_fs);
+fs_id_hash_cleanup:
+ rhashtable_destroy(&macsec_fs->fs_id_hash);
+sci_hash_cleanup:
+ rhashtable_destroy(&macsec_fs->sci_hash);
+err_hash:
+ kfree(macsec_fs);
+ return NULL;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h
new file mode 100644
index 000000000000..34b80c3ef6a5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_MACSEC_STEERING_H__
+#define __MLX5_MACSEC_STEERING_H__
+
+#ifdef CONFIG_MLX5_MACSEC
+
+/* Bit31 - 30: MACsec marker, Bit15-0: MACsec id */
+#define MLX5_MACEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */
+#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACEC_RX_FS_ID_MAX
+#define MLX5_MACSEC_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x1)
+#define MLX5_MACSEC_RX_METADAT_HANDLE(metadata) ((metadata) & MLX5_MACSEC_RX_FS_ID_MASK)
+
+#define MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES 16
+
+struct mlx5_macsec_fs;
+union mlx5_macsec_rule;
+
+struct mlx5_macsec_rule_attrs {
+ sci_t sci;
+ u32 macsec_obj_id;
+ u8 assoc_num;
+ int action;
+};
+
+struct mlx5_macsec_stats {
+ u64 macsec_rx_pkts;
+ u64 macsec_rx_bytes;
+ u64 macsec_rx_pkts_drop;
+ u64 macsec_rx_bytes_drop;
+ u64 macsec_tx_pkts;
+ u64 macsec_tx_bytes;
+ u64 macsec_tx_pkts_drop;
+ u64 macsec_tx_bytes_drop;
+};
+
+enum mlx5_macsec_action {
+ MLX5_ACCEL_MACSEC_ACTION_ENCRYPT,
+ MLX5_ACCEL_MACSEC_ACTION_DECRYPT,
+};
+
+void mlx5_macsec_fs_cleanup(struct mlx5_macsec_fs *macsec_fs);
+
+struct mlx5_macsec_fs *
+mlx5_macsec_fs_init(struct mlx5_core_dev *mdev);
+
+union mlx5_macsec_rule *
+mlx5_macsec_fs_add_rule(struct mlx5_macsec_fs *macsec_fs,
+ const struct macsec_context *ctx,
+ struct mlx5_macsec_rule_attrs *attrs,
+ u32 *sa_fs_id);
+
+void mlx5_macsec_fs_del_rule(struct mlx5_macsec_fs *macsec_fs,
+ union mlx5_macsec_rule *macsec_rule,
+ int action, void *macdev, u32 sa_fs_id);
+
+void mlx5_macsec_fs_get_stats_fill(struct mlx5_macsec_fs *macsec_fs, void *macsec_stats);
+struct mlx5_macsec_stats *mlx5_macsec_fs_get_stats(struct mlx5_macsec_fs *macsec_fs);
+u32 mlx5_macsec_fs_get_fs_id_from_hashtable(struct mlx5_macsec_fs *macsec_fs, sci_t *sci);
+
+#endif
+
+#endif /* __MLX5_MACSEC_STEERING_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 72ae560a1c68..15561965d2af 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -49,7 +49,6 @@
#include <linux/version.h>
#include <net/devlink.h>
#include "mlx5_core.h"
-#include "thermal.h"
#include "lib/eq.h"
#include "fs_core.h"
#include "lib/mpfs.h"
@@ -73,6 +72,7 @@
#include "sf/dev/dev.h"
#include "sf/sf.h"
#include "mlx5_irq.h"
+#include "hwmon.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox 5th generation network adapters (ConnectX series) core driver");
@@ -361,9 +361,8 @@ void mlx5_core_uplink_netdev_event_replay(struct mlx5_core_dev *dev)
}
EXPORT_SYMBOL(mlx5_core_uplink_netdev_event_replay);
-static int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev,
- enum mlx5_cap_type cap_type,
- enum mlx5_cap_mode cap_mode)
+int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type,
+ enum mlx5_cap_mode cap_mode)
{
u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)];
int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
@@ -951,10 +950,10 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
{
int err;
- dev->priv.devcom = mlx5_devcom_register_device(dev);
- if (IS_ERR(dev->priv.devcom))
- mlx5_core_err(dev, "failed to register with devcom (0x%p)\n",
- dev->priv.devcom);
+ dev->priv.devc = mlx5_devcom_register_device(dev);
+ if (IS_ERR(dev->priv.devc))
+ mlx5_core_warn(dev, "failed to register devcom device %ld\n",
+ PTR_ERR(dev->priv.devc));
err = mlx5_query_board_id(dev);
if (err) {
@@ -1089,7 +1088,7 @@ err_eq_cleanup:
err_irq_cleanup:
mlx5_irq_table_cleanup(dev);
err_devcom:
- mlx5_devcom_unregister_device(dev->priv.devcom);
+ mlx5_devcom_unregister_device(dev->priv.devc);
return err;
}
@@ -1118,7 +1117,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
mlx5_events_cleanup(dev);
mlx5_eq_table_cleanup(dev);
mlx5_irq_table_cleanup(dev);
- mlx5_devcom_unregister_device(dev->priv.devcom);
+ mlx5_devcom_unregister_device(dev->priv.devc);
}
static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeout)
@@ -1142,7 +1141,7 @@ static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeou
return err;
}
- err = mlx5_cmd_init(dev);
+ err = mlx5_cmd_enable(dev);
if (err) {
mlx5_core_err(dev, "Failed initializing command interface, aborting\n");
return err;
@@ -1196,7 +1195,7 @@ stop_health_poll:
mlx5_stop_health_poll(dev, boot);
err_cmd_cleanup:
mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN);
- mlx5_cmd_cleanup(dev);
+ mlx5_cmd_disable(dev);
return err;
}
@@ -1207,7 +1206,7 @@ static void mlx5_function_disable(struct mlx5_core_dev *dev, bool boot)
mlx5_core_disable_hca(dev, 0);
mlx5_stop_health_poll(dev, boot);
mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN);
- mlx5_cmd_cleanup(dev);
+ mlx5_cmd_disable(dev);
}
static int mlx5_function_open(struct mlx5_core_dev *dev)
@@ -1620,21 +1619,24 @@ static int mlx5_query_hca_caps_light(struct mlx5_core_dev *dev)
return err;
if (MLX5_CAP_GEN(dev, eth_net_offloads)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_ETHERNET_OFFLOADS,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN(dev, nic_flow_table) ||
MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_FLOW_TABLE,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
if (MLX5_CAP_GEN_64(dev, general_obj_types) &
MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) {
- err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION);
+ err = mlx5_core_get_caps_mode(dev, MLX5_CAP_VDPA_EMULATION,
+ HCA_CAP_OPMOD_GET_CUR);
if (err)
return err;
}
@@ -1714,7 +1716,6 @@ static const int types[] = {
MLX5_CAP_FLOW_TABLE,
MLX5_CAP_ESWITCH_FLOW_TABLE,
MLX5_CAP_ESWITCH,
- MLX5_CAP_VECTOR_CALC,
MLX5_CAP_QOS,
MLX5_CAP_DEBUG,
MLX5_CAP_DEV_MEM,
@@ -1723,7 +1724,6 @@ static const int types[] = {
MLX5_CAP_VDPA_EMULATION,
MLX5_CAP_IPSEC,
MLX5_CAP_PORT_SELECTION,
- MLX5_CAP_DEV_SHAMPO,
MLX5_CAP_MACSEC,
MLX5_CAP_ADV_VIRTUALIZATION,
MLX5_CAP_CRYPTO,
@@ -1797,6 +1797,12 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
debugfs_create_file("vhca_id", 0400, priv->dbg.dbg_root, dev, &vhca_id_fops);
INIT_LIST_HEAD(&priv->traps);
+ err = mlx5_cmd_init(dev);
+ if (err) {
+ mlx5_core_err(dev, "Failed initializing cmdif SW structs, aborting\n");
+ goto err_cmd_init;
+ }
+
err = mlx5_tout_init(dev);
if (err) {
mlx5_core_err(dev, "Failed initializing timeouts, aborting\n");
@@ -1842,6 +1848,8 @@ err_pagealloc_init:
err_health_init:
mlx5_tout_cleanup(dev);
err_timeout_init:
+ mlx5_cmd_cleanup(dev);
+err_cmd_init:
debugfs_remove(dev->priv.dbg.dbg_root);
mutex_destroy(&priv->pgdir_mutex);
mutex_destroy(&priv->alloc_mutex);
@@ -1864,6 +1872,7 @@ void mlx5_mdev_uninit(struct mlx5_core_dev *dev)
mlx5_pagealloc_cleanup(dev);
mlx5_health_cleanup(dev);
mlx5_tout_cleanup(dev);
+ mlx5_cmd_cleanup(dev);
debugfs_remove_recursive(dev->priv.dbg.dbg_root);
mutex_destroy(&priv->pgdir_mutex);
mutex_destroy(&priv->alloc_mutex);
@@ -1921,9 +1930,9 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
dev_err(&pdev->dev, "mlx5_crdump_enable failed with error code %d\n", err);
- err = mlx5_thermal_init(dev);
+ err = mlx5_hwmon_dev_register(dev);
if (err)
- dev_err(&pdev->dev, "mlx5_thermal_init failed with error code %d\n", err);
+ mlx5_core_err(dev, "mlx5_hwmon_dev_register failed with error code %d\n", err);
pci_save_state(pdev);
devlink_register(devlink);
@@ -1955,7 +1964,7 @@ static void remove_one(struct pci_dev *pdev)
mlx5_drain_health_wq(dev);
devlink_unregister(devlink);
mlx5_sriov_disable(pdev, false);
- mlx5_thermal_uninit(dev);
+ mlx5_hwmon_dev_unregister(dev);
mlx5_crdump_disable(dev);
mlx5_uninit_one(dev);
mlx5_pci_close(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 682d3dc00dd1..124352459c23 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -174,10 +174,16 @@ static inline int mlx5_flexible_inlen(struct mlx5_core_dev *dev, size_t fixed,
#define MLX5_FLEXIBLE_INLEN(dev, fixed, item_size, num_items) \
mlx5_flexible_inlen(dev, fixed, item_size, num_items, __func__, __LINE__)
+int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type);
+int mlx5_core_get_caps_mode(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type,
+ enum mlx5_cap_mode cap_mode);
int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
int mlx5_query_board_id(struct mlx5_core_dev *dev);
+int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num);
int mlx5_cmd_init(struct mlx5_core_dev *dev);
void mlx5_cmd_cleanup(struct mlx5_core_dev *dev);
+int mlx5_cmd_enable(struct mlx5_core_dev *dev);
+void mlx5_cmd_disable(struct mlx5_core_dev *dev);
void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
enum mlx5_cmdif_state cmdif_state);
int mlx5_cmd_init_hca(struct mlx5_core_dev *dev, uint32_t *sw_owner_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
index aa403a5ea34e..1088114e905d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_irq.h
@@ -29,9 +29,9 @@ void mlx5_ctrl_irq_release(struct mlx5_irq *ctrl_irq);
struct mlx5_irq *mlx5_irq_request(struct mlx5_core_dev *dev, u16 vecidx,
struct irq_affinity_desc *af_desc,
struct cpu_rmap **rmap);
-int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs,
- struct mlx5_irq **irqs, struct cpu_rmap **rmap);
-void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs);
+struct mlx5_irq *mlx5_irq_request_vector(struct mlx5_core_dev *dev, u16 cpu,
+ u16 vecidx, struct cpu_rmap **rmap);
+void mlx5_irq_release_vector(struct mlx5_irq *irq);
int mlx5_irq_attach_nb(struct mlx5_irq *irq, struct notifier_block *nb);
int mlx5_irq_detach_nb(struct mlx5_irq *irq, struct notifier_block *nb);
struct cpumask *mlx5_irq_get_affinity_mask(struct mlx5_irq *irq);
@@ -39,17 +39,17 @@ int mlx5_irq_get_index(struct mlx5_irq *irq);
struct mlx5_irq_pool;
#ifdef CONFIG_MLX5_SF
-int mlx5_irq_affinity_irqs_request_auto(struct mlx5_core_dev *dev, int nirqs,
- struct mlx5_irq **irqs);
+struct mlx5_irq *mlx5_irq_affinity_irq_request_auto(struct mlx5_core_dev *dev,
+ struct cpumask *used_cpus, u16 vecidx);
struct mlx5_irq *mlx5_irq_affinity_request(struct mlx5_irq_pool *pool,
struct irq_affinity_desc *af_desc);
-void mlx5_irq_affinity_irqs_release(struct mlx5_core_dev *dev, struct mlx5_irq **irqs,
- int num_irqs);
+void mlx5_irq_affinity_irq_release(struct mlx5_core_dev *dev, struct mlx5_irq *irq);
#else
-static inline int mlx5_irq_affinity_irqs_request_auto(struct mlx5_core_dev *dev, int nirqs,
- struct mlx5_irq **irqs)
+static inline
+struct mlx5_irq *mlx5_irq_affinity_irq_request_auto(struct mlx5_core_dev *dev,
+ struct cpumask *used_cpus, u16 vecidx)
{
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
}
static inline struct mlx5_irq *
@@ -58,7 +58,9 @@ mlx5_irq_affinity_request(struct mlx5_irq_pool *pool, struct irq_affinity_desc *
return ERR_PTR(-EOPNOTSUPP);
}
-static inline void mlx5_irq_affinity_irqs_release(struct mlx5_core_dev *dev,
- struct mlx5_irq **irqs, int num_irqs) {}
+static inline
+void mlx5_irq_affinity_irq_release(struct mlx5_core_dev *dev, struct mlx5_irq *irq)
+{
+}
#endif
#endif /* __MLX5_IRQ_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
index cba2a4afb5fd..653648216730 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -259,8 +259,11 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i,
int err;
irq = kzalloc(sizeof(*irq), GFP_KERNEL);
- if (!irq)
+ if (!irq || !zalloc_cpumask_var(&irq->mask, GFP_KERNEL)) {
+ kfree(irq);
return ERR_PTR(-ENOMEM);
+ }
+
if (!i || !pci_msix_can_alloc_dyn(dev->pdev)) {
/* The vector at index 0 is always statically allocated. If
* dynamic irq is not supported all vectors are statically
@@ -297,11 +300,7 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i,
mlx5_core_err(dev, "Failed to request irq. err = %d\n", err);
goto err_req_irq;
}
- if (!zalloc_cpumask_var(&irq->mask, GFP_KERNEL)) {
- mlx5_core_warn(dev, "zalloc_cpumask_var failed\n");
- err = -ENOMEM;
- goto err_cpumask;
- }
+
if (af_desc) {
cpumask_copy(irq->mask, &af_desc->mask);
irq_set_affinity_and_hint(irq->map.virq, irq->mask);
@@ -319,8 +318,6 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i,
err_xa:
if (af_desc)
irq_update_affinity_hint(irq->map.virq, NULL);
- free_cpumask_var(irq->mask);
-err_cpumask:
free_irq(irq->map.virq, &irq->nh);
err_req_irq:
#ifdef CONFIG_RFS_ACCEL
@@ -333,6 +330,7 @@ err_irq_rmap:
if (i && pci_msix_can_alloc_dyn(dev->pdev))
pci_msix_free_irq(dev->pdev, irq->map);
err_alloc_irq:
+ free_cpumask_var(irq->mask);
kfree(irq);
return ERR_PTR(err);
}
@@ -432,19 +430,10 @@ static struct mlx5_irq_pool *ctrl_irq_pool_get(struct mlx5_core_dev *dev)
return pool ? pool : irq_table->pcif_pool;
}
-/**
- * mlx5_irqs_release - release one or more IRQs back to the system.
- * @irqs: IRQs to be released.
- * @nirqs: number of IRQs to be released.
- */
-static void mlx5_irqs_release(struct mlx5_irq **irqs, int nirqs)
+static void _mlx5_irq_release(struct mlx5_irq *irq)
{
- int i;
-
- for (i = 0; i < nirqs; i++) {
- synchronize_irq(irqs[i]->map.virq);
- mlx5_irq_put(irqs[i]);
- }
+ synchronize_irq(irq->map.virq);
+ mlx5_irq_put(irq);
}
/**
@@ -453,7 +442,7 @@ static void mlx5_irqs_release(struct mlx5_irq **irqs, int nirqs)
*/
void mlx5_ctrl_irq_release(struct mlx5_irq *ctrl_irq)
{
- mlx5_irqs_release(&ctrl_irq, 1);
+ _mlx5_irq_release(ctrl_irq);
}
/**
@@ -569,53 +558,42 @@ void mlx5_msix_free(struct mlx5_core_dev *dev, struct msi_map map)
EXPORT_SYMBOL(mlx5_msix_free);
/**
- * mlx5_irqs_release_vectors - release one or more IRQs back to the system.
- * @irqs: IRQs to be released.
- * @nirqs: number of IRQs to be released.
+ * mlx5_irq_release_vector - release one IRQ back to the system.
+ * @irq: the irq to release.
*/
-void mlx5_irqs_release_vectors(struct mlx5_irq **irqs, int nirqs)
+void mlx5_irq_release_vector(struct mlx5_irq *irq)
{
- mlx5_irqs_release(irqs, nirqs);
+ _mlx5_irq_release(irq);
}
/**
- * mlx5_irqs_request_vectors - request one or more IRQs for mlx5 device.
- * @dev: mlx5 device that is requesting the IRQs.
- * @cpus: CPUs array for binding the IRQs
- * @nirqs: number of IRQs to request.
- * @irqs: an output array of IRQs pointers.
+ * mlx5_irq_request_vector - request one IRQ for mlx5 device.
+ * @dev: mlx5 device that is requesting the IRQ.
+ * @cpu: CPU to bind the IRQ to.
+ * @vecidx: vector index to request an IRQ for.
* @rmap: pointer to reverse map pointer for completion interrupts
*
* Each IRQ is bound to at most 1 CPU.
- * This function is requests nirqs IRQs, starting from @vecidx.
+ * This function is requests one IRQ, for the given @vecidx.
*
- * This function returns the number of IRQs requested, (which might be smaller than
- * @nirqs), if successful, or a negative error code in case of an error.
+ * This function returns a pointer to the irq on success, or an error pointer
+ * in case of an error.
*/
-int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs,
- struct mlx5_irq **irqs, struct cpu_rmap **rmap)
+struct mlx5_irq *mlx5_irq_request_vector(struct mlx5_core_dev *dev, u16 cpu,
+ u16 vecidx, struct cpu_rmap **rmap)
{
struct mlx5_irq_table *table = mlx5_irq_table_get(dev);
struct mlx5_irq_pool *pool = table->pcif_pool;
struct irq_affinity_desc af_desc;
- struct mlx5_irq *irq;
int offset = 1;
- int i;
if (!pool->xa_num_irqs.max)
offset = 0;
af_desc.is_managed = false;
- for (i = 0; i < nirqs; i++) {
- cpumask_clear(&af_desc.mask);
- cpumask_set_cpu(cpus[i], &af_desc.mask);
- irq = mlx5_irq_request(dev, i + offset, &af_desc, rmap);
- if (IS_ERR(irq))
- break;
- irqs[i] = irq;
- }
-
- return i ? i : PTR_ERR(irq);
+ cpumask_clear(&af_desc.mask);
+ cpumask_set_cpu(cpu, &af_desc.mask);
+ return mlx5_irq_request(dev, vecidx + offset, &af_desc, rmap);
}
static struct mlx5_irq_pool *
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 0daeb4b72cca..be70d1f23a5d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -271,7 +271,7 @@ void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
}
EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
-static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
+int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
{
u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
index 8e2abbab05f0..05e148db9889 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/dev.c
@@ -129,7 +129,7 @@ static void mlx5_sf_dev_add(struct mlx5_core_dev *dev, u16 sf_index, u16 fn_id,
err = auxiliary_device_add(&sf_dev->adev);
if (err) {
- put_device(&sf_dev->adev.dev);
+ auxiliary_device_uninit(&sf_dev->adev);
goto add_err;
}
@@ -167,7 +167,7 @@ mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_
if (!max_functions)
return 0;
- base_id = MLX5_CAP_GEN(table->dev, sf_base_id);
+ base_id = mlx5_sf_start_function_id(table->dev);
if (event->function_id < base_id || event->function_id >= (base_id + max_functions))
return 0;
@@ -185,7 +185,7 @@ mlx5_sf_dev_state_change_handler(struct notifier_block *nb, unsigned long event_
mlx5_sf_dev_del(table->dev, sf_dev, sf_index);
else
mlx5_core_err(table->dev,
- "SF DEV: teardown state for invalid dev index=%d fn_id=0x%x\n",
+ "SF DEV: teardown state for invalid dev index=%d sfnum=0x%x\n",
sf_index, event->sw_function_id);
break;
case MLX5_VHCA_STATE_ACTIVE:
@@ -209,7 +209,7 @@ static int mlx5_sf_dev_vhca_arm_all(struct mlx5_sf_dev_table *table)
int i;
max_functions = mlx5_sf_max_functions(dev);
- function_id = MLX5_CAP_GEN(dev, sf_base_id);
+ function_id = mlx5_sf_start_function_id(dev);
/* Arm the vhca context as the vhca event notifier */
for (i = 0; i < max_functions; i++) {
err = mlx5_vhca_event_arm(dev, function_id);
@@ -234,7 +234,7 @@ static void mlx5_sf_dev_add_active_work(struct work_struct *work)
int i;
max_functions = mlx5_sf_max_functions(dev);
- function_id = MLX5_CAP_GEN(dev, sf_base_id);
+ function_id = mlx5_sf_start_function_id(dev);
for (i = 0; i < max_functions; i++, function_id++) {
if (table->stop_active_wq)
return;
@@ -299,7 +299,7 @@ void mlx5_sf_dev_table_create(struct mlx5_core_dev *dev)
unsigned int max_sfs;
int err;
- if (!mlx5_sf_dev_supported(dev) || !mlx5_vhca_event_supported(dev))
+ if (!mlx5_sf_dev_supported(dev))
return;
table = kzalloc(sizeof(*table), GFP_KERNEL);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
index 6a3fa30b2bf2..e34a8f88c518 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
@@ -12,7 +12,7 @@
#include "diag/sf_tracepoint.h"
struct mlx5_sf {
- struct devlink_port dl_port;
+ struct mlx5_devlink_port dl_port;
unsigned int port_index;
u32 controller;
u16 id;
@@ -292,11 +292,11 @@ static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table,
if (IS_ERR(sf))
return PTR_ERR(sf);
- err = mlx5_esw_offloads_sf_vport_enable(esw, &sf->dl_port, sf->hw_fn_id,
- new_attr->controller, new_attr->sfnum);
+ err = mlx5_eswitch_load_sf_vport(esw, sf->hw_fn_id, MLX5_VPORT_UC_ADDR_CHANGE,
+ &sf->dl_port, new_attr->controller, new_attr->sfnum);
if (err)
goto esw_err;
- *dl_port = &sf->dl_port;
+ *dl_port = &sf->dl_port.dl_port;
trace_mlx5_sf_add(dev, sf->port_index, sf->controller, sf->hw_fn_id, new_attr->sfnum);
return 0;
@@ -400,7 +400,7 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink,
goto sf_err;
}
- mlx5_esw_offloads_sf_vport_disable(esw, sf->hw_fn_id);
+ mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id);
mlx5_sf_id_erase(table, sf);
mutex_lock(&table->sf_state_lock);
@@ -472,7 +472,7 @@ static void mlx5_sf_deactivate_all(struct mlx5_sf_table *table)
* arrive. It is safe to destroy all user created SFs.
*/
xa_for_each(&table->port_indices, index, sf) {
- mlx5_esw_offloads_sf_vport_disable(esw, sf->hw_fn_id);
+ mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id);
mlx5_sf_id_erase(table, sf);
mlx5_sf_dealloc(table, sf);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
index 17aa348989cb..1f613320fe07 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c
@@ -9,6 +9,7 @@
#include "mlx5_core.h"
#include "eswitch.h"
#include "diag/sf_tracepoint.h"
+#include "devlink.h"
struct mlx5_sf_hw {
u32 usr_sfnum;
@@ -243,31 +244,61 @@ static void mlx5_sf_hw_table_hwc_cleanup(struct mlx5_sf_hwc_table *hwc)
kfree(hwc->sfs);
}
+static void mlx5_sf_hw_table_res_unregister(struct mlx5_core_dev *dev)
+{
+ devl_resources_unregister(priv_to_devlink(dev));
+}
+
+static int mlx5_sf_hw_table_res_register(struct mlx5_core_dev *dev, u16 max_fn,
+ u16 max_ext_fn)
+{
+ struct devlink_resource_size_params size_params;
+ struct devlink *devlink = priv_to_devlink(dev);
+ int err;
+
+ devlink_resource_size_params_init(&size_params, max_fn, max_fn, 1,
+ DEVLINK_RESOURCE_UNIT_ENTRY);
+ err = devl_resource_register(devlink, "max_local_SFs", max_fn, MLX5_DL_RES_MAX_LOCAL_SFS,
+ DEVLINK_RESOURCE_ID_PARENT_TOP, &size_params);
+ if (err)
+ return err;
+
+ devlink_resource_size_params_init(&size_params, max_ext_fn, max_ext_fn, 1,
+ DEVLINK_RESOURCE_UNIT_ENTRY);
+ return devl_resource_register(devlink, "max_external_SFs", max_ext_fn,
+ MLX5_DL_RES_MAX_EXTERNAL_SFS, DEVLINK_RESOURCE_ID_PARENT_TOP,
+ &size_params);
+}
+
int mlx5_sf_hw_table_init(struct mlx5_core_dev *dev)
{
struct mlx5_sf_hw_table *table;
u16 max_ext_fn = 0;
u16 ext_base_id = 0;
- u16 max_fn = 0;
u16 base_id;
+ u16 max_fn;
int err;
if (!mlx5_vhca_event_supported(dev))
return 0;
- if (mlx5_sf_supported(dev))
- max_fn = mlx5_sf_max_functions(dev);
+ max_fn = mlx5_sf_max_functions(dev);
err = mlx5_esw_sf_max_hpf_functions(dev, &max_ext_fn, &ext_base_id);
if (err)
return err;
+ if (mlx5_sf_hw_table_res_register(dev, max_fn, max_ext_fn))
+ mlx5_core_dbg(dev, "failed to register max SFs resources");
+
if (!max_fn && !max_ext_fn)
return 0;
table = kzalloc(sizeof(*table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
+ if (!table) {
+ err = -ENOMEM;
+ goto alloc_err;
+ }
mutex_init(&table->table_lock);
table->dev = dev;
@@ -291,6 +322,8 @@ ext_err:
table_err:
mutex_destroy(&table->table_lock);
kfree(table);
+alloc_err:
+ mlx5_sf_hw_table_res_unregister(dev);
return err;
}
@@ -299,12 +332,14 @@ void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev)
struct mlx5_sf_hw_table *table = dev->priv.sf_hw_table;
if (!table)
- return;
+ goto res_unregister;
- mutex_destroy(&table->table_lock);
mlx5_sf_hw_table_hwc_cleanup(&table->hwc[MLX5_SF_HWC_EXTERNAL]);
mlx5_sf_hw_table_hwc_cleanup(&table->hwc[MLX5_SF_HWC_LOCAL]);
+ mutex_destroy(&table->table_lock);
kfree(table);
+res_unregister:
+ mlx5_sf_hw_table_res_unregister(dev);
}
static int mlx5_sf_hw_vhca_event(struct notifier_block *nb, unsigned long opcode, void *data)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
index 54bb0866ed72..5b83da08692d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
@@ -1422,7 +1422,6 @@ dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
case DR_ACTION_TYP_TNL_L3_TO_L2:
{
u8 *hw_actions;
- int ret;
hw_actions = kzalloc(DR_ACTION_CACHE_LINE_SIZE, GFP_KERNEL);
if (!hw_actions)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
index 4a5ae86e2b62..4e8527a724f5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
@@ -52,6 +52,7 @@ struct dr_qp_init_attr {
u32 cqn;
u32 pdn;
u32 max_send_wr;
+ u32 max_send_sge;
struct mlx5_uars_page *uar;
u8 isolate_vl_tc:1;
};
@@ -246,6 +247,37 @@ static int dr_poll_cq(struct mlx5dr_cq *dr_cq, int ne)
return err == CQ_POLL_ERR ? err : npolled;
}
+static int dr_qp_get_args_update_send_wqe_size(struct dr_qp_init_attr *attr)
+{
+ return roundup_pow_of_two(sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_flow_update_ctrl_seg) +
+ sizeof(struct mlx5_wqe_header_modify_argument_update_seg));
+}
+
+/* We calculate for specific RC QP with the required functionality */
+static int dr_qp_calc_rc_send_wqe(struct dr_qp_init_attr *attr)
+{
+ int update_arg_size;
+ int inl_size = 0;
+ int tot_size;
+ int size;
+
+ update_arg_size = dr_qp_get_args_update_send_wqe_size(attr);
+
+ size = sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg);
+ inl_size = size + ALIGN(sizeof(struct mlx5_wqe_inline_seg) +
+ DR_STE_SIZE, 16);
+
+ size += attr->max_send_sge * sizeof(struct mlx5_wqe_data_seg);
+
+ size = max(size, update_arg_size);
+
+ tot_size = max(size, inl_size);
+
+ return ALIGN(tot_size, MLX5_SEND_WQE_BB);
+}
+
static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev,
struct dr_qp_init_attr *attr)
{
@@ -253,6 +285,7 @@ static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev,
u32 temp_qpc[MLX5_ST_SZ_DW(qpc)] = {};
struct mlx5_wq_param wqp;
struct mlx5dr_qp *dr_qp;
+ int wqe_size;
int inlen;
void *qpc;
void *in;
@@ -332,6 +365,15 @@ static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev,
if (err)
goto err_in;
dr_qp->uar = attr->uar;
+ wqe_size = dr_qp_calc_rc_send_wqe(attr);
+ dr_qp->max_inline_data = min(wqe_size -
+ (sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_inline_seg)),
+ (2 * MLX5_SEND_WQE_BB -
+ (sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_inline_seg))));
return dr_qp;
@@ -395,8 +437,48 @@ dr_rdma_handle_flow_access_arg_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl,
MLX5_SEND_WQE_DS;
}
+static int dr_set_data_inl_seg(struct mlx5dr_qp *dr_qp,
+ struct dr_data_seg *data_seg, void *wqe)
+{
+ int inline_header_size = sizeof(struct mlx5_wqe_ctrl_seg) +
+ sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_inline_seg);
+ struct mlx5_wqe_inline_seg *seg;
+ int left_space;
+ int inl = 0;
+ void *addr;
+ int len;
+ int idx;
+
+ seg = wqe;
+ wqe += sizeof(*seg);
+ addr = (void *)(unsigned long)(data_seg->addr);
+ len = data_seg->length;
+ inl += len;
+ left_space = MLX5_SEND_WQE_BB - inline_header_size;
+
+ if (likely(len > left_space)) {
+ memcpy(wqe, addr, left_space);
+ len -= left_space;
+ addr += left_space;
+ idx = (dr_qp->sq.pc + 1) & (dr_qp->sq.wqe_cnt - 1);
+ wqe = mlx5_wq_cyc_get_wqe(&dr_qp->wq.sq, idx);
+ }
+
+ memcpy(wqe, addr, len);
+
+ if (likely(inl)) {
+ seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
+ return DIV_ROUND_UP(inl + sizeof(seg->byte_count),
+ MLX5_SEND_WQE_DS);
+ } else {
+ return 0;
+ }
+}
+
static void
-dr_rdma_handle_icm_write_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl,
+dr_rdma_handle_icm_write_segments(struct mlx5dr_qp *dr_qp,
+ struct mlx5_wqe_ctrl_seg *wq_ctrl,
u64 remote_addr,
u32 rkey,
struct dr_data_seg *data_seg,
@@ -412,15 +494,17 @@ dr_rdma_handle_icm_write_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl,
wq_raddr->reserved = 0;
wq_dseg = (void *)(wq_raddr + 1);
+ /* WQE ctrl segment + WQE remote addr segment */
+ *size = (sizeof(*wq_ctrl) + sizeof(*wq_raddr)) / MLX5_SEND_WQE_DS;
- wq_dseg->byte_count = cpu_to_be32(data_seg->length);
- wq_dseg->lkey = cpu_to_be32(data_seg->lkey);
- wq_dseg->addr = cpu_to_be64(data_seg->addr);
-
- *size = (sizeof(*wq_ctrl) + /* WQE ctrl segment */
- sizeof(*wq_dseg) + /* WQE data segment */
- sizeof(*wq_raddr)) / /* WQE remote addr segment */
- MLX5_SEND_WQE_DS;
+ if (data_seg->send_flags & IB_SEND_INLINE) {
+ *size += dr_set_data_inl_seg(dr_qp, data_seg, wq_dseg);
+ } else {
+ wq_dseg->byte_count = cpu_to_be32(data_seg->length);
+ wq_dseg->lkey = cpu_to_be32(data_seg->lkey);
+ wq_dseg->addr = cpu_to_be64(data_seg->addr);
+ *size += sizeof(*wq_dseg) / MLX5_SEND_WQE_DS; /* WQE data segment */
+ }
}
static void dr_set_ctrl_seg(struct mlx5_wqe_ctrl_seg *wq_ctrl,
@@ -451,7 +535,7 @@ static void dr_rdma_segments(struct mlx5dr_qp *dr_qp, u64 remote_addr,
switch (opcode) {
case MLX5_OPCODE_RDMA_READ:
case MLX5_OPCODE_RDMA_WRITE:
- dr_rdma_handle_icm_write_segments(wq_ctrl, remote_addr,
+ dr_rdma_handle_icm_write_segments(dr_qp, wq_ctrl, remote_addr,
rkey, data_seg, &size);
break;
case MLX5_OPCODE_FLOW_TBL_ACCESS:
@@ -572,7 +656,7 @@ static void dr_fill_write_args_segs(struct mlx5dr_send_ring *send_ring,
if (send_ring->pending_wqe % send_ring->signal_th == 0)
send_info->write.send_flags |= IB_SEND_SIGNALED;
else
- send_info->write.send_flags = 0;
+ send_info->write.send_flags &= ~IB_SEND_SIGNALED;
}
static void dr_fill_write_icm_segs(struct mlx5dr_domain *dmn,
@@ -596,9 +680,13 @@ static void dr_fill_write_icm_segs(struct mlx5dr_domain *dmn,
}
send_ring->pending_wqe++;
+ if (!send_info->write.lkey)
+ send_info->write.send_flags |= IB_SEND_INLINE;
if (send_ring->pending_wqe % send_ring->signal_th == 0)
send_info->write.send_flags |= IB_SEND_SIGNALED;
+ else
+ send_info->write.send_flags &= ~IB_SEND_SIGNALED;
send_ring->pending_wqe++;
send_info->read.length = send_info->write.length;
@@ -608,9 +696,9 @@ static void dr_fill_write_icm_segs(struct mlx5dr_domain *dmn,
send_info->read.lkey = send_ring->sync_mr->mkey;
if (send_ring->pending_wqe % send_ring->signal_th == 0)
- send_info->read.send_flags = IB_SEND_SIGNALED;
+ send_info->read.send_flags |= IB_SEND_SIGNALED;
else
- send_info->read.send_flags = 0;
+ send_info->read.send_flags &= ~IB_SEND_SIGNALED;
}
static void dr_fill_data_segs(struct mlx5dr_domain *dmn,
@@ -1096,8 +1184,8 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
if (!in)
goto err_cqwq;
- vector = raw_smp_processor_id() % mlx5_comp_vectors_count(mdev);
- err = mlx5_vector2eqn(mdev, vector, &eqn);
+ vector = raw_smp_processor_id() % mlx5_comp_vectors_max(mdev);
+ err = mlx5_comp_eqn_get(mdev, vector, &eqn);
if (err) {
kvfree(in);
goto err_cqwq;
@@ -1257,6 +1345,7 @@ int mlx5dr_send_ring_alloc(struct mlx5dr_domain *dmn)
dmn->send_ring->cq->qp = dmn->send_ring->qp;
dmn->info.max_send_wr = QUEUE_SIZE;
+ init_attr.max_send_sge = 1;
dmn->info.max_inline_size = min(dmn->send_ring->qp->max_inline_data,
DR_STE_SIZE);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
index feb307fb3440..14f6df88b1f9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
@@ -336,7 +336,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
if (fte->action.pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_FW) {
err = -EINVAL;
mlx5dr_err(domain, "FW-owned reformat can't be used in SW rule\n");
- goto free_actions;
+ goto free_actions;
}
is_decap = fte->action.pkt_reformat->reformat_type ==
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/thermal.c b/drivers/net/ethernet/mellanox/mlx5/core/thermal.c
deleted file mode 100644
index 52199d39657e..000000000000
--- a/drivers/net/ethernet/mellanox/mlx5/core/thermal.c
+++ /dev/null
@@ -1,114 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
-// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/thermal.h>
-#include <linux/err.h>
-#include <linux/mlx5/driver.h>
-#include "mlx5_core.h"
-#include "thermal.h"
-
-#define MLX5_THERMAL_POLL_INT_MSEC 1000
-#define MLX5_THERMAL_NUM_TRIPS 0
-#define MLX5_THERMAL_ASIC_SENSOR_INDEX 0
-
-/* Bit string indicating the writeablility of trip points if any */
-#define MLX5_THERMAL_TRIP_MASK (BIT(MLX5_THERMAL_NUM_TRIPS) - 1)
-
-struct mlx5_thermal {
- struct mlx5_core_dev *mdev;
- struct thermal_zone_device *tzdev;
-};
-
-static int mlx5_thermal_get_mtmp_temp(struct mlx5_core_dev *mdev, u32 id, int *p_temp)
-{
- u32 mtmp_out[MLX5_ST_SZ_DW(mtmp_reg)] = {};
- u32 mtmp_in[MLX5_ST_SZ_DW(mtmp_reg)] = {};
- int err;
-
- MLX5_SET(mtmp_reg, mtmp_in, sensor_index, id);
-
- err = mlx5_core_access_reg(mdev, mtmp_in, sizeof(mtmp_in),
- mtmp_out, sizeof(mtmp_out),
- MLX5_REG_MTMP, 0, 0);
-
- if (err)
- return err;
-
- *p_temp = MLX5_GET(mtmp_reg, mtmp_out, temperature);
-
- return 0;
-}
-
-static int mlx5_thermal_get_temp(struct thermal_zone_device *tzdev,
- int *p_temp)
-{
- struct mlx5_thermal *thermal = thermal_zone_device_priv(tzdev);
- struct mlx5_core_dev *mdev = thermal->mdev;
- int err;
-
- err = mlx5_thermal_get_mtmp_temp(mdev, MLX5_THERMAL_ASIC_SENSOR_INDEX, p_temp);
-
- if (err)
- return err;
-
- /* The unit of temp returned is in 0.125 C. The thermal
- * framework expects the value in 0.001 C.
- */
- *p_temp *= 125;
-
- return 0;
-}
-
-static struct thermal_zone_device_ops mlx5_thermal_ops = {
- .get_temp = mlx5_thermal_get_temp,
-};
-
-int mlx5_thermal_init(struct mlx5_core_dev *mdev)
-{
- char data[THERMAL_NAME_LENGTH];
- struct mlx5_thermal *thermal;
- int err;
-
- if (!mlx5_core_is_pf(mdev) && !mlx5_core_is_ecpf(mdev))
- return 0;
-
- err = snprintf(data, sizeof(data), "mlx5_%s", dev_name(mdev->device));
- if (err < 0 || err >= sizeof(data)) {
- mlx5_core_err(mdev, "Failed to setup thermal zone name, %d\n", err);
- return -EINVAL;
- }
-
- thermal = kzalloc(sizeof(*thermal), GFP_KERNEL);
- if (!thermal)
- return -ENOMEM;
-
- thermal->mdev = mdev;
- thermal->tzdev = thermal_zone_device_register_with_trips(data,
- NULL,
- MLX5_THERMAL_NUM_TRIPS,
- MLX5_THERMAL_TRIP_MASK,
- thermal,
- &mlx5_thermal_ops,
- NULL, 0, MLX5_THERMAL_POLL_INT_MSEC);
- if (IS_ERR(thermal->tzdev)) {
- err = PTR_ERR(thermal->tzdev);
- mlx5_core_err(mdev, "Failed to register thermal zone device (%s) %d\n", data, err);
- kfree(thermal);
- return err;
- }
-
- mdev->thermal = thermal;
- return 0;
-}
-
-void mlx5_thermal_uninit(struct mlx5_core_dev *mdev)
-{
- if (!mdev->thermal)
- return;
-
- thermal_zone_device_unregister(mdev->thermal->tzdev);
- kfree(mdev->thermal);
-}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/thermal.h b/drivers/net/ethernet/mellanox/mlx5/core/thermal.h
deleted file mode 100644
index 7d752c122192..000000000000
--- a/drivers/net/ethernet/mellanox/mlx5/core/thermal.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
- * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES.
- */
-#ifndef __MLX5_THERMAL_DRIVER_H
-#define __MLX5_THERMAL_DRIVER_H
-
-#if IS_ENABLED(CONFIG_THERMAL)
-int mlx5_thermal_init(struct mlx5_core_dev *mdev);
-void mlx5_thermal_uninit(struct mlx5_core_dev *mdev);
-#else
-static inline int mlx5_thermal_init(struct mlx5_core_dev *mdev)
-{
- mdev->thermal = NULL;
- return 0;
-}
-
-static inline void mlx5_thermal_uninit(struct mlx5_core_dev *mdev) { }
-#endif
-
-#endif /* __MLX5_THERMAL_DRIVER_H */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index a453b9cd9033..bc94e75a7aeb 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -175,9 +175,6 @@ enum mlxbf_gige_res {
int mlxbf_gige_mdio_probe(struct platform_device *pdev,
struct mlxbf_gige *priv);
void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv);
-irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id);
-void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv);
-
void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv,
unsigned int index, u64 dmac);
void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index 3ca9fce759ea..71cad6bb6e62 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -29,7 +29,7 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_nve.o spectrum_nve_vxlan.o \
spectrum_dpipe.o spectrum_trap.o \
spectrum_ethtool.o spectrum_policer.o \
- spectrum_pgt.o
+ spectrum_pgt.o spectrum_port_range.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
mlxsw_spectrum-$(CONFIG_PTP_1588_CLOCK) += spectrum_ptp.o
obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
index 9dfe7148199f..faa63ea9b83e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
@@ -1887,6 +1887,46 @@ int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid,
}
EXPORT_SYMBOL(mlxsw_afa_block_append_fid_set);
+/* Ignore Action
+ * -------------
+ * The ignore action is used to ignore basic switching functions such as
+ * learning on a per-packet basis.
+ */
+
+#define MLXSW_AFA_IGNORE_CODE 0x0F
+#define MLXSW_AFA_IGNORE_SIZE 1
+
+/* afa_ignore_disable_learning
+ * Disable learning on ingress.
+ */
+MLXSW_ITEM32(afa, ignore, disable_learning, 0x00, 29, 1);
+
+/* afa_ignore_disable_security
+ * Disable security lookup on ingress.
+ * Reserved when Spectrum-1.
+ */
+MLXSW_ITEM32(afa, ignore, disable_security, 0x00, 28, 1);
+
+static void mlxsw_afa_ignore_pack(char *payload, bool disable_learning,
+ bool disable_security)
+{
+ mlxsw_afa_ignore_disable_learning_set(payload, disable_learning);
+ mlxsw_afa_ignore_disable_security_set(payload, disable_security);
+}
+
+int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block,
+ bool disable_learning, bool disable_security)
+{
+ char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_IGNORE_CODE,
+ MLXSW_AFA_IGNORE_SIZE);
+
+ if (IS_ERR(act))
+ return PTR_ERR(act);
+ mlxsw_afa_ignore_pack(act, disable_learning, disable_security);
+ return 0;
+}
+EXPORT_SYMBOL(mlxsw_afa_block_append_ignore);
+
/* MC Routing Action
* -----------------
* The Multicast router action. Can be used by RMFT_V2 - Router Multicast
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
index db58037be46e..0ead3a212de8 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
@@ -89,6 +89,8 @@ int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_fid_set(struct mlxsw_afa_block *block, u16 fid,
struct netlink_ext_ack *extack);
+int mlxsw_afa_block_append_ignore(struct mlxsw_afa_block *block,
+ bool disable_learning, bool disable_security);
int mlxsw_afa_block_append_mcrouter(struct mlxsw_afa_block *block,
u16 expected_irif, u16 min_mtu,
bool rmid_valid, u32 kvdl_index);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
index f0b2963ebac3..70f9b5e85a26 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c
@@ -32,8 +32,8 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8),
MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2),
MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6),
- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x18, 17, 3),
- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_LSB, 0x18, 20, 8),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x18, 17, 4),
+ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_LSB, 0x18, 21, 8),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_96_127, 0x20, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_64_95, 0x24, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_32_63, 0x28, 4),
@@ -43,6 +43,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_32_63, 0x38, 4),
MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_0_31, 0x3C, 4),
MLXSW_AFK_ELEMENT_INFO_U32(FDB_MISS, 0x40, 0, 1),
+ MLXSW_AFK_ELEMENT_INFO_U32(L4_PORT_RANGE, 0x40, 1, 16),
};
struct mlxsw_afk {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
index 65a4abadc7db..2eac7582c31a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
@@ -36,6 +36,7 @@ enum mlxsw_afk_element {
MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
MLXSW_AFK_ELEMENT_FDB_MISS,
+ MLXSW_AFK_ELEMENT_L4_PORT_RANGE,
MLXSW_AFK_ELEMENT_MAX,
};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index 0107cbc32fc7..d637c0348fa1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
@@ -32,6 +32,7 @@ struct mlxsw_env {
const struct mlxsw_bus_info *bus_info;
u8 max_module_count; /* Maximum number of modules per-slot. */
u8 num_of_slots; /* Including the main board. */
+ u8 max_eeprom_len; /* Maximum module EEPROM transaction length. */
struct mutex line_cards_lock; /* Protects line cards. */
struct mlxsw_env_line_card *line_cards[];
};
@@ -111,7 +112,7 @@ mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id,
if (err)
return err;
- mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0,
+ mlxsw_reg_mcia_pack(mcia_pl, slot_index, id,
MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1,
MLXSW_REG_MCIA_I2C_ADDR_LOW);
err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl);
@@ -146,6 +147,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
int module, u16 offset, u16 size, void *data,
bool qsfp, unsigned int *p_read_size)
{
+ struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
char mcia_pl[MLXSW_REG_MCIA_LEN];
char *eeprom_tmp;
u16 i2c_addr;
@@ -153,11 +155,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
int status;
int err;
- /* MCIA register accepts buffer size <= 48. Page of size 128 should be
- * read by chunks of size 48, 48, 32. Align the size of the last chunk
- * to avoid reading after the end of the page.
- */
- size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
+ size = min_t(u16, size, mlxsw_env->max_eeprom_len);
if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
@@ -188,7 +186,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
}
}
- mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size,
+ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page, offset, size,
i2c_addr);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl);
@@ -266,12 +264,12 @@ mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index,
page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM;
else
page = MLXSW_REG_MCIA_TH_PAGE_NUM;
- mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page,
+ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page,
MLXSW_REG_MCIA_TH_PAGE_OFF + off,
MLXSW_REG_MCIA_TH_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_LOW);
} else {
- mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0,
+ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module,
MLXSW_REG_MCIA_PAGE0_LO,
off, MLXSW_REG_MCIA_TH_ITEM_SIZE,
MLXSW_REG_MCIA_I2C_ADDR_HIGH);
@@ -489,9 +487,9 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core,
u8 size;
size = min_t(u8, page->length - bytes_read,
- MLXSW_REG_MCIA_EEPROM_SIZE);
+ mlxsw_env->max_eeprom_len);
- mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page,
+ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, page->page,
device_addr + bytes_read, size,
page->i2c_address);
mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank);
@@ -1359,6 +1357,26 @@ static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = {
.got_inactive = mlxsw_env_got_inactive,
};
+static int mlxsw_env_max_module_eeprom_len_query(struct mlxsw_env *mlxsw_env)
+{
+ char mcam_pl[MLXSW_REG_MCAM_LEN];
+ bool mcia_128b_supported;
+ int err;
+
+ mlxsw_reg_mcam_pack(mcam_pl,
+ MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES);
+ err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mcam), mcam_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_MCIA_128B,
+ &mcia_128b_supported);
+
+ mlxsw_env->max_eeprom_len = mcia_128b_supported ? 128 : 48;
+
+ return 0;
+}
+
int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *bus_info,
struct mlxsw_env **p_env)
@@ -1427,10 +1445,15 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core,
if (err)
goto err_type_set;
+ err = mlxsw_env_max_module_eeprom_len_query(env);
+ if (err)
+ goto err_eeprom_len_query;
+
env->line_cards[0]->active = true;
return 0;
+err_eeprom_len_query:
err_type_set:
mlxsw_env_module_event_disable(env, 0);
err_mlxsw_env_module_event_enable:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
index 70735068cf29..0fd290d776ff 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
@@ -405,7 +405,8 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev,
container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
return sprintf(buf, "front panel %03u\n",
- mlxsw_hwmon_attr->type_index);
+ mlxsw_hwmon_attr->type_index + 1 -
+ mlxsw_hwmon_attr->mlxsw_hwmon_dev->sensor_count);
}
static ssize_t
diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
index 41298835a11e..d23f293e285c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -48,6 +48,7 @@
#define MLXSW_I2C_MBOX_SIZE_BITS 12
#define MLXSW_I2C_ADDR_BUF_SIZE 4
#define MLXSW_I2C_BLK_DEF 32
+#define MLXSW_I2C_BLK_MAX 100
#define MLXSW_I2C_RETRY 5
#define MLXSW_I2C_TIMEOUT_MSECS 5000
#define MLXSW_I2C_MAX_DATA_SIZE 256
@@ -444,7 +445,7 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
} else {
/* No input mailbox is case of initialization query command. */
reg_size = MLXSW_I2C_MAX_DATA_SIZE;
- num = reg_size / mlxsw_i2c->block_size;
+ num = DIV_ROUND_UP(reg_size, mlxsw_i2c->block_size);
if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
dev_err(&client->dev, "Could not acquire lock");
@@ -653,7 +654,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client)
return -EOPNOTSUPP;
}
- mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF,
+ mlxsw_i2c->block_size = min_t(u16, MLXSW_I2C_BLK_MAX,
min_t(u16, quirks->max_read_len,
quirks->max_write_len));
} else {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index c968309657dd..51eea1f0529c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -517,11 +517,15 @@ static void mlxsw_pci_skb_cb_ts_set(struct mlxsw_pci *mlxsw_pci,
struct sk_buff *skb,
enum mlxsw_pci_cqe_v cqe_v, char *cqe)
{
+ u8 ts_type;
+
if (cqe_v != MLXSW_PCI_CQE_V2)
return;
- if (mlxsw_pci_cqe2_time_stamp_type_get(cqe) !=
- MLXSW_PCI_CQE_TIME_STAMP_TYPE_UTC)
+ ts_type = mlxsw_pci_cqe2_time_stamp_type_get(cqe);
+
+ if (ts_type != MLXSW_PCI_CQE_TIME_STAMP_TYPE_UTC &&
+ ts_type != MLXSW_PCI_CQE_TIME_STAMP_TYPE_MIRROR_UTC)
return;
mlxsw_skb_cb(skb)->cqe_ts.sec = mlxsw_pci_cqe2_time_stamp_sec_get(cqe);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 8165bf31a99a..ae556ddd7624 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -97,14 +97,6 @@ MLXSW_ITEM32(reg, sspr, m, 0x00, 31, 1);
*/
MLXSW_ITEM32_LP(reg, sspr, 0x00, 16, 0x00, 12);
-/* reg_sspr_sub_port
- * Virtual port within the physical port.
- * Should be set to 0 when virtual ports are not enabled on the port.
- *
- * Access: RW
- */
-MLXSW_ITEM32(reg, sspr, sub_port, 0x00, 8, 8);
-
/* reg_sspr_system_port
* Unique identifier within the stacking domain that represents all the ports
* that are available in the system (external ports).
@@ -120,7 +112,6 @@ static inline void mlxsw_reg_sspr_pack(char *payload, u16 local_port)
MLXSW_REG_ZERO(sspr, payload);
mlxsw_reg_sspr_m_set(payload, 1);
mlxsw_reg_sspr_local_port_set(payload, local_port);
- mlxsw_reg_sspr_sub_port_set(payload, 0);
mlxsw_reg_sspr_system_port_set(payload, local_port);
}
@@ -2799,6 +2790,78 @@ static inline void mlxsw_reg_ptar_unpack(char *payload, char *tcam_region_info)
mlxsw_reg_ptar_tcam_region_info_memcpy_from(payload, tcam_region_info);
}
+/* PPRR - Policy-Engine Port Range Register
+ * ----------------------------------------
+ * This register is used for configuring port range identification.
+ */
+#define MLXSW_REG_PPRR_ID 0x3008
+#define MLXSW_REG_PPRR_LEN 0x14
+
+MLXSW_REG_DEFINE(pprr, MLXSW_REG_PPRR_ID, MLXSW_REG_PPRR_LEN);
+
+/* reg_pprr_ipv4
+ * Apply port range register to IPv4 packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, ipv4, 0x00, 31, 1);
+
+/* reg_pprr_ipv6
+ * Apply port range register to IPv6 packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, ipv6, 0x00, 30, 1);
+
+/* reg_pprr_src
+ * Apply port range register to source L4 ports.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, src, 0x00, 29, 1);
+
+/* reg_pprr_dst
+ * Apply port range register to destination L4 ports.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, dst, 0x00, 28, 1);
+
+/* reg_pprr_tcp
+ * Apply port range register to TCP packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, tcp, 0x00, 27, 1);
+
+/* reg_pprr_udp
+ * Apply port range register to UDP packets.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, udp, 0x00, 26, 1);
+
+/* reg_pprr_register_index
+ * Index of Port Range Register being accessed.
+ * Range is 0..cap_max_acl_l4_port_range-1.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, pprr, register_index, 0x00, 0, 8);
+
+/* reg_prrr_port_range_min
+ * Minimum port range for comparison.
+ * Match is defined as:
+ * port_range_min <= packet_port <= port_range_max.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, port_range_min, 0x04, 16, 16);
+
+/* reg_prrr_port_range_max
+ * Maximum port range for comparison.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, pprr, port_range_max, 0x04, 0, 16);
+
+static inline void mlxsw_reg_pprr_pack(char *payload, u8 register_index)
+{
+ MLXSW_REG_ZERO(pprr, payload);
+ mlxsw_reg_pprr_register_index_set(payload, register_index);
+}
+
/* PPBS - Policy-Engine Policy Based Switching Register
* ----------------------------------------------------
* This register retrieves and sets Policy Based Switching Table entries.
@@ -9568,18 +9631,10 @@ static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind,
*/
#define MLXSW_REG_MCIA_ID 0x9014
-#define MLXSW_REG_MCIA_LEN 0x40
+#define MLXSW_REG_MCIA_LEN 0x94
MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN);
-/* reg_mcia_l
- * Lock bit. Setting this bit will lock the access to the specific
- * cable. Used for updating a full page in a cable EPROM. Any access
- * other then subsequence writes will fail while the port is locked.
- * Access: RW
- */
-MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1);
-
/* reg_mcia_module
* Module number.
* Access: Index
@@ -9644,7 +9699,6 @@ MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16);
#define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256
#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128
-#define MLXSW_REG_MCIA_EEPROM_SIZE 48
#define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50
#define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51
#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0
@@ -9681,7 +9735,7 @@ enum mlxsw_reg_mcia_eeprom_module_info {
* Bytes to read/write.
* Access: RW
*/
-MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE);
+MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, 128);
/* This is used to access the optional upper pages (1-3) in the QSFP+
* memory map. Page 1 is available on offset 256 through 383, page 2 -
@@ -9692,14 +9746,12 @@ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE);
MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1)
static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module,
- u8 lock, u8 page_number,
- u16 device_addr, u8 size,
+ u8 page_number, u16 device_addr, u8 size,
u8 i2c_device_addr)
{
MLXSW_REG_ZERO(mcia, payload);
mlxsw_reg_mcia_slot_set(payload, slot_index);
mlxsw_reg_mcia_module_set(payload, module);
- mlxsw_reg_mcia_l_set(payload, lock);
mlxsw_reg_mcia_page_number_set(payload, page_number);
mlxsw_reg_mcia_device_address_set(payload, device_addr);
mlxsw_reg_mcia_size_set(payload, size);
@@ -10509,6 +10561,79 @@ static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle,
mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]);
}
+/* MCAM - Management Capabilities Mask Register
+ * --------------------------------------------
+ * Reports the device supported management features.
+ */
+#define MLXSW_REG_MCAM_ID 0x907F
+#define MLXSW_REG_MCAM_LEN 0x48
+
+MLXSW_REG_DEFINE(mcam, MLXSW_REG_MCAM_ID, MLXSW_REG_MCAM_LEN);
+
+enum mlxsw_reg_mcam_feature_group {
+ /* Enhanced features. */
+ MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES,
+};
+
+/* reg_mcam_feature_group
+ * Feature list mask index.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, mcam, feature_group, 0x00, 16, 8);
+
+enum mlxsw_reg_mcam_mng_feature_cap_mask_bits {
+ /* If set, MCIA supports 128 bytes payloads. Otherwise, 48 bytes. */
+ MLXSW_REG_MCAM_MCIA_128B = 34,
+};
+
+#define MLXSW_REG_BYTES_PER_DWORD 0x4
+
+/* reg_mcam_mng_feature_cap_mask
+ * Supported port's enhanced features.
+ * Based on feature_group index.
+ * When bit is set, the feature is supported in the device.
+ * Access: RO
+ */
+#define MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(_dw_num, _offset) \
+ MLXSW_ITEM_BIT_ARRAY(reg, mcam, mng_feature_cap_mask_dw##_dw_num, \
+ _offset, MLXSW_REG_BYTES_PER_DWORD, 1)
+
+/* The access to the bits in the field 'mng_feature_cap_mask' is not same to
+ * other mask fields in other registers. In most of the cases bit #0 is the
+ * first one in the last dword. In MCAM register, the first dword contains bits
+ * #0-#31 and so on, so the access to the bits is simpler using bit array per
+ * dword. Declare each dword of 'mng_feature_cap_mask' field separately.
+ */
+MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(0, 0x28);
+MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(1, 0x2C);
+MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(2, 0x30);
+MLXSW_REG_MCAM_MNG_FEATURE_CAP_MASK_DWORD(3, 0x34);
+
+static inline void
+mlxsw_reg_mcam_pack(char *payload, enum mlxsw_reg_mcam_feature_group feat_group)
+{
+ MLXSW_REG_ZERO(mcam, payload);
+ mlxsw_reg_mcam_feature_group_set(payload, feat_group);
+}
+
+static inline void
+mlxsw_reg_mcam_unpack(char *payload,
+ enum mlxsw_reg_mcam_mng_feature_cap_mask_bits bit,
+ bool *p_mng_feature_cap_val)
+{
+ int offset = bit % (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE);
+ int dword = bit / (MLXSW_REG_BYTES_PER_DWORD * BITS_PER_BYTE);
+ u8 (*getters[])(const char *, u16) = {
+ mlxsw_reg_mcam_mng_feature_cap_mask_dw0_get,
+ mlxsw_reg_mcam_mng_feature_cap_mask_dw1_get,
+ mlxsw_reg_mcam_mng_feature_cap_mask_dw2_get,
+ mlxsw_reg_mcam_mng_feature_cap_mask_dw3_get,
+ };
+
+ if (!WARN_ON_ONCE(dword >= ARRAY_SIZE(getters)))
+ *p_mng_feature_cap_val = getters[dword](payload, offset);
+}
+
/* MPSC - Monitoring Packet Sampling Configuration Register
* --------------------------------------------------------
* MPSC Register is used to configure the Packet Sampling mechanism.
@@ -12819,6 +12944,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(pacl),
MLXSW_REG(pagt),
MLXSW_REG(ptar),
+ MLXSW_REG(pprr),
MLXSW_REG(ppbs),
MLXSW_REG(prcr),
MLXSW_REG(pefa),
@@ -12901,10 +13027,11 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(mcion),
MLXSW_REG(mtpps),
MLXSW_REG(mtutc),
- MLXSW_REG(mpsc),
MLXSW_REG(mcqi),
MLXSW_REG(mcc),
MLXSW_REG(mcda),
+ MLXSW_REG(mcam),
+ MLXSW_REG(mpsc),
MLXSW_REG(mgpc),
MLXSW_REG(mprs),
MLXSW_REG(mogcr),
diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h
index 19ae0d1c74a8..89dd2777ec4d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/resources.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h
@@ -39,6 +39,7 @@ enum mlxsw_res_id {
MLXSW_RES_ID_ACL_FLEX_KEYS,
MLXSW_RES_ID_ACL_MAX_ACTION_PER_RULE,
MLXSW_RES_ID_ACL_ACTIONS_PER_SET,
+ MLXSW_RES_ID_ACL_MAX_L4_PORT_RANGE,
MLXSW_RES_ID_ACL_MAX_ERPT_BANKS,
MLXSW_RES_ID_ACL_MAX_ERPT_BANK_SIZE,
MLXSW_RES_ID_ACL_MAX_LARGE_KEY_ID,
@@ -99,6 +100,7 @@ static u16 mlxsw_res_ids[] = {
[MLXSW_RES_ID_ACL_FLEX_KEYS] = 0x2910,
[MLXSW_RES_ID_ACL_MAX_ACTION_PER_RULE] = 0x2911,
[MLXSW_RES_ID_ACL_ACTIONS_PER_SET] = 0x2912,
+ [MLXSW_RES_ID_ACL_MAX_L4_PORT_RANGE] = 0x2920,
[MLXSW_RES_ID_ACL_MAX_ERPT_BANKS] = 0x2940,
[MLXSW_RES_ID_ACL_MAX_ERPT_BANK_SIZE] = 0x2941,
[MLXSW_RES_ID_ACL_MAX_LARGE_KEY_ID] = 0x2942,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 25a01dafde1b..9dbd5edff0b0 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1132,8 +1132,8 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev,
return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));
}
-static int mlxsw_sp_port_kill_vid(struct net_device *dev,
- __be16 __always_unused proto, u16 vid)
+int mlxsw_sp_port_kill_vid(struct net_device *dev,
+ __be16 __always_unused proto, u16 vid)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
@@ -3188,6 +3188,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_nve_init;
}
+ err = mlxsw_sp_port_range_init(mlxsw_sp);
+ if (err) {
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize port ranges\n");
+ goto err_port_range_init;
+ }
+
err = mlxsw_sp_acl_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
@@ -3280,6 +3286,8 @@ err_ptp_clock_init:
err_router_init:
mlxsw_sp_acl_fini(mlxsw_sp);
err_acl_init:
+ mlxsw_sp_port_range_fini(mlxsw_sp);
+err_port_range_init:
mlxsw_sp_nve_fini(mlxsw_sp);
err_nve_init:
mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
@@ -3462,6 +3470,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
}
mlxsw_sp_router_fini(mlxsw_sp);
mlxsw_sp_acl_fini(mlxsw_sp);
+ mlxsw_sp_port_range_fini(mlxsw_sp);
mlxsw_sp_nve_fini(mlxsw_sp);
mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
mlxsw_sp_afa_fini(mlxsw_sp);
@@ -3730,6 +3739,26 @@ static int mlxsw_sp_resources_rifs_register(struct mlxsw_core *mlxsw_core)
&size_params);
}
+static int
+mlxsw_sp_resources_port_range_register(struct mlxsw_core *mlxsw_core)
+{
+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
+ struct devlink_resource_size_params size_params;
+ u64 max;
+
+ if (!MLXSW_CORE_RES_VALID(mlxsw_core, ACL_MAX_L4_PORT_RANGE))
+ return -EIO;
+
+ max = MLXSW_CORE_RES_GET(mlxsw_core, ACL_MAX_L4_PORT_RANGE);
+ devlink_resource_size_params_init(&size_params, max, max, 1,
+ DEVLINK_RESOURCE_UNIT_ENTRY);
+
+ return devl_resource_register(devlink, "port_range_registers", max,
+ MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,
+ DEVLINK_RESOURCE_ID_PARENT_TOP,
+ &size_params);
+}
+
static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
{
int err;
@@ -3758,8 +3787,13 @@ static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
if (err)
goto err_resources_rifs_register;
+ err = mlxsw_sp_resources_port_range_register(mlxsw_core);
+ if (err)
+ goto err_resources_port_range_register;
+
return 0;
+err_resources_port_range_register:
err_resources_rifs_register:
err_resources_rif_mac_profile_register:
err_policer_resources_register:
@@ -3797,8 +3831,13 @@ static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)
if (err)
goto err_resources_rifs_register;
+ err = mlxsw_sp_resources_port_range_register(mlxsw_core);
+ if (err)
+ goto err_resources_port_range_register;
+
return 0;
+err_resources_port_range_register:
err_resources_rifs_register:
err_resources_rif_mac_profile_register:
err_policer_resources_register:
@@ -4073,23 +4112,6 @@ struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
return (struct mlxsw_sp_port *)priv.data;
}
-struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev)
-{
- struct mlxsw_sp_port *mlxsw_sp_port;
-
- rcu_read_lock();
- mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev);
- if (mlxsw_sp_port)
- dev_hold(mlxsw_sp_port->dev);
- rcu_read_unlock();
- return mlxsw_sp_port;
-}
-
-void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port)
-{
- dev_put(mlxsw_sp_port->dev);
-}
-
int mlxsw_sp_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp)
{
char mprs_pl[MLXSW_REG_MPRS_LEN];
@@ -4298,6 +4320,88 @@ static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp,
return -EBUSY;
}
+static int mlxsw_sp_lag_uppers_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct net_device *lag_dev,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *upper_dev;
+ struct net_device *master;
+ struct list_head *iter;
+ int done = 0;
+ int err;
+
+ master = netdev_master_upper_dev_get(lag_dev);
+ if (master && netif_is_bridge_master(master)) {
+ err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, lag_dev, master,
+ extack);
+ if (err)
+ return err;
+ }
+
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ master = netdev_master_upper_dev_get(upper_dev);
+ if (master && netif_is_bridge_master(master)) {
+ err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
+ upper_dev, master,
+ extack);
+ if (err)
+ goto err_port_bridge_join;
+ }
+
+ ++done;
+ }
+
+ return 0;
+
+err_port_bridge_join:
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ master = netdev_master_upper_dev_get(upper_dev);
+ if (!master || !netif_is_bridge_master(master))
+ continue;
+
+ if (!done--)
+ break;
+
+ mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);
+ }
+
+ master = netdev_master_upper_dev_get(lag_dev);
+ if (master && netif_is_bridge_master(master))
+ mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);
+
+ return err;
+}
+
+static void
+mlxsw_sp_lag_uppers_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct net_device *lag_dev)
+{
+ struct net_device *upper_dev;
+ struct net_device *master;
+ struct list_head *iter;
+
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ master = netdev_master_upper_dev_get(upper_dev);
+ if (!master)
+ continue;
+
+ mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);
+ }
+
+ master = netdev_master_upper_dev_get(lag_dev);
+ if (master)
+ mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);
+}
+
static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack)
@@ -4322,6 +4426,12 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index);
if (err)
return err;
+
+ err = mlxsw_sp_lag_uppers_bridge_join(mlxsw_sp_port, lag_dev,
+ extack);
+ if (err)
+ goto err_lag_uppers_bridge_join;
+
err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index);
if (err)
goto err_col_port_add;
@@ -4342,8 +4452,14 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
if (err)
goto err_router_join;
+ err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, lag_dev, extack);
+ if (err)
+ goto err_replay;
+
return 0;
+err_replay:
+ mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
err_router_join:
lag->ref_count--;
mlxsw_sp_port->lagged = 0;
@@ -4351,6 +4467,8 @@ err_router_join:
mlxsw_sp_port->local_port);
mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
err_col_port_add:
+ mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev);
+err_lag_uppers_bridge_join:
if (!lag->ref_count)
mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
return err;
@@ -4600,9 +4718,62 @@ static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
return true;
}
+static bool mlxsw_sp_netdev_is_master(struct net_device *upper_dev,
+ struct net_device *dev)
+{
+ return upper_dev == netdev_master_upper_dev_get(dev);
+}
+
+static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,
+ unsigned long event, void *ptr,
+ bool process_foreign);
+
+static int mlxsw_sp_netdevice_validate_uppers(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *upper_dev;
+ struct list_head *iter;
+ int err;
+
+ netdev_for_each_upper_dev_rcu(dev, upper_dev, iter) {
+ struct netdev_notifier_changeupper_info info = {
+ .info = {
+ .dev = dev,
+ .extack = extack,
+ },
+ .master = mlxsw_sp_netdev_is_master(upper_dev, dev),
+ .upper_dev = upper_dev,
+ .linking = true,
+
+ /* upper_info is relevant for LAG devices. But we would
+ * only need this if LAG were a valid upper above
+ * another upper (e.g. a bridge that is a member of a
+ * LAG), and that is never a valid configuration. So we
+ * can keep this as NULL.
+ */
+ .upper_info = NULL,
+ };
+
+ err = __mlxsw_sp_netdevice_event(mlxsw_sp,
+ NETDEV_PRECHANGEUPPER,
+ &info, true);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, upper_dev,
+ extack);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
struct net_device *dev,
- unsigned long event, void *ptr)
+ unsigned long event, void *ptr,
+ bool replay_deslavement)
{
struct netdev_notifier_changeupper_info *info;
struct mlxsw_sp_port *mlxsw_sp_port;
@@ -4640,8 +4811,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
(!netif_is_bridge_master(upper_dev) ||
!mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
upper_dev))) {
- NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
- return -EINVAL;
+ err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,
+ upper_dev,
+ extack);
+ if (err)
+ return err;
}
if (netif_is_lag_master(upper_dev) &&
!mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev,
@@ -4656,11 +4830,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port");
return -EINVAL;
}
- if (netif_is_macvlan(upper_dev) &&
- !mlxsw_sp_rif_exists(mlxsw_sp, lower_dev)) {
- NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
- return -EOPNOTSUPP;
- }
if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {
NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN");
return -EINVAL;
@@ -4707,15 +4876,20 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
case NETDEV_CHANGEUPPER:
upper_dev = info->upper_dev;
if (netif_is_bridge_master(upper_dev)) {
- if (info->linking)
+ if (info->linking) {
err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
lower_dev,
upper_dev,
extack);
- else
+ } else {
mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
lower_dev,
upper_dev);
+ if (!replay_deslavement)
+ break;
+ mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
+ lower_dev);
+ }
} else if (netif_is_lag_master(upper_dev)) {
if (info->linking) {
err = mlxsw_sp_port_lag_join(mlxsw_sp_port,
@@ -4724,6 +4898,8 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);
mlxsw_sp_port_lag_leave(mlxsw_sp_port,
upper_dev);
+ mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
+ dev);
}
} else if (netif_is_ovs_master(upper_dev)) {
if (info->linking)
@@ -4776,13 +4952,15 @@ static int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev,
static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev,
struct net_device *port_dev,
- unsigned long event, void *ptr)
+ unsigned long event, void *ptr,
+ bool replay_deslavement)
{
switch (event) {
case NETDEV_PRECHANGEUPPER:
case NETDEV_CHANGEUPPER:
return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev,
- event, ptr);
+ event, ptr,
+ replay_deslavement);
case NETDEV_CHANGELOWERSTATE:
return mlxsw_sp_netdevice_port_lower_event(port_dev, event,
ptr);
@@ -4791,6 +4969,30 @@ static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev,
return 0;
}
+/* Called for LAG or its upper VLAN after the per-LAG-lower processing was done,
+ * to do any per-LAG / per-LAG-upper processing.
+ */
+static int mlxsw_sp_netdevice_post_lag_event(struct net_device *dev,
+ unsigned long event,
+ void *ptr)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(dev);
+ struct netdev_notifier_changeupper_info *info = ptr;
+
+ if (!mlxsw_sp)
+ return 0;
+
+ switch (event) {
+ case NETDEV_CHANGEUPPER:
+ if (info->linking)
+ break;
+ if (netif_is_bridge_master(info->upper_dev))
+ mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, dev);
+ break;
+ }
+ return 0;
+}
+
static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
unsigned long event, void *ptr)
{
@@ -4801,19 +5003,19 @@ static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
netdev_for_each_lower_dev(lag_dev, dev, iter) {
if (mlxsw_sp_port_dev_check(dev)) {
ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event,
- ptr);
+ ptr, false);
if (ret)
return ret;
}
}
- return 0;
+ return mlxsw_sp_netdevice_post_lag_event(lag_dev, event, ptr);
}
static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
struct net_device *dev,
unsigned long event, void *ptr,
- u16 vid)
+ u16 vid, bool replay_deslavement)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
@@ -4844,27 +5046,30 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
(!netif_is_bridge_master(upper_dev) ||
!mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
upper_dev))) {
- NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
- return -EINVAL;
- }
- if (netif_is_macvlan(upper_dev) &&
- !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
- NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
- return -EOPNOTSUPP;
+ err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,
+ upper_dev,
+ extack);
+ if (err)
+ return err;
}
break;
case NETDEV_CHANGEUPPER:
upper_dev = info->upper_dev;
if (netif_is_bridge_master(upper_dev)) {
- if (info->linking)
+ if (info->linking) {
err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
vlan_dev,
upper_dev,
extack);
- else
+ } else {
mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
vlan_dev,
upper_dev);
+ if (!replay_deslavement)
+ break;
+ mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
+ vlan_dev);
+ }
} else if (netif_is_macvlan(upper_dev)) {
if (!info->linking)
mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
@@ -4888,26 +5093,26 @@ static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,
if (mlxsw_sp_port_dev_check(dev)) {
ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev,
event, ptr,
- vid);
+ vid, false);
if (ret)
return ret;
}
}
- return 0;
+ return mlxsw_sp_netdevice_post_lag_event(vlan_dev, event, ptr);
}
-static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
+static int mlxsw_sp_netdevice_bridge_vlan_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *vlan_dev,
struct net_device *br_dev,
unsigned long event, void *ptr,
- u16 vid)
+ u16 vid, bool process_foreign)
{
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
struct netdev_notifier_changeupper_info *info = ptr;
struct netlink_ext_ack *extack;
struct net_device *upper_dev;
- if (!mlxsw_sp)
+ if (!process_foreign && !mlxsw_sp_lower_get(vlan_dev))
return 0;
extack = netdev_notifier_info_to_extack(&info->info);
@@ -4920,13 +5125,6 @@ static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
return -EOPNOTSUPP;
}
- if (!info->linking)
- break;
- if (netif_is_macvlan(upper_dev) &&
- !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
- NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
- return -EOPNOTSUPP;
- }
break;
case NETDEV_CHANGEUPPER:
upper_dev = info->upper_dev;
@@ -4940,36 +5138,42 @@ static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
return 0;
}
-static int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
- unsigned long event, void *ptr)
+static int mlxsw_sp_netdevice_vlan_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *vlan_dev,
+ unsigned long event, void *ptr,
+ bool process_foreign)
{
struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
u16 vid = vlan_dev_vlan_id(vlan_dev);
if (mlxsw_sp_port_dev_check(real_dev))
return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev,
- event, ptr, vid);
+ event, ptr, vid,
+ true);
else if (netif_is_lag_master(real_dev))
return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,
real_dev, event,
ptr, vid);
else if (netif_is_bridge_master(real_dev))
- return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, real_dev,
- event, ptr, vid);
+ return mlxsw_sp_netdevice_bridge_vlan_event(mlxsw_sp, vlan_dev,
+ real_dev, event,
+ ptr, vid,
+ process_foreign);
return 0;
}
-static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
- unsigned long event, void *ptr)
+static int mlxsw_sp_netdevice_bridge_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *br_dev,
+ unsigned long event, void *ptr,
+ bool process_foreign)
{
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(br_dev);
struct netdev_notifier_changeupper_info *info = ptr;
struct netlink_ext_ack *extack;
struct net_device *upper_dev;
u16 proto;
- if (!mlxsw_sp)
+ if (!process_foreign && !mlxsw_sp_lower_get(br_dev))
return 0;
extack = netdev_notifier_info_to_extack(&info->info);
@@ -4997,11 +5201,6 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");
return -EOPNOTSUPP;
}
- if (netif_is_macvlan(upper_dev) &&
- !mlxsw_sp_rif_exists(mlxsw_sp, br_dev)) {
- NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
- return -EOPNOTSUPP;
- }
break;
case NETDEV_CHANGEUPPER:
upper_dev = info->upper_dev;
@@ -5107,35 +5306,48 @@ static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
return 0;
}
-static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,
+ unsigned long event, void *ptr,
+ bool process_foreign)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct mlxsw_sp_span_entry *span_entry;
- struct mlxsw_sp *mlxsw_sp;
int err = 0;
- mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
if (event == NETDEV_UNREGISTER) {
span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);
if (span_entry)
mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
}
- mlxsw_sp_span_respin(mlxsw_sp);
if (netif_is_vxlan(dev))
err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr);
else if (mlxsw_sp_port_dev_check(dev))
- err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr);
+ err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr, true);
else if (netif_is_lag_master(dev))
err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);
else if (is_vlan_dev(dev))
- err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr);
+ err = mlxsw_sp_netdevice_vlan_event(mlxsw_sp, dev, event, ptr,
+ process_foreign);
else if (netif_is_bridge_master(dev))
- err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr);
+ err = mlxsw_sp_netdevice_bridge_event(mlxsw_sp, dev, event, ptr,
+ process_foreign);
else if (netif_is_macvlan(dev))
err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr);
+ return err;
+}
+
+static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct mlxsw_sp *mlxsw_sp;
+ int err;
+
+ mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
+ mlxsw_sp_span_respin(mlxsw_sp);
+ err = __mlxsw_sp_netdevice_event(mlxsw_sp, event, ptr, false);
+
return notifier_from_errno(err);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 231e364cbb7c..02ca2871b6f9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -69,6 +69,7 @@ enum mlxsw_sp_resource_id {
MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
MLXSW_SP_RESOURCE_RIFS,
+ MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,
};
struct mlxsw_sp_port;
@@ -175,6 +176,7 @@ struct mlxsw_sp {
struct mlxsw_sp_acl *acl;
struct mlxsw_sp_fid_core *fid_core;
struct mlxsw_sp_policer_core *policer_core;
+ struct mlxsw_sp_port_range_core *pr_core;
struct mlxsw_sp_kvdl *kvdl;
struct mlxsw_sp_nve *nve;
struct notifier_block netdevice_nb;
@@ -698,6 +700,8 @@ int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
struct mlxsw_sp_port_vlan *
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
+int mlxsw_sp_port_kill_vid(struct net_device *dev,
+ __be16 __always_unused proto, u16 vid);
int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
u16 vid_end, bool is_member, bool untagged);
int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
@@ -716,8 +720,6 @@ int mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core,
bool mlxsw_sp_port_dev_check(const struct net_device *dev);
struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev);
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev);
-struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
-void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev);
int mlxsw_sp_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp);
@@ -865,9 +867,13 @@ struct mlxsw_sp_acl_rule_info {
egress_bind_blocker:1,
counter_valid:1,
policer_index_valid:1,
- ipv6_valid:1;
+ ipv6_valid:1,
+ src_port_range_reg_valid:1,
+ dst_port_range_reg_valid:1;
unsigned int counter_index;
u16 policer_index;
+ u8 src_port_range_reg_index;
+ u8 dst_port_range_reg_index;
struct {
u32 prev_val;
enum mlxsw_sp_acl_mangle_field prev_field;
@@ -992,7 +998,8 @@ void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
struct mlxsw_afa_block *afa_block);
-void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei);
+void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei);
int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei);
void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
unsigned int priority);
@@ -1043,6 +1050,9 @@ int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u16 fid, struct netlink_ext_ack *extack);
+int mlxsw_sp_acl_rulei_act_ignore(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei,
+ bool disable_learning, bool disable_security);
int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
struct mlxsw_sp_flow_block *block,
@@ -1261,7 +1271,6 @@ int mlxsw_sp_setup_tc_block_qevent_mark(struct mlxsw_sp_port *mlxsw_sp_port,
struct flow_block_offload *f);
/* spectrum_fid.c */
-bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
u16 fid_index);
int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex);
@@ -1394,10 +1403,6 @@ void mlxsw_sp_port_nve_fini(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_nve_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp);
-/* spectrum_nve_vxlan.c */
-int mlxsw_sp_nve_inc_parsing_depth_get(struct mlxsw_sp *mlxsw_sp);
-void mlxsw_sp_nve_inc_parsing_depth_put(struct mlxsw_sp *mlxsw_sp);
-
/* spectrum_trap.c */
int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp);
@@ -1484,4 +1489,18 @@ int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid,
int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp);
+/* spectrum_port_range.c */
+struct mlxsw_sp_port_range {
+ u16 min;
+ u16 max;
+ u8 source:1; /* Source or destination */
+};
+
+int mlxsw_sp_port_range_reg_get(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_port_range *range,
+ struct netlink_ext_ack *extack,
+ u8 *p_prr_index);
+void mlxsw_sp_port_range_reg_put(struct mlxsw_sp *mlxsw_sp, u8 prr_index);
+int mlxsw_sp_port_range_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_port_range_fini(struct mlxsw_sp *mlxsw_sp);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
index 3a636f753607..dfcdd37e797b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
@@ -90,7 +90,7 @@ mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp,
err_entry_add:
err_rulei_commit:
err_rulei_act_continue:
- mlxsw_sp_acl_rulei_destroy(rulei);
+ mlxsw_sp_acl_rulei_destroy(mlxsw_sp, rulei);
err_rulei_create:
mlxsw_sp_acl_ctcam_chunk_fini(&region->catchall.cchunk);
return err;
@@ -105,7 +105,7 @@ mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &region->cregion,
&region->catchall.cchunk,
&region->catchall.centry);
- mlxsw_sp_acl_rulei_destroy(rulei);
+ mlxsw_sp_acl_rulei_destroy(mlxsw_sp, rulei);
mlxsw_sp_acl_ctcam_chunk_fini(&region->catchall.cchunk);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
index e4f4cded2b6f..b1178b7a7f51 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
@@ -193,7 +193,7 @@ mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
key->vrid, GENMASK(7, 0));
mlxsw_sp_acl_rulei_keymask_u32(rulei,
MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
- key->vrid >> 8, GENMASK(2, 0));
+ key->vrid >> 8, GENMASK(3, 0));
switch (key->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 0423ac262d89..7c59c8a13584 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -339,10 +339,17 @@ err_afa_block_create:
return ERR_PTR(err);
}
-void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei)
+void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei)
{
if (rulei->action_created)
mlxsw_afa_block_destroy(rulei->act_block);
+ if (rulei->src_port_range_reg_valid)
+ mlxsw_sp_port_range_reg_put(mlxsw_sp,
+ rulei->src_port_range_reg_index);
+ if (rulei->dst_port_range_reg_valid)
+ mlxsw_sp_port_range_reg_put(mlxsw_sp,
+ rulei->dst_port_range_reg_index);
kfree(rulei);
}
@@ -768,6 +775,15 @@ int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp,
return mlxsw_afa_block_append_fid_set(rulei->act_block, fid, extack);
}
+int mlxsw_sp_acl_rulei_act_ignore(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei,
+ bool disable_learning, bool disable_security)
+{
+ return mlxsw_afa_block_append_ignore(rulei->act_block,
+ disable_learning,
+ disable_security);
+}
+
int mlxsw_sp_acl_rulei_act_sample(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
struct mlxsw_sp_flow_block *block,
@@ -834,7 +850,7 @@ void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp,
{
struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
- mlxsw_sp_acl_rulei_destroy(rule->rulei);
+ mlxsw_sp_acl_rulei_destroy(mlxsw_sp, rule->rulei);
kfree(rule);
mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
index 4dea39f2b304..cb746a43b24b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c
@@ -31,12 +31,14 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = {
MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4),
+ MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16),
MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = {
MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4),
+ MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16),
MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8),
MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16),
};
@@ -171,7 +173,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4[] = {
MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 24, 8),
- MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 3),
+ MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true),
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
@@ -205,6 +207,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = {
MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x04, 16, 9), /* TCP_CONTROL + TCP_ECN */
+ MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 0, 16),
};
static const struct mlxsw_afk_block mlxsw_sp2_afk_blocks[] = {
@@ -321,7 +324,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = {
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4b[] = {
MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 13, 8),
- MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x04, 21, 4, 0, true),
+ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x04, 21, 4),
};
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
index b6ee2d658b0c..9df098474743 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -137,16 +137,6 @@ static const int *mlxsw_sp_packet_type_sfgc_types[] = {
[MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
};
-bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
-{
- enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY;
- struct mlxsw_sp_fid_family *fid_family;
-
- fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type];
-
- return fid_family->start_index == fid_index;
-}
-
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
u16 fid_index)
{
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 72917f09e806..9fd1ca079258 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -160,6 +160,16 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
*/
rulei->egress_bind_blocker = 1;
+ /* Ignore learning and security lookup as redirection
+ * using ingress filters happens before the bridge.
+ */
+ err = mlxsw_sp_acl_rulei_act_ignore(mlxsw_sp, rulei,
+ true, true);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Cannot append ignore action");
+ return err;
+ }
+
fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp);
fid_index = mlxsw_sp_fid_index(fid);
err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei,
@@ -418,6 +428,68 @@ static int mlxsw_sp_flower_parse_ports(struct mlxsw_sp *mlxsw_sp,
return 0;
}
+static int
+mlxsw_sp_flower_parse_ports_range(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei,
+ struct flow_cls_offload *f, u8 ip_proto)
+{
+ const struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct flow_match_ports_range match;
+ u32 key_mask_value = 0;
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS_RANGE))
+ return 0;
+
+ if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) {
+ NL_SET_ERR_MSG_MOD(f->common.extack, "Only UDP and TCP keys are supported");
+ return -EINVAL;
+ }
+
+ flow_rule_match_ports_range(rule, &match);
+
+ if (match.mask->tp_min.src) {
+ struct mlxsw_sp_port_range range = {
+ .min = ntohs(match.key->tp_min.src),
+ .max = ntohs(match.key->tp_max.src),
+ .source = true,
+ };
+ u8 prr_index;
+ int err;
+
+ err = mlxsw_sp_port_range_reg_get(mlxsw_sp, &range,
+ f->common.extack, &prr_index);
+ if (err)
+ return err;
+
+ rulei->src_port_range_reg_index = prr_index;
+ rulei->src_port_range_reg_valid = true;
+ key_mask_value |= BIT(prr_index);
+ }
+
+ if (match.mask->tp_min.dst) {
+ struct mlxsw_sp_port_range range = {
+ .min = ntohs(match.key->tp_min.dst),
+ .max = ntohs(match.key->tp_max.dst),
+ };
+ u8 prr_index;
+ int err;
+
+ err = mlxsw_sp_port_range_reg_get(mlxsw_sp, &range,
+ f->common.extack, &prr_index);
+ if (err)
+ return err;
+
+ rulei->dst_port_range_reg_index = prr_index;
+ rulei->dst_port_range_reg_valid = true;
+ key_mask_value |= BIT(prr_index);
+ }
+
+ mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_L4_PORT_RANGE,
+ key_mask_value, key_mask_value);
+
+ return 0;
+}
+
static int mlxsw_sp_flower_parse_tcp(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
struct flow_cls_offload *f,
@@ -496,16 +568,17 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
int err;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_META) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_TCP) |
- BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_VLAN))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_META) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS_RANGE) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN))) {
dev_err(mlxsw_sp->bus_info->dev, "Unsupported key\n");
NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key");
return -EOPNOTSUPP;
@@ -604,6 +677,11 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
err = mlxsw_sp_flower_parse_ports(mlxsw_sp, rulei, f, ip_proto);
if (err)
return err;
+
+ err = mlxsw_sp_flower_parse_ports_range(mlxsw_sp, rulei, f, ip_proto);
+ if (err)
+ return err;
+
err = mlxsw_sp_flower_parse_tcp(mlxsw_sp, rulei, f, ip_proto);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
index d2b57a045aa4..5479a1c19d2e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c
@@ -989,6 +989,9 @@ void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
int nve_ifindex;
__be32 vni;
+ /* Necessary for __dev_get_by_index() below. */
+ ASSERT_RTNL();
+
mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
mlxsw_sp_nve_ipv6_addr_flush_by_fid(mlxsw_sp, fid_index);
@@ -997,15 +1000,13 @@ void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_fid_vni(fid, &vni)))
goto out;
- nve_dev = dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex);
+ nve_dev = __dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex);
if (!nve_dev)
goto out;
mlxsw_sp_nve_fdb_clear_offload(mlxsw_sp, fid, nve_dev, vni);
mlxsw_sp_fid_fdb_clear_offload(fid, nve_dev);
- dev_put(nve_dev);
-
out:
mlxsw_sp_fid_vni_clear(fid);
mlxsw_sp_nve_tunnel_fini(mlxsw_sp);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_port_range.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_port_range.c
new file mode 100644
index 000000000000..2d193de12be6
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_port_range.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <linux/bits.h>
+#include <linux/netlink.h>
+#include <linux/refcount.h>
+#include <linux/xarray.h>
+#include <net/devlink.h>
+
+#include "spectrum.h"
+
+struct mlxsw_sp_port_range_reg {
+ struct mlxsw_sp_port_range range;
+ refcount_t refcount;
+ u32 index;
+};
+
+struct mlxsw_sp_port_range_core {
+ struct xarray prr_xa;
+ struct xa_limit prr_ids;
+ atomic_t prr_count;
+};
+
+static int
+mlxsw_sp_port_range_reg_configure(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_port_range_reg *prr)
+{
+ char pprr_pl[MLXSW_REG_PPRR_LEN];
+
+ /* We do not care if packet is IPv4/IPv6 and TCP/UDP, so set all four
+ * fields.
+ */
+ mlxsw_reg_pprr_pack(pprr_pl, prr->index);
+ mlxsw_reg_pprr_ipv4_set(pprr_pl, true);
+ mlxsw_reg_pprr_ipv6_set(pprr_pl, true);
+ mlxsw_reg_pprr_src_set(pprr_pl, prr->range.source);
+ mlxsw_reg_pprr_dst_set(pprr_pl, !prr->range.source);
+ mlxsw_reg_pprr_tcp_set(pprr_pl, true);
+ mlxsw_reg_pprr_udp_set(pprr_pl, true);
+ mlxsw_reg_pprr_port_range_min_set(pprr_pl, prr->range.min);
+ mlxsw_reg_pprr_port_range_max_set(pprr_pl, prr->range.max);
+
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pprr), pprr_pl);
+}
+
+static struct mlxsw_sp_port_range_reg *
+mlxsw_sp_port_range_reg_create(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_port_range *range,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
+ struct mlxsw_sp_port_range_reg *prr;
+ int err;
+
+ prr = kzalloc(sizeof(*prr), GFP_KERNEL);
+ if (!prr)
+ return ERR_PTR(-ENOMEM);
+
+ prr->range = *range;
+ refcount_set(&prr->refcount, 1);
+
+ err = xa_alloc(&pr_core->prr_xa, &prr->index, prr, pr_core->prr_ids,
+ GFP_KERNEL);
+ if (err) {
+ if (err == -EBUSY)
+ NL_SET_ERR_MSG_MOD(extack, "Exceeded number of port range registers");
+ goto err_xa_alloc;
+ }
+
+ err = mlxsw_sp_port_range_reg_configure(mlxsw_sp, prr);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to configure port range register");
+ goto err_reg_configure;
+ }
+
+ atomic_inc(&pr_core->prr_count);
+
+ return prr;
+
+err_reg_configure:
+ xa_erase(&pr_core->prr_xa, prr->index);
+err_xa_alloc:
+ kfree(prr);
+ return ERR_PTR(err);
+}
+
+static void mlxsw_sp_port_range_reg_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_port_range_reg *prr)
+{
+ struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
+
+ atomic_dec(&pr_core->prr_count);
+ xa_erase(&pr_core->prr_xa, prr->index);
+ kfree(prr);
+}
+
+static struct mlxsw_sp_port_range_reg *
+mlxsw_sp_port_range_reg_find(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_port_range *range)
+{
+ struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
+ struct mlxsw_sp_port_range_reg *prr;
+ unsigned long index;
+
+ xa_for_each(&pr_core->prr_xa, index, prr) {
+ if (prr->range.min == range->min &&
+ prr->range.max == range->max &&
+ prr->range.source == range->source)
+ return prr;
+ }
+
+ return NULL;
+}
+
+int mlxsw_sp_port_range_reg_get(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_port_range *range,
+ struct netlink_ext_ack *extack,
+ u8 *p_prr_index)
+{
+ struct mlxsw_sp_port_range_reg *prr;
+
+ prr = mlxsw_sp_port_range_reg_find(mlxsw_sp, range);
+ if (prr) {
+ refcount_inc(&prr->refcount);
+ *p_prr_index = prr->index;
+ return 0;
+ }
+
+ prr = mlxsw_sp_port_range_reg_create(mlxsw_sp, range, extack);
+ if (IS_ERR(prr))
+ return PTR_ERR(prr);
+
+ *p_prr_index = prr->index;
+
+ return 0;
+}
+
+void mlxsw_sp_port_range_reg_put(struct mlxsw_sp *mlxsw_sp, u8 prr_index)
+{
+ struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
+ struct mlxsw_sp_port_range_reg *prr;
+
+ prr = xa_load(&pr_core->prr_xa, prr_index);
+ if (WARN_ON(!prr))
+ return;
+
+ if (!refcount_dec_and_test(&prr->refcount))
+ return;
+
+ mlxsw_sp_port_range_reg_destroy(mlxsw_sp, prr);
+}
+
+static u64 mlxsw_sp_port_range_reg_occ_get(void *priv)
+{
+ struct mlxsw_sp_port_range_core *pr_core = priv;
+
+ return atomic_read(&pr_core->prr_count);
+}
+
+int mlxsw_sp_port_range_init(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_port_range_core *pr_core;
+ struct mlxsw_core *core = mlxsw_sp->core;
+ u64 max;
+
+ if (!MLXSW_CORE_RES_VALID(core, ACL_MAX_L4_PORT_RANGE))
+ return -EIO;
+ max = MLXSW_CORE_RES_GET(core, ACL_MAX_L4_PORT_RANGE);
+
+ /* Each port range register is represented using a single bit in the
+ * two bytes "l4_port_range" ACL key element.
+ */
+ WARN_ON(max > BITS_PER_BYTE * sizeof(u16));
+
+ pr_core = kzalloc(sizeof(*mlxsw_sp->pr_core), GFP_KERNEL);
+ if (!pr_core)
+ return -ENOMEM;
+ mlxsw_sp->pr_core = pr_core;
+
+ pr_core->prr_ids.max = max - 1;
+ xa_init_flags(&pr_core->prr_xa, XA_FLAGS_ALLOC);
+
+ devl_resource_occ_get_register(priv_to_devlink(core),
+ MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,
+ mlxsw_sp_port_range_reg_occ_get,
+ pr_core);
+
+ return 0;
+}
+
+void mlxsw_sp_port_range_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_port_range_core *pr_core = mlxsw_sp->pr_core;
+
+ devl_resource_occ_get_unregister(priv_to_devlink(mlxsw_sp->core),
+ MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS);
+ WARN_ON(!xa_empty(&pr_core->prr_xa));
+ xa_destroy(&pr_core->prr_xa);
+ kfree(pr_core);
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index b32adf277a22..debd2c466f11 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -71,6 +71,7 @@ static const struct rhashtable_params mlxsw_sp_crif_ht_params = {
struct mlxsw_sp_rif {
struct mlxsw_sp_crif *crif; /* NULL for underlay RIF */
+ netdevice_tracker dev_tracker;
struct list_head neigh_list;
struct mlxsw_sp_fid *fid;
unsigned char addr[ETH_ALEN];
@@ -139,6 +140,7 @@ struct mlxsw_sp_rif_ops {
struct netlink_ext_ack *extack);
void (*deconfigure)(struct mlxsw_sp_rif *rif);
struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack);
void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
};
@@ -2871,6 +2873,21 @@ static bool mlxsw_sp_dev_lower_is_port(struct net_device *dev)
return !!mlxsw_sp_port;
}
+static int mlxsw_sp_router_schedule_neigh_work(struct mlxsw_sp_router *router,
+ struct neighbour *n)
+{
+ struct net *net;
+
+ net = neigh_parms_net(n->parms);
+
+ /* Take a reference to ensure the neighbour won't be destructed until we
+ * drop the reference in delayed work.
+ */
+ neigh_clone(n);
+ return mlxsw_sp_router_schedule_work(net, router, n,
+ mlxsw_sp_router_neigh_event_work);
+}
+
static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -2878,7 +2895,6 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
unsigned long interval;
struct neigh_parms *p;
struct neighbour *n;
- struct net *net;
router = container_of(nb, struct mlxsw_sp_router, netevent_nb);
@@ -2902,7 +2918,6 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
break;
case NETEVENT_NEIGH_UPDATE:
n = ptr;
- net = neigh_parms_net(n->parms);
if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
return NOTIFY_DONE;
@@ -2910,13 +2925,7 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb,
if (!mlxsw_sp_dev_lower_is_port(n->dev))
return NOTIFY_DONE;
- /* Take a reference to ensure the neighbour won't be
- * destructed until we drop the reference in delayed
- * work.
- */
- neigh_clone(n);
- return mlxsw_sp_router_schedule_work(net, router, n,
- mlxsw_sp_router_neigh_event_work);
+ return mlxsw_sp_router_schedule_neigh_work(router, n);
case NETEVENT_IPV4_MPATH_HASH_UPDATE:
case NETEVENT_IPV6_MPATH_HASH_UPDATE:
@@ -2975,6 +2984,52 @@ static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
}
}
+struct mlxsw_sp_neigh_rif_made_sync {
+ struct mlxsw_sp *mlxsw_sp;
+ struct mlxsw_sp_rif *rif;
+ int err;
+};
+
+static void mlxsw_sp_neigh_rif_made_sync_each(struct neighbour *n, void *data)
+{
+ struct mlxsw_sp_neigh_rif_made_sync *rms = data;
+ int rc;
+
+ if (rms->err)
+ return;
+ if (n->dev != mlxsw_sp_rif_dev(rms->rif))
+ return;
+ rc = mlxsw_sp_router_schedule_neigh_work(rms->mlxsw_sp->router, n);
+ if (rc != NOTIFY_DONE)
+ rms->err = -ENOMEM;
+}
+
+static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp_neigh_rif_made_sync rms = {
+ .mlxsw_sp = mlxsw_sp,
+ .rif = rif,
+ };
+
+ neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
+ if (rms.err)
+ goto err_arp;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ neigh_for_each(&nd_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
+#endif
+ if (rms.err)
+ goto err_nd;
+
+ return 0;
+
+err_nd:
+err_arp:
+ mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
+ return rms.err;
+}
+
enum mlxsw_sp_nexthop_type {
MLXSW_SP_NEXTHOP_TYPE_ETH,
MLXSW_SP_NEXTHOP_TYPE_IPIP,
@@ -4396,6 +4451,19 @@ err_neigh_init:
return err;
}
+static int mlxsw_sp_nexthop_type_rif_made(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_nexthop *nh)
+{
+ switch (nh->type) {
+ case MLXSW_SP_NEXTHOP_TYPE_ETH:
+ return mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
+ case MLXSW_SP_NEXTHOP_TYPE_IPIP:
+ break;
+ }
+
+ return 0;
+}
+
static void mlxsw_sp_nexthop_type_rif_gone(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh)
{
@@ -4524,6 +4592,35 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp,
}
}
+static int mlxsw_sp_nexthop_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *rif)
+{
+ struct mlxsw_sp_nexthop *nh, *tmp;
+ unsigned int n = 0;
+ int err;
+
+ list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list,
+ crif_list_node) {
+ err = mlxsw_sp_nexthop_type_rif_made(mlxsw_sp, nh);
+ if (err)
+ goto err_nexthop_type_rif;
+ mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
+ n++;
+ }
+
+ return 0;
+
+err_nexthop_type_rif:
+ list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list,
+ crif_list_node) {
+ if (!n--)
+ break;
+ mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh);
+ mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp);
+ }
+ return err;
+}
+
static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif)
{
@@ -7451,6 +7548,7 @@ struct mlxsw_sp_fib6_event_work {
struct mlxsw_sp_fib_event_work {
struct work_struct work;
+ netdevice_tracker dev_tracker;
union {
struct mlxsw_sp_fib6_event_work fib6_work;
struct fib_entry_notifier_info fen_info;
@@ -7624,12 +7722,12 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
&fib_work->ven_info);
if (err)
dev_warn(mlxsw_sp->bus_info->dev, "MR VIF add failed.\n");
- dev_put(fib_work->ven_info.dev);
+ netdev_put(fib_work->ven_info.dev, &fib_work->dev_tracker);
break;
case FIB_EVENT_VIF_DEL:
mlxsw_sp_router_fibmr_vif_del(mlxsw_sp,
&fib_work->ven_info);
- dev_put(fib_work->ven_info.dev);
+ netdev_put(fib_work->ven_info.dev, &fib_work->dev_tracker);
break;
}
mutex_unlock(&mlxsw_sp->router->lock);
@@ -7700,7 +7798,8 @@ mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
case FIB_EVENT_VIF_ADD:
case FIB_EVENT_VIF_DEL:
memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
- dev_hold(fib_work->ven_info.dev);
+ netdev_hold(fib_work->ven_info.dev, &fib_work->dev_tracker,
+ GFP_ATOMIC);
break;
}
}
@@ -7884,6 +7983,26 @@ static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}
+static int mlxsw_sp_router_rif_made_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *rif)
+{
+ int err;
+
+ err = mlxsw_sp_neigh_rif_made_sync(mlxsw_sp, rif);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_nexthop_rif_made_sync(mlxsw_sp, rif);
+ if (err)
+ goto err_nexthop;
+
+ return 0;
+
+err_nexthop:
+ mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif);
+ return err;
+}
+
static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif)
{
@@ -8190,6 +8309,7 @@ mlxsw_sp_router_port_l3_stats_report_delta(struct mlxsw_sp_rif *rif,
struct mlxsw_sp_router_hwstats_notify_work {
struct work_struct work;
struct net_device *dev;
+ netdevice_tracker dev_tracker;
};
static void mlxsw_sp_router_hwstats_notify_work(struct work_struct *work)
@@ -8201,7 +8321,7 @@ static void mlxsw_sp_router_hwstats_notify_work(struct work_struct *work)
rtnl_lock();
rtnl_offload_xstats_notify(hws_work->dev);
rtnl_unlock();
- dev_put(hws_work->dev);
+ netdev_put(hws_work->dev, &hws_work->dev_tracker);
kfree(hws_work);
}
@@ -8221,7 +8341,7 @@ mlxsw_sp_router_hwstats_notify_schedule(struct net_device *dev)
return;
INIT_WORK(&hws_work->work, mlxsw_sp_router_hwstats_notify_work);
- dev_hold(dev);
+ netdev_hold(dev, &hws_work->dev_tracker, GFP_KERNEL);
hws_work->dev = dev;
mlxsw_core_schedule_work(&hws_work->work);
}
@@ -8293,14 +8413,14 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
err = -ENOMEM;
goto err_rif_alloc;
}
- dev_hold(params->dev);
+ netdev_hold(params->dev, &rif->dev_tracker, GFP_KERNEL);
mlxsw_sp->router->rifs[rif_index] = rif;
rif->mlxsw_sp = mlxsw_sp;
rif->ops = ops;
rif->rif_entries = rif_entries;
if (ops->fid_get) {
- fid = ops->fid_get(rif, extack);
+ fid = ops->fid_get(rif, params, extack);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
goto err_fid_get;
@@ -8321,6 +8441,10 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
goto err_mr_rif_add;
}
+ err = mlxsw_sp_router_rif_made_sync(mlxsw_sp, rif);
+ if (err)
+ goto err_rif_made_sync;
+
if (netdev_offload_xstats_enabled(params->dev,
NETDEV_OFFLOAD_XSTATS_TYPE_L3)) {
err = mlxsw_sp_router_port_l3_stats_enable(rif);
@@ -8335,6 +8459,8 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
return rif;
err_stats_enable:
+ mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
+err_rif_made_sync:
err_mr_rif_add:
for (i--; i >= 0; i--)
mlxsw_sp_mr_rif_del(vr->mr_table[i], rif);
@@ -8344,7 +8470,7 @@ err_configure:
mlxsw_sp_fid_put(fid);
err_fid_get:
mlxsw_sp->router->rifs[rif_index] = NULL;
- dev_put(params->dev);
+ netdev_put(params->dev, &rif->dev_tracker);
mlxsw_sp_rif_free(rif);
err_rif_alloc:
err_crif_lookup:
@@ -8386,7 +8512,7 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
/* Loopback RIFs are not associated with a FID. */
mlxsw_sp_fid_put(fid);
mlxsw_sp->router->rifs[rif->rif_index] = NULL;
- dev_put(dev);
+ netdev_put(dev, &rif->dev_tracker);
mlxsw_sp_rif_free(rif);
mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries);
vr->rif_count--;
@@ -8410,6 +8536,110 @@ out:
mutex_unlock(&mlxsw_sp->router->lock);
}
+static void mlxsw_sp_rif_destroy_vlan_upper(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *br_dev,
+ u16 vid)
+{
+ struct net_device *upper_dev;
+ struct mlxsw_sp_crif *crif;
+
+ rcu_read_lock();
+ upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q), vid);
+ rcu_read_unlock();
+
+ if (!upper_dev)
+ return;
+
+ crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, upper_dev);
+ if (!crif || !crif->rif)
+ return;
+
+ mlxsw_sp_rif_destroy(crif->rif);
+}
+
+static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *l3_dev,
+ int lower_pvid,
+ unsigned long event,
+ struct netlink_ext_ack *extack);
+
+int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *br_dev,
+ u16 new_vid, bool is_pvid,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_rif *old_rif;
+ struct mlxsw_sp_rif *new_rif;
+ struct net_device *upper_dev;
+ u16 old_pvid = 0;
+ u16 new_pvid;
+ int err = 0;
+
+ mutex_lock(&mlxsw_sp->router->lock);
+ old_rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev);
+ if (old_rif) {
+ /* If the RIF on the bridge is not a VLAN RIF, we shouldn't have
+ * gotten a PVID notification.
+ */
+ if (WARN_ON(old_rif->ops->type != MLXSW_SP_RIF_TYPE_VLAN))
+ old_rif = NULL;
+ else
+ old_pvid = mlxsw_sp_fid_8021q_vid(old_rif->fid);
+ }
+
+ if (is_pvid)
+ new_pvid = new_vid;
+ else if (old_pvid == new_vid)
+ new_pvid = 0;
+ else
+ goto out;
+
+ if (old_pvid == new_pvid)
+ goto out;
+
+ if (new_pvid) {
+ struct mlxsw_sp_rif_params params = {
+ .dev = br_dev,
+ .vid = new_pvid,
+ };
+
+ /* If there is a VLAN upper with the same VID as the new PVID,
+ * kill its RIF, if there is one.
+ */
+ mlxsw_sp_rif_destroy_vlan_upper(mlxsw_sp, br_dev, new_pvid);
+
+ if (mlxsw_sp_dev_addr_list_empty(br_dev))
+ goto out;
+ new_rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
+ if (IS_ERR(new_rif)) {
+ err = PTR_ERR(new_rif);
+ goto out;
+ }
+
+ if (old_pvid)
+ mlxsw_sp_rif_migrate_destroy(mlxsw_sp, old_rif, new_rif,
+ true);
+ } else {
+ mlxsw_sp_rif_destroy(old_rif);
+ }
+
+ if (old_pvid) {
+ rcu_read_lock();
+ upper_dev = __vlan_find_dev_deep_rcu(br_dev, htons(ETH_P_8021Q),
+ old_pvid);
+ rcu_read_unlock();
+ if (upper_dev)
+ err = mlxsw_sp_inetaddr_bridge_event(mlxsw_sp,
+ upper_dev,
+ new_pvid,
+ NETDEV_UP, extack);
+ }
+
+out:
+ mutex_unlock(&mlxsw_sp->router->lock);
+ return err;
+}
+
static void
mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
@@ -8664,21 +8894,24 @@ __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
{
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- struct mlxsw_sp_rif_params params = {
- .dev = l3_dev,
- };
+ struct mlxsw_sp_rif_params params;
u16 vid = mlxsw_sp_port_vlan->vid;
struct mlxsw_sp_rif *rif;
struct mlxsw_sp_fid *fid;
int err;
+ params = (struct mlxsw_sp_rif_params) {
+ .dev = l3_dev,
+ .vid = vid,
+ };
+
mlxsw_sp_rif_subport_params_init(&params, mlxsw_sp_port_vlan);
rif = mlxsw_sp_rif_subport_get(mlxsw_sp, &params, extack);
if (IS_ERR(rif))
return PTR_ERR(rif);
/* FID was already created, just take a reference */
- fid = rif->ops->fid_get(rif, extack);
+ fid = rif->ops->fid_get(rif, &params, extack);
err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
if (err)
goto err_fid_port_vid_map;
@@ -8776,10 +9009,11 @@ static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
}
static int mlxsw_sp_inetaddr_port_event(struct net_device *port_dev,
- unsigned long event,
+ unsigned long event, bool nomaster,
struct netlink_ext_ack *extack)
{
- if (netif_is_any_bridge_port(port_dev) || netif_is_lag_port(port_dev))
+ if (!nomaster && (netif_is_any_bridge_port(port_dev) ||
+ netif_is_lag_port(port_dev)))
return 0;
return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event,
@@ -8810,10 +9044,10 @@ static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
}
static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
- unsigned long event,
+ unsigned long event, bool nomaster,
struct netlink_ext_ack *extack)
{
- if (netif_is_bridge_port(lag_dev))
+ if (!nomaster && netif_is_bridge_port(lag_dev))
return 0;
return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event,
@@ -8822,6 +9056,7 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev,
static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
struct net_device *l3_dev,
+ int lower_pvid,
unsigned long event,
struct netlink_ext_ack *extack)
{
@@ -8829,6 +9064,7 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
.dev = l3_dev,
};
struct mlxsw_sp_rif *rif;
+ int err;
switch (event) {
case NETDEV_UP:
@@ -8840,7 +9076,21 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
NL_SET_ERR_MSG_MOD(extack, "Adding an IP address to 802.1ad bridge is not supported");
return -EOPNOTSUPP;
}
+ err = br_vlan_get_pvid(l3_dev, &params.vid);
+ if (err)
+ return err;
+ if (!params.vid)
+ return 0;
+ } else if (is_vlan_dev(l3_dev)) {
+ params.vid = vlan_dev_vlan_id(l3_dev);
+
+ /* If the VID matches PVID of the bridge below, the
+ * bridge owns the RIF for this VLAN. Don't do anything.
+ */
+ if ((int)params.vid == lower_pvid)
+ return 0;
}
+
rif = mlxsw_sp_rif_create(mlxsw_sp, &params, extack);
if (IS_ERR(rif))
return PTR_ERR(rif);
@@ -8856,24 +9106,32 @@ static int mlxsw_sp_inetaddr_bridge_event(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_inetaddr_vlan_event(struct mlxsw_sp *mlxsw_sp,
struct net_device *vlan_dev,
- unsigned long event,
+ unsigned long event, bool nomaster,
struct netlink_ext_ack *extack)
{
struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
u16 vid = vlan_dev_vlan_id(vlan_dev);
+ u16 lower_pvid;
+ int err;
- if (netif_is_bridge_port(vlan_dev))
+ if (!nomaster && netif_is_bridge_port(vlan_dev))
return 0;
- if (mlxsw_sp_port_dev_check(real_dev))
+ if (mlxsw_sp_port_dev_check(real_dev)) {
return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
event, vid, extack);
- else if (netif_is_lag_master(real_dev))
+ } else if (netif_is_lag_master(real_dev)) {
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
vid, extack);
- else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
- return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev, event,
+ } else if (netif_is_bridge_master(real_dev) &&
+ br_vlan_enabled(real_dev)) {
+ err = br_vlan_get_pvid(real_dev, &lower_pvid);
+ if (err)
+ return err;
+ return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, vlan_dev,
+ lower_pvid, event,
extack);
+ }
return 0;
}
@@ -8927,10 +9185,8 @@ static int mlxsw_sp_rif_macvlan_add(struct mlxsw_sp *mlxsw_sp,
int err;
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan->lowerdev);
- if (!rif) {
- NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
- return -EOPNOTSUPP;
- }
+ if (!rif)
+ return 0;
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, macvlan_dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), true);
@@ -9000,19 +9256,21 @@ static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp,
static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
struct net_device *dev,
- unsigned long event,
+ unsigned long event, bool nomaster,
struct netlink_ext_ack *extack)
{
if (mlxsw_sp_port_dev_check(dev))
- return mlxsw_sp_inetaddr_port_event(dev, event, extack);
+ return mlxsw_sp_inetaddr_port_event(dev, event, nomaster,
+ extack);
else if (netif_is_lag_master(dev))
- return mlxsw_sp_inetaddr_lag_event(dev, event, extack);
+ return mlxsw_sp_inetaddr_lag_event(dev, event, nomaster,
+ extack);
else if (netif_is_bridge_master(dev))
- return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, event,
+ return mlxsw_sp_inetaddr_bridge_event(mlxsw_sp, dev, -1, event,
extack);
else if (is_vlan_dev(dev))
return mlxsw_sp_inetaddr_vlan_event(mlxsw_sp, dev, event,
- extack);
+ nomaster, extack);
else if (netif_is_macvlan(dev))
return mlxsw_sp_inetaddr_macvlan_event(mlxsw_sp, dev, event,
extack);
@@ -9039,7 +9297,8 @@ static int mlxsw_sp_inetaddr_event(struct notifier_block *nb,
if (!mlxsw_sp_rif_should_config(rif, dev, event))
goto out;
- err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, NULL);
+ err = __mlxsw_sp_inetaddr_event(router->mlxsw_sp, dev, event, false,
+ NULL);
out:
mutex_unlock(&router->lock);
return notifier_from_errno(err);
@@ -9063,7 +9322,8 @@ static int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
if (!mlxsw_sp_rif_should_config(rif, dev, event))
goto out;
- err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack);
+ err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false,
+ ivi->extack);
out:
mutex_unlock(&mlxsw_sp->router->lock);
return notifier_from_errno(err);
@@ -9073,6 +9333,7 @@ struct mlxsw_sp_inet6addr_event_work {
struct work_struct work;
struct mlxsw_sp *mlxsw_sp;
struct net_device *dev;
+ netdevice_tracker dev_tracker;
unsigned long event;
};
@@ -9092,11 +9353,11 @@ static void mlxsw_sp_inet6addr_event_work(struct work_struct *work)
if (!mlxsw_sp_rif_should_config(rif, dev, event))
goto out;
- __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, NULL);
+ __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false, NULL);
out:
mutex_unlock(&mlxsw_sp->router->lock);
rtnl_unlock();
- dev_put(dev);
+ netdev_put(dev, &inet6addr_work->dev_tracker);
kfree(inet6addr_work);
}
@@ -9122,7 +9383,7 @@ static int mlxsw_sp_inet6addr_event(struct notifier_block *nb,
inet6addr_work->mlxsw_sp = router->mlxsw_sp;
inet6addr_work->dev = dev;
inet6addr_work->event = event;
- dev_hold(dev);
+ netdev_hold(dev, &inet6addr_work->dev_tracker, GFP_ATOMIC);
mlxsw_core_schedule_work(&inet6addr_work->work);
return NOTIFY_DONE;
@@ -9146,7 +9407,8 @@ static int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
if (!mlxsw_sp_rif_should_config(rif, dev, event))
goto out;
- err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack);
+ err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, false,
+ i6vi->extack);
out:
mutex_unlock(&mlxsw_sp->router->lock);
return notifier_from_errno(err);
@@ -9466,10 +9728,11 @@ static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
*/
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
if (rif)
- __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN,
+ __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, false,
extack);
- return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, extack);
+ return __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_UP, false,
+ extack);
}
static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
@@ -9480,7 +9743,7 @@ static void mlxsw_sp_port_vrf_leave(struct mlxsw_sp *mlxsw_sp,
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
if (!rif)
return;
- __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, NULL);
+ __mlxsw_sp_inetaddr_event(mlxsw_sp, l3_dev, NETDEV_DOWN, false, NULL);
}
static bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
@@ -9523,6 +9786,116 @@ mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
return err;
}
+struct mlxsw_sp_router_replay_inetaddr_up {
+ struct mlxsw_sp *mlxsw_sp;
+ struct netlink_ext_ack *extack;
+ unsigned int done;
+ bool deslavement;
+};
+
+static int mlxsw_sp_router_replay_inetaddr_up(struct net_device *dev,
+ struct netdev_nested_priv *priv)
+{
+ struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
+ bool nomaster = ctx->deslavement;
+ struct mlxsw_sp_crif *crif;
+ int err;
+
+ if (mlxsw_sp_dev_addr_list_empty(dev))
+ return 0;
+
+ crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
+ if (!crif || crif->rif)
+ return 0;
+
+ if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
+ return 0;
+
+ err = __mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_UP,
+ nomaster, ctx->extack);
+ if (err)
+ return err;
+
+ ctx->done++;
+ return 0;
+}
+
+static int mlxsw_sp_router_unreplay_inetaddr_up(struct net_device *dev,
+ struct netdev_nested_priv *priv)
+{
+ struct mlxsw_sp_router_replay_inetaddr_up *ctx = priv->data;
+ bool nomaster = ctx->deslavement;
+ struct mlxsw_sp_crif *crif;
+
+ if (!ctx->done)
+ return 0;
+
+ if (mlxsw_sp_dev_addr_list_empty(dev))
+ return 0;
+
+ crif = mlxsw_sp_crif_lookup(ctx->mlxsw_sp->router, dev);
+ if (!crif || !crif->rif)
+ return 0;
+
+ /* We are rolling back NETDEV_UP, so ask for that. */
+ if (!mlxsw_sp_rif_should_config(crif->rif, dev, NETDEV_UP))
+ return 0;
+
+ __mlxsw_sp_inetaddr_event(ctx->mlxsw_sp, dev, NETDEV_DOWN, nomaster,
+ NULL);
+
+ ctx->done--;
+ return 0;
+}
+
+int mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *upper_dev,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_router_replay_inetaddr_up ctx = {
+ .mlxsw_sp = mlxsw_sp,
+ .extack = extack,
+ .deslavement = false,
+ };
+ struct netdev_nested_priv priv = {
+ .data = &ctx,
+ };
+ int err;
+
+ err = mlxsw_sp_router_replay_inetaddr_up(upper_dev, &priv);
+ if (err)
+ return err;
+
+ err = netdev_walk_all_upper_dev_rcu(upper_dev,
+ mlxsw_sp_router_replay_inetaddr_up,
+ &priv);
+ if (err)
+ goto err_replay_up;
+
+ return 0;
+
+err_replay_up:
+ netdev_walk_all_upper_dev_rcu(upper_dev,
+ mlxsw_sp_router_unreplay_inetaddr_up,
+ &priv);
+ mlxsw_sp_router_unreplay_inetaddr_up(upper_dev, &priv);
+ return err;
+}
+
+void mlxsw_sp_netdevice_deslavement_replay(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *dev)
+{
+ struct mlxsw_sp_router_replay_inetaddr_up ctx = {
+ .mlxsw_sp = mlxsw_sp,
+ .deslavement = true,
+ };
+ struct netdev_nested_priv priv = {
+ .data = &ctx,
+ };
+
+ mlxsw_sp_router_replay_inetaddr_up(dev, &priv);
+}
+
static int
mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid, struct net_device *dev,
@@ -9539,15 +9912,84 @@ mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port *mlxsw_sp_port,
dev, extack);
}
+static void
+mlxsw_sp_port_vid_router_leave(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
+ struct net_device *dev)
+{
+ struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+
+ mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port,
+ vid);
+ if (WARN_ON(!mlxsw_sp_port_vlan))
+ return;
+
+ __mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
+}
+
static int __mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack)
{
u16 default_vid = MLXSW_SP_DEFAULT_VID;
+ struct net_device *upper_dev;
+ struct list_head *iter;
+ int done = 0;
+ u16 vid;
+ int err;
- return mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port,
- default_vid, lag_dev,
- extack);
+ err = mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port, default_vid,
+ lag_dev, extack);
+ if (err)
+ return err;
+
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ vid = vlan_dev_vlan_id(upper_dev);
+ err = mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port, vid,
+ upper_dev, extack);
+ if (err)
+ goto err_router_join_dev;
+
+ ++done;
+ }
+
+ return 0;
+
+err_router_join_dev:
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+ if (!done--)
+ break;
+
+ vid = vlan_dev_vlan_id(upper_dev);
+ mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, vid, upper_dev);
+ }
+
+ mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, default_vid, lag_dev);
+ return err;
+}
+
+static void
+__mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct net_device *lag_dev)
+{
+ u16 default_vid = MLXSW_SP_DEFAULT_VID;
+ struct net_device *upper_dev;
+ struct list_head *iter;
+ u16 vid;
+
+ netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
+ if (!is_vlan_dev(upper_dev))
+ continue;
+
+ vid = vlan_dev_vlan_id(upper_dev);
+ mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, vid, upper_dev);
+ }
+
+ mlxsw_sp_port_vid_router_leave(mlxsw_sp_port, default_vid, lag_dev);
}
int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -9563,6 +10005,14 @@ int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
return err;
}
+void mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct net_device *lag_dev)
+{
+ mutex_lock(&mlxsw_sp_port->mlxsw_sp->router->lock);
+ __mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
+ mutex_unlock(&mlxsw_sp_port->mlxsw_sp->router->lock);
+}
+
static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
@@ -9608,6 +10058,40 @@ out:
return notifier_from_errno(err);
}
+struct mlxsw_sp_macvlan_replay {
+ struct mlxsw_sp *mlxsw_sp;
+ struct netlink_ext_ack *extack;
+};
+
+static int mlxsw_sp_macvlan_replay_upper(struct net_device *dev,
+ struct netdev_nested_priv *priv)
+{
+ const struct mlxsw_sp_macvlan_replay *rms = priv->data;
+ struct netlink_ext_ack *extack = rms->extack;
+ struct mlxsw_sp *mlxsw_sp = rms->mlxsw_sp;
+
+ if (!netif_is_macvlan(dev))
+ return 0;
+
+ return mlxsw_sp_rif_macvlan_add(mlxsw_sp, dev, extack);
+}
+
+static int mlxsw_sp_macvlan_replay(struct mlxsw_sp_rif *rif,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_macvlan_replay rms = {
+ .mlxsw_sp = rif->mlxsw_sp,
+ .extack = extack,
+ };
+ struct netdev_nested_priv priv = {
+ .data = &rms,
+ };
+
+ return netdev_walk_all_upper_dev_rcu(mlxsw_sp_rif_dev(rif),
+ mlxsw_sp_macvlan_replay_upper,
+ &priv);
+}
+
static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev,
struct netdev_nested_priv *priv)
{
@@ -9630,7 +10114,6 @@ static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
if (!netif_is_macvlan_port(dev))
return 0;
- netdev_warn(dev, "Router interface is deleted. Upper macvlans will not work\n");
return netdev_walk_all_upper_dev_rcu(dev,
__mlxsw_sp_rif_macvlan_flush, &priv);
}
@@ -9688,6 +10171,10 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
if (err)
goto err_rif_subport_op;
+ err = mlxsw_sp_macvlan_replay(rif, extack);
+ if (err)
+ goto err_macvlan_replay;
+
err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), true);
if (err)
@@ -9703,6 +10190,8 @@ err_fid_rif_set:
mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), false);
err_rif_fdb_op:
+ mlxsw_sp_rif_macvlan_flush(rif);
+err_macvlan_replay:
mlxsw_sp_rif_subport_op(rif, false);
err_rif_subport_op:
mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, mac_profile);
@@ -9724,6 +10213,7 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
static struct mlxsw_sp_fid *
mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
@@ -9788,6 +10278,10 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
if (err)
goto err_fid_bc_flood_set;
+ err = mlxsw_sp_macvlan_replay(rif, extack);
+ if (err)
+ goto err_macvlan_replay;
+
err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), true);
if (err)
@@ -9803,6 +10297,8 @@ err_fid_rif_set:
mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), false);
err_rif_fdb_op:
+ mlxsw_sp_rif_macvlan_flush(rif);
+err_macvlan_replay:
mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
mlxsw_sp_router_port(mlxsw_sp), false);
err_fid_bc_flood_set:
@@ -9836,6 +10332,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
static struct mlxsw_sp_fid *
mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
int rif_ifindex = mlxsw_sp_rif_dev_ifindex(rif);
@@ -9869,27 +10366,22 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
static struct mlxsw_sp_fid *
mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif,
+ const struct mlxsw_sp_rif_params *params,
struct netlink_ext_ack *extack)
{
struct net_device *dev = mlxsw_sp_rif_dev(rif);
struct net_device *br_dev;
- u16 vid;
- int err;
+
+ if (WARN_ON(!params->vid))
+ return ERR_PTR(-EINVAL);
if (is_vlan_dev(dev)) {
- vid = vlan_dev_vlan_id(dev);
br_dev = vlan_dev_real_dev(dev);
if (WARN_ON(!netif_is_bridge_master(br_dev)))
return ERR_PTR(-EINVAL);
- } else {
- err = br_vlan_get_pvid(dev, &vid);
- if (err < 0 || !vid) {
- NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID");
- return ERR_PTR(-EINVAL);
- }
}
- return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
+ return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, params->vid);
}
static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
@@ -9954,6 +10446,10 @@ static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid,
if (err)
goto err_fid_bc_flood_set;
+ err = mlxsw_sp_macvlan_replay(rif, extack);
+ if (err)
+ goto err_macvlan_replay;
+
err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), true);
if (err)
@@ -9969,6 +10465,8 @@ err_fid_rif_set:
mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr,
mlxsw_sp_fid_index(rif->fid), false);
err_rif_fdb_op:
+ mlxsw_sp_rif_macvlan_flush(rif);
+err_macvlan_replay:
mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
mlxsw_sp_router_port(mlxsw_sp), false);
err_fid_bc_flood_set:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
index 9a2669a08480..ed3b628caafe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
@@ -171,8 +171,19 @@ int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp);
struct net_device *
mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev);
+int mlxsw_sp_router_bridge_vlan_add(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *dev,
+ u16 new_vid, bool is_pvid,
+ struct netlink_ext_ack *extack);
int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev,
struct netlink_ext_ack *extack);
+void mlxsw_sp_router_port_leave_lag(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct net_device *lag_dev);
+int mlxsw_sp_netdevice_enslavement_replay(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *upper_dev,
+ struct netlink_ext_ack *extack);
+void mlxsw_sp_netdevice_deslavement_replay(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *dev);
#endif /* _MLXSW_ROUTER_H_*/
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
index 82e711afb02b..c59b5f11f357 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
@@ -93,13 +93,8 @@ void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp);
struct mlxsw_sp_span_entry *
mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp,
const struct net_device *to_dev);
-
void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_span_entry *span_entry);
-
-int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu);
-void mlxsw_sp_span_speed_update_work(struct work_struct *work);
-
int mlxsw_sp_span_agent_get(struct mlxsw_sp *mlxsw_sp, int *p_span_id,
const struct mlxsw_sp_span_agent_parms *parms);
void mlxsw_sp_span_agent_put(struct mlxsw_sp *mlxsw_sp, int span_id);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index d88e62bc759f..6c749c148148 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -384,6 +384,91 @@ mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge,
return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
}
+static int mlxsw_sp_port_obj_add(struct net_device *dev, const void *ctx,
+ const struct switchdev_obj *obj,
+ struct netlink_ext_ack *extack);
+static int mlxsw_sp_port_obj_del(struct net_device *dev, const void *ctx,
+ const struct switchdev_obj *obj);
+
+struct mlxsw_sp_bridge_port_replay_switchdev_objs {
+ struct net_device *brport_dev;
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ int done;
+};
+
+static int
+mlxsw_sp_bridge_port_replay_switchdev_objs(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct switchdev_notifier_port_obj_info *port_obj_info = ptr;
+ struct netlink_ext_ack *extack = port_obj_info->info.extack;
+ struct mlxsw_sp_bridge_port_replay_switchdev_objs *rso;
+ int err = 0;
+
+ rso = (void *)port_obj_info->info.ctx;
+
+ if (event != SWITCHDEV_PORT_OBJ_ADD ||
+ dev != rso->brport_dev)
+ goto out;
+
+ /* When a port is joining the bridge through a LAG, there likely are
+ * VLANs configured on that LAG already. The replay will thus attempt to
+ * have the given port-vlans join the corresponding FIDs. But the LAG
+ * netdevice has already called the ndo_vlan_rx_add_vid NDO for its VLAN
+ * memberships, back before CHANGEUPPER was distributed and netdevice
+ * master set. So now before propagating the VLAN events further, we
+ * first need to kill the corresponding VID at the mlxsw_sp_port.
+ *
+ * Note that this doesn't need to be rolled back on failure -- if the
+ * replay fails, the enslavement is off, and the VIDs would be killed by
+ * LAG anyway as part of its rollback.
+ */
+ if (port_obj_info->obj->id == SWITCHDEV_OBJ_ID_PORT_VLAN) {
+ u16 vid = SWITCHDEV_OBJ_PORT_VLAN(port_obj_info->obj)->vid;
+
+ err = mlxsw_sp_port_kill_vid(rso->mlxsw_sp_port->dev, 0, vid);
+ if (err)
+ goto out;
+ }
+
+ ++rso->done;
+ err = mlxsw_sp_port_obj_add(rso->mlxsw_sp_port->dev, NULL,
+ port_obj_info->obj, extack);
+
+out:
+ return notifier_from_errno(err);
+}
+
+static struct notifier_block mlxsw_sp_bridge_port_replay_switchdev_objs_nb = {
+ .notifier_call = mlxsw_sp_bridge_port_replay_switchdev_objs,
+};
+
+static int
+mlxsw_sp_bridge_port_unreplay_switchdev_objs(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct switchdev_notifier_port_obj_info *port_obj_info = ptr;
+ struct mlxsw_sp_bridge_port_replay_switchdev_objs *rso;
+
+ rso = (void *)port_obj_info->info.ctx;
+
+ if (event != SWITCHDEV_PORT_OBJ_ADD ||
+ dev != rso->brport_dev)
+ return NOTIFY_DONE;
+ if (!rso->done--)
+ return NOTIFY_STOP;
+
+ mlxsw_sp_port_obj_del(rso->mlxsw_sp_port->dev, NULL,
+ port_obj_info->obj);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mlxsw_sp_bridge_port_unreplay_switchdev_objs_nb = {
+ .notifier_call = mlxsw_sp_bridge_port_unreplay_switchdev_objs,
+};
+
static struct mlxsw_sp_bridge_port *
mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
struct net_device *brport_dev,
@@ -405,7 +490,7 @@ mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
bridge_port->system_port = mlxsw_sp_port->local_port;
bridge_port->dev = brport_dev;
bridge_port->bridge_device = bridge_device;
- bridge_port->stp_state = BR_STATE_DISABLED;
+ bridge_port->stp_state = br_port_get_stp_state(brport_dev);
bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC |
BR_MCAST_FLOOD;
INIT_LIST_HEAD(&bridge_port->vlans_list);
@@ -1479,29 +1564,15 @@ err_port_vlan_set:
}
static int
-mlxsw_sp_br_ban_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,
- const struct net_device *br_dev,
- const struct switchdev_obj_port_vlan *vlan)
+mlxsw_sp_br_rif_pvid_change(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *br_dev,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct netlink_ext_ack *extack)
{
- u16 pvid;
-
- pvid = mlxsw_sp_rif_vid(mlxsw_sp, br_dev);
- if (!pvid)
- return 0;
-
- if (vlan->flags & BRIDGE_VLAN_INFO_PVID) {
- if (vlan->vid != pvid) {
- netdev_err(br_dev, "Can't change PVID, it's used by router interface\n");
- return -EBUSY;
- }
- } else {
- if (vlan->vid == pvid) {
- netdev_err(br_dev, "Can't remove PVID, it's used by router interface\n");
- return -EBUSY;
- }
- }
+ bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
- return 0;
+ return mlxsw_sp_router_bridge_vlan_add(mlxsw_sp, br_dev, vlan->vid,
+ flag_pvid, extack);
}
static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -1518,8 +1589,8 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
int err = 0;
if (br_vlan_enabled(orig_dev))
- err = mlxsw_sp_br_ban_rif_pvid_change(mlxsw_sp,
- orig_dev, vlan);
+ err = mlxsw_sp_br_rif_pvid_change(mlxsw_sp, orig_dev,
+ vlan, extack);
if (!err)
err = -EOPNOTSUPP;
return err;
@@ -2365,6 +2436,33 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,
}
static int
+mlxsw_sp_bridge_port_replay(struct mlxsw_sp_bridge_port *bridge_port,
+ struct mlxsw_sp_port *mlxsw_sp_port,
+ struct netlink_ext_ack *extack)
+{
+ struct mlxsw_sp_bridge_port_replay_switchdev_objs rso = {
+ .brport_dev = bridge_port->dev,
+ .mlxsw_sp_port = mlxsw_sp_port,
+ };
+ struct notifier_block *nb;
+ int err;
+
+ nb = &mlxsw_sp_bridge_port_replay_switchdev_objs_nb;
+ err = switchdev_bridge_port_replay(bridge_port->dev, mlxsw_sp_port->dev,
+ &rso, NULL, nb, extack);
+ if (err)
+ goto err_replay;
+
+ return 0;
+
+err_replay:
+ nb = &mlxsw_sp_bridge_port_unreplay_switchdev_objs_nb;
+ switchdev_bridge_port_replay(bridge_port->dev, mlxsw_sp_port->dev,
+ &rso, NULL, nb, extack);
+ return err;
+}
+
+static int
mlxsw_sp_bridge_vlan_aware_port_join(struct mlxsw_sp_bridge_port *bridge_port,
struct mlxsw_sp_port *mlxsw_sp_port,
struct netlink_ext_ack *extack)
@@ -2378,7 +2476,7 @@ mlxsw_sp_bridge_vlan_aware_port_join(struct mlxsw_sp_bridge_port *bridge_port,
if (mlxsw_sp_port->default_vlan->fid)
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);
- return 0;
+ return mlxsw_sp_bridge_port_replay(bridge_port, mlxsw_sp_port, extack);
}
static int
@@ -2550,6 +2648,7 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
struct net_device *dev = bridge_port->dev;
u16 vid;
+ int err;
vid = is_vlan_dev(dev) ? vlan_dev_vlan_id(dev) : MLXSW_SP_DEFAULT_VID;
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
@@ -2565,8 +2664,20 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
if (mlxsw_sp_port_vlan->fid)
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
- return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port,
- extack);
+ err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port,
+ extack);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_bridge_port_replay(bridge_port, mlxsw_sp_port, extack);
+ if (err)
+ goto err_replay;
+
+ return 0;
+
+err_replay:
+ mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
+ return err;
}
static void
@@ -2783,8 +2894,15 @@ int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
if (err)
goto err_port_join;
+ err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, br_dev, extack);
+ if (err)
+ goto err_replay;
+
return 0;
+err_replay:
+ bridge_device->ops->port_leave(bridge_device, bridge_port,
+ mlxsw_sp_port);
err_port_join:
mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
return err;
@@ -2948,9 +3066,6 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
goto just_remove;
}
- if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
- goto just_remove;
-
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
if (!mlxsw_sp_port_vlan) {
netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
@@ -3018,9 +3133,6 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
goto just_remove;
}
- if (mlxsw_sp_fid_is_dummy(mlxsw_sp, fid))
- goto just_remove;
-
mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
if (!mlxsw_sp_port_vlan) {
netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
@@ -3262,6 +3374,7 @@ out:
struct mlxsw_sp_switchdev_event_work {
struct work_struct work;
+ netdevice_tracker dev_tracker;
union {
struct switchdev_notifier_fdb_info fdb_info;
struct switchdev_notifier_vxlan_fdb_info vxlan_fdb_info;
@@ -3418,8 +3531,8 @@ static void mlxsw_sp_switchdev_bridge_fdb_event_work(struct work_struct *work)
out:
rtnl_unlock();
kfree(switchdev_work->fdb_info.addr);
+ netdev_put(dev, &switchdev_work->dev_tracker);
kfree(switchdev_work);
- dev_put(dev);
}
static void
@@ -3430,7 +3543,6 @@ mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp,
struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
struct mlxsw_sp_bridge_device *bridge_device;
struct net_device *dev = switchdev_work->dev;
- u8 all_zeros_mac[ETH_ALEN] = { 0 };
enum mlxsw_sp_l3proto proto;
union mlxsw_sp_l3addr addr;
struct net_device *br_dev;
@@ -3452,7 +3564,7 @@ mlxsw_sp_switchdev_vxlan_fdb_add(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
&proto, &addr);
- if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
+ if (is_zero_ether_addr(vxlan_fdb_info->eth_addr)) {
err = mlxsw_sp_nve_flood_ip_add(mlxsw_sp, fid, proto, &addr);
if (err) {
mlxsw_sp_fid_put(fid);
@@ -3504,7 +3616,6 @@ mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_bridge_device *bridge_device;
struct net_device *dev = switchdev_work->dev;
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
- u8 all_zeros_mac[ETH_ALEN] = { 0 };
enum mlxsw_sp_l3proto proto;
union mlxsw_sp_l3addr addr;
struct mlxsw_sp_fid *fid;
@@ -3525,7 +3636,7 @@ mlxsw_sp_switchdev_vxlan_fdb_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_switchdev_vxlan_addr_convert(&vxlan_fdb_info->remote_ip,
&proto, &addr);
- if (ether_addr_equal(vxlan_fdb_info->eth_addr, all_zeros_mac)) {
+ if (is_zero_ether_addr(vxlan_fdb_info->eth_addr)) {
mlxsw_sp_nve_flood_ip_del(mlxsw_sp, fid, proto, &addr);
mlxsw_sp_fid_put(fid);
return;
@@ -3574,8 +3685,8 @@ static void mlxsw_sp_switchdev_vxlan_fdb_event_work(struct work_struct *work)
out:
rtnl_unlock();
+ netdev_put(dev, &switchdev_work->dev_tracker);
kfree(switchdev_work);
- dev_put(dev);
}
static int
@@ -3675,7 +3786,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
* upper device containig mlxsw_sp_port or just a
* mlxsw_sp_port
*/
- dev_hold(dev);
+ netdev_hold(dev, &switchdev_work->dev_tracker, GFP_ATOMIC);
break;
case SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE:
case SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE:
@@ -3685,7 +3796,7 @@ static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
info);
if (err)
goto err_vxlan_work_prepare;
- dev_hold(dev);
+ netdev_hold(dev, &switchdev_work->dev_tracker, GFP_ATOMIC);
break;
default:
kfree(switchdev_work);
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index a36f6369f132..c81cdeb4d4e7 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1515,7 +1515,7 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter)
&fphy_status, NULL);
if (IS_ERR(phydev)) {
netdev_err(netdev, "No PHY/fixed_PHY found\n");
- return -EIO;
+ return PTR_ERR(phydev);
}
} else {
goto return_error;
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
index bd72fbc2220f..3960534ac2ad 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
@@ -2,6 +2,7 @@
#include <linux/bpf.h>
#include <linux/filter.h>
+#include <net/page_pool/helpers.h>
#include "lan966x_main.h"
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index fbb0bb4594cd..0d6e79af2410 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -5,9 +5,10 @@
#include <linux/if_vlan.h>
#include <linux/iopoll.h>
#include <linux/ip.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <net/addrconf.h>
@@ -449,39 +450,46 @@ static int lan966x_port_get_parent_id(struct net_device *dev,
return 0;
}
-static int lan966x_port_ioctl(struct net_device *dev, struct ifreq *ifr,
- int cmd)
+static int lan966x_port_hwtstamp_get(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg)
+{
+ struct lan966x_port *port = netdev_priv(dev);
+
+ if (!port->lan966x->ptp)
+ return -EOPNOTSUPP;
+
+ lan966x_ptp_hwtstamp_get(port, cfg);
+
+ return 0;
+}
+
+static int lan966x_port_hwtstamp_set(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct lan966x_port *port = netdev_priv(dev);
int err;
- if (cmd == SIOCSHWTSTAMP) {
- err = lan966x_ptp_setup_traps(port, ifr);
- if (err)
- return err;
- }
+ if (cfg->source != HWTSTAMP_SOURCE_NETDEV &&
+ cfg->source != HWTSTAMP_SOURCE_PHYLIB)
+ return -EOPNOTSUPP;
- if (!phy_has_hwtstamp(dev->phydev) && port->lan966x->ptp) {
- switch (cmd) {
- case SIOCSHWTSTAMP:
- err = lan966x_ptp_hwtstamp_set(port, ifr);
- if (err)
- lan966x_ptp_del_traps(port);
+ err = lan966x_ptp_setup_traps(port, cfg);
+ if (err)
+ return err;
+ if (cfg->source == HWTSTAMP_SOURCE_NETDEV) {
+ if (!port->lan966x->ptp)
+ return -EOPNOTSUPP;
+
+ err = lan966x_ptp_hwtstamp_set(port, cfg, extack);
+ if (err) {
+ lan966x_ptp_del_traps(port);
return err;
- case SIOCGHWTSTAMP:
- return lan966x_ptp_hwtstamp_get(port, ifr);
}
}
- if (!dev->phydev)
- return -ENODEV;
-
- err = phy_mii_ioctl(dev->phydev, ifr, cmd);
- if (err && cmd == SIOCSHWTSTAMP)
- lan966x_ptp_del_traps(port);
-
- return err;
+ return 0;
}
static const struct net_device_ops lan966x_port_netdev_ops = {
@@ -494,10 +502,12 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
.ndo_get_stats64 = lan966x_stats_get,
.ndo_set_mac_address = lan966x_port_set_mac_address,
.ndo_get_port_parent_id = lan966x_port_get_parent_id,
- .ndo_eth_ioctl = lan966x_port_ioctl,
+ .ndo_eth_ioctl = phy_do_ioctl,
.ndo_setup_tc = lan966x_tc_setup,
.ndo_bpf = lan966x_xdp,
.ndo_xdp_xmit = lan966x_xdp_xmit,
+ .ndo_hwtstamp_get = lan966x_port_hwtstamp_get,
+ .ndo_hwtstamp_set = lan966x_port_hwtstamp_set,
};
bool lan966x_netdevice_check(const struct net_device *dev)
@@ -807,6 +817,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
NETIF_F_HW_VLAN_STAG_TX |
NETIF_F_HW_TC;
dev->hw_features |= NETIF_F_HW_TC;
+ dev->priv_flags |= IFF_SEE_ALL_HWTSTAMP_REQUESTS;
dev->needed_headroom = IFH_LEN_BYTES;
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
@@ -1108,8 +1119,8 @@ static int lan966x_probe(struct platform_device *pdev)
/* set irq */
lan966x->xtr_irq = platform_get_irq_byname(pdev, "xtr");
- if (lan966x->xtr_irq <= 0)
- return -EINVAL;
+ if (lan966x->xtr_irq < 0)
+ return lan966x->xtr_irq;
err = devm_request_threaded_irq(&pdev->dev, lan966x->xtr_irq, NULL,
lan966x_xtr_irq_handler, IRQF_ONESHOT,
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 27f272831ea5..caa9e0533c96 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -10,10 +10,11 @@
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/ptp_clock_kernel.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include <net/switchdev.h>
+#include <net/xdp.h>
#include <vcap_api.h>
#include <vcap_api_client.h>
@@ -298,7 +299,7 @@ struct lan966x_phc {
struct ptp_clock *clock;
struct ptp_clock_info info;
struct ptp_pin_desc pins[LAN966X_PHC_PINS_NUM];
- struct hwtstamp_config hwtstamp_config;
+ struct kernel_hwtstamp_config hwtstamp_config;
struct lan966x *lan966x;
u8 index;
};
@@ -578,8 +579,11 @@ void lan966x_mdb_restore_entries(struct lan966x *lan966x);
int lan966x_ptp_init(struct lan966x *lan966x);
void lan966x_ptp_deinit(struct lan966x *lan966x);
-int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr);
-int lan966x_ptp_hwtstamp_get(struct lan966x_port *port, struct ifreq *ifr);
+int lan966x_ptp_hwtstamp_set(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack);
+void lan966x_ptp_hwtstamp_get(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg);
void lan966x_ptp_rxtstamp(struct lan966x *lan966x, struct sk_buff *skb,
u64 src_port, u64 timestamp);
int lan966x_ptp_txtstamp_request(struct lan966x_port *port,
@@ -590,7 +594,8 @@ irqreturn_t lan966x_ptp_irq_handler(int irq, void *args);
irqreturn_t lan966x_ptp_ext_irq_handler(int irq, void *args);
u32 lan966x_ptp_get_period_ps(void);
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
-int lan966x_ptp_setup_traps(struct lan966x_port *port, struct ifreq *ifr);
+int lan966x_ptp_setup_traps(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg);
int lan966x_ptp_del_traps(struct lan966x_port *port);
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
index 266a21a2d124..63905bb5a63a 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
@@ -59,7 +59,7 @@ static int lan966x_ptp_add_trap(struct lan966x_port *port,
int err;
vrule = vcap_get_rule(lan966x->vcap_ctrl, rule_id);
- if (vrule) {
+ if (!IS_ERR(vrule)) {
u32 value, mask;
/* Just modify the ingress port mask and exit */
@@ -106,7 +106,7 @@ static int lan966x_ptp_del_trap(struct lan966x_port *port,
int err;
vrule = vcap_get_rule(lan966x->vcap_ctrl, rule_id);
- if (!vrule)
+ if (IS_ERR(vrule))
return -EEXIST;
vcap_rule_get_key_u32(vrule, VCAP_KF_IF_IGR_PORT_MASK, &value, &mask);
@@ -248,29 +248,23 @@ int lan966x_ptp_del_traps(struct lan966x_port *port)
return err;
}
-int lan966x_ptp_setup_traps(struct lan966x_port *port, struct ifreq *ifr)
+int lan966x_ptp_setup_traps(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg)
{
- struct hwtstamp_config cfg;
-
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- if (cfg.rx_filter == HWTSTAMP_FILTER_NONE)
+ if (cfg->rx_filter == HWTSTAMP_FILTER_NONE)
return lan966x_ptp_del_traps(port);
else
return lan966x_ptp_add_traps(port);
}
-int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
+int lan966x_ptp_hwtstamp_set(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct lan966x *lan966x = port->lan966x;
- struct hwtstamp_config cfg;
struct lan966x_phc *phc;
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- switch (cfg.tx_type) {
+ switch (cfg->tx_type) {
case HWTSTAMP_TX_ON:
port->ptp_tx_cmd = IFH_REW_OP_TWO_STEP_PTP;
break;
@@ -284,7 +278,7 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
return -ERANGE;
}
- switch (cfg.rx_filter) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
port->ptp_rx_cmd = false;
break;
@@ -303,7 +297,7 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
port->ptp_rx_cmd = true;
- cfg.rx_filter = HWTSTAMP_FILTER_ALL;
+ cfg->rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
@@ -312,20 +306,20 @@ int lan966x_ptp_hwtstamp_set(struct lan966x_port *port, struct ifreq *ifr)
/* Commit back the result & save it */
mutex_lock(&lan966x->ptp_lock);
phc = &lan966x->phc[LAN966X_PHC_PORT];
- memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg));
+ phc->hwtstamp_config = *cfg;
mutex_unlock(&lan966x->ptp_lock);
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
-int lan966x_ptp_hwtstamp_get(struct lan966x_port *port, struct ifreq *ifr)
+void lan966x_ptp_hwtstamp_get(struct lan966x_port *port,
+ struct kernel_hwtstamp_config *cfg)
{
struct lan966x *lan966x = port->lan966x;
struct lan966x_phc *phc;
phc = &lan966x->phc[LAN966X_PHC_PORT];
- return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config,
- sizeof(phc->hwtstamp_config)) ? -EFAULT : 0;
+ *cfg = phc->hwtstamp_config;
}
static int lan966x_ptp_classify(struct lan966x_port *port, struct sk_buff *skb)
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c
index 96b3def6c474..d696cf9dbd19 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c
@@ -75,7 +75,7 @@ lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
return err;
@@ -172,7 +172,7 @@ lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
}
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
index 62c85463b634..6f565c0c0c3d 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -205,7 +205,7 @@ enum sparx5_core_clockfreq {
struct sparx5_phc {
struct ptp_clock *clock;
struct ptp_clock_info info;
- struct hwtstamp_config hwtstamp_config;
+ struct kernel_hwtstamp_config hwtstamp_config;
struct sparx5 *sparx5;
u8 index;
};
@@ -388,8 +388,11 @@ void sparx5_unregister_netdevs(struct sparx5 *sparx5);
/* sparx5_ptp.c */
int sparx5_ptp_init(struct sparx5 *sparx5);
void sparx5_ptp_deinit(struct sparx5 *sparx5);
-int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr);
-int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr);
+int sparx5_ptp_hwtstamp_set(struct sparx5_port *port,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack);
+void sparx5_ptp_hwtstamp_get(struct sparx5_port *port,
+ struct kernel_hwtstamp_config *cfg);
void sparx5_ptp_rxtstamp(struct sparx5 *sparx5, struct sk_buff *skb,
u64 timestamp);
int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
@@ -411,7 +414,6 @@ enum sparx5_pgid_type {
};
void sparx5_pgid_init(struct sparx5 *spx5);
-int sparx5_pgid_alloc_glag(struct sparx5 *spx5, u16 *idx);
int sparx5_pgid_alloc_mcast(struct sparx5 *spx5, u16 *idx);
int sparx5_pgid_free(struct sparx5 *spx5, u16 idx);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
index d078156581d5..705a004b324f 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -210,22 +210,31 @@ static int sparx5_get_port_parent_id(struct net_device *dev,
return 0;
}
-static int sparx5_port_ioctl(struct net_device *dev, struct ifreq *ifr,
- int cmd)
+static int sparx5_port_hwtstamp_get(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg)
{
struct sparx5_port *sparx5_port = netdev_priv(dev);
struct sparx5 *sparx5 = sparx5_port->sparx5;
- if (!phy_has_hwtstamp(dev->phydev) && sparx5->ptp) {
- switch (cmd) {
- case SIOCSHWTSTAMP:
- return sparx5_ptp_hwtstamp_set(sparx5_port, ifr);
- case SIOCGHWTSTAMP:
- return sparx5_ptp_hwtstamp_get(sparx5_port, ifr);
- }
- }
+ if (!sparx5->ptp)
+ return -EOPNOTSUPP;
+
+ sparx5_ptp_hwtstamp_get(sparx5_port, cfg);
+
+ return 0;
+}
+
+static int sparx5_port_hwtstamp_set(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct sparx5_port *sparx5_port = netdev_priv(dev);
+ struct sparx5 *sparx5 = sparx5_port->sparx5;
+
+ if (!sparx5->ptp)
+ return -EOPNOTSUPP;
- return phy_mii_ioctl(dev->phydev, ifr, cmd);
+ return sparx5_ptp_hwtstamp_set(sparx5_port, cfg, extack);
}
static const struct net_device_ops sparx5_port_netdev_ops = {
@@ -238,8 +247,10 @@ static const struct net_device_ops sparx5_port_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_get_stats64 = sparx5_get_stats64,
.ndo_get_port_parent_id = sparx5_get_port_parent_id,
- .ndo_eth_ioctl = sparx5_port_ioctl,
+ .ndo_eth_ioctl = phy_do_ioctl,
.ndo_setup_tc = sparx5_port_setup_tc,
+ .ndo_hwtstamp_get = sparx5_port_hwtstamp_get,
+ .ndo_hwtstamp_set = sparx5_port_hwtstamp_set,
};
bool sparx5_netdevice_check(const struct net_device *dev)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
index 0edb98cef7e4..5a932460db58 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
@@ -74,10 +74,11 @@ static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
return res;
}
-int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
+int sparx5_ptp_hwtstamp_set(struct sparx5_port *port,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct sparx5 *sparx5 = port->sparx5;
- struct hwtstamp_config cfg;
struct sparx5_phc *phc;
/* For now don't allow to run ptp on ports that are part of a bridge,
@@ -88,10 +89,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
if (test_bit(port->portno, sparx5->bridge_mask))
return -EINVAL;
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- switch (cfg.tx_type) {
+ switch (cfg->tx_type) {
case HWTSTAMP_TX_ON:
port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
break;
@@ -105,7 +103,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
return -ERANGE;
}
- switch (cfg.rx_filter) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
@@ -122,7 +120,7 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
- cfg.rx_filter = HWTSTAMP_FILTER_ALL;
+ cfg->rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
@@ -131,20 +129,20 @@ int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr)
/* Commit back the result & save it */
mutex_lock(&sparx5->ptp_lock);
phc = &sparx5->phc[SPARX5_PHC_PORT];
- memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg));
+ phc->hwtstamp_config = *cfg;
mutex_unlock(&sparx5->ptp_lock);
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
-int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr)
+void sparx5_ptp_hwtstamp_get(struct sparx5_port *port,
+ struct kernel_hwtstamp_config *cfg)
{
struct sparx5 *sparx5 = port->sparx5;
struct sparx5_phc *phc;
phc = &sparx5->phc[SPARX5_PHC_PORT];
- return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config,
- sizeof(phc->hwtstamp_config)) ? -EFAULT : 0;
+ *cfg = phc->hwtstamp_config;
}
static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
index 3f87a5285a6d..523e0c470894 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
@@ -126,7 +126,7 @@ sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
}
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
return err;
@@ -175,7 +175,7 @@ sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
return err;
@@ -1274,7 +1274,7 @@ static int sparx5_tc_free_rule_resources(struct net_device *ndev,
int ret = 0;
vrule = vcap_get_rule(vctrl, rule_id);
- if (!vrule || IS_ERR(vrule))
+ if (IS_ERR(vrule))
return -EINVAL;
sparx5_tc_free_psfp_resources(sparx5, vrule);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index a418ad8e8770..300fe1a93dce 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -2396,7 +2396,7 @@ struct vcap_rule *vcap_decode_rule(struct vcap_rule_internal *elem)
ri = vcap_dup_rule(elem, elem->state == VCAP_RS_DISABLED);
if (IS_ERR(ri))
- return ERR_PTR(PTR_ERR(ri));
+ return ERR_CAST(ri);
if (ri->state == VCAP_RS_DISABLED)
goto out;
@@ -2429,7 +2429,7 @@ struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
elem = vcap_get_locked_rule(vctrl, id);
if (!elem)
- return NULL;
+ return ERR_PTR(-ENOENT);
rule = vcap_decode_rule(elem);
mutex_unlock(&elem->admin->lock);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h
index 62db270f65af..9eccfa633c1a 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h
@@ -277,7 +277,4 @@ struct vcap_control {
struct list_head list; /* list of vcap instances */
};
-/* Set client control interface on the API */
-int vcap_api_set_client(struct vcap_control *vctrl);
-
#endif /* __VCAP_API__ */
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
index d9d1f7c9d762..88641508f885 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
@@ -226,9 +226,6 @@ int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid);
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
/* Is this chain id the last lookup of all VCAPs */
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress);
-/* Provide all rules via a callback interface */
-int vcap_rule_iter(struct vcap_control *vctrl,
- int (*callback)(void *, struct vcap_rule *), void *arg);
/* Match a list of keys against the keysets available in a vcap type */
bool vcap_rule_find_keysets(struct vcap_rule *rule,
struct vcap_keyset_list *matches);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_tc.c b/drivers/net/ethernet/microchip/vcap/vcap_tc.c
index 09abe7944af6..27e2dffb65e6 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_tc.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_tc.c
@@ -50,7 +50,7 @@ int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS);
return err;
@@ -86,7 +86,7 @@ int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st)
}
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
return err;
@@ -124,7 +124,7 @@ int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
@@ -158,7 +158,7 @@ int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_PORTS);
return err;
@@ -201,7 +201,7 @@ int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN);
return 0;
out:
@@ -238,7 +238,7 @@ int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
if (mt.mask->vlan_tpid)
st->tpid = be16_to_cpu(mt.key->vlan_tpid);
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_VLAN);
return 0;
out:
@@ -313,7 +313,7 @@ int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_TCP);
return err;
@@ -376,7 +376,7 @@ int vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ARP);
return 0;
@@ -401,7 +401,7 @@ int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st)
goto out;
}
- st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP);
+ st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP);
return err;
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_tc.h b/drivers/net/ethernet/microchip/vcap/vcap_tc.h
index 071f892f9aa4..49b02d032906 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_tc.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_tc.h
@@ -14,7 +14,7 @@ struct vcap_tc_flower_parse_usage {
u16 l3_proto;
u8 l4_proto;
u16 tpid;
- unsigned int used_keys;
+ unsigned long long used_keys;
};
int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st);
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 8f3f78b68592..6367de0c2c2e 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -106,6 +106,25 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev)
return 0;
}
+static int mana_gd_query_hwc_timeout(struct pci_dev *pdev, u32 *timeout_val)
+{
+ struct gdma_context *gc = pci_get_drvdata(pdev);
+ struct gdma_query_hwc_timeout_resp resp = {};
+ struct gdma_query_hwc_timeout_req req = {};
+ int err;
+
+ mana_gd_init_req_hdr(&req.hdr, GDMA_QUERY_HWC_TIMEOUT,
+ sizeof(req), sizeof(resp));
+ req.timeout_ms = *timeout_val;
+ err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
+ if (err || resp.hdr.status)
+ return err ? err : -EPROTO;
+
+ *timeout_val = resp.timeout_ms;
+
+ return 0;
+}
+
static int mana_gd_detect_devices(struct pci_dev *pdev)
{
struct gdma_context *gc = pci_get_drvdata(pdev);
@@ -300,8 +319,11 @@ static void mana_gd_ring_doorbell(struct gdma_context *gc, u32 db_index,
void mana_gd_wq_ring_doorbell(struct gdma_context *gc, struct gdma_queue *queue)
{
+ /* Hardware Spec specifies that software client should set 0 for
+ * wqe_cnt for Receive Queues. This value is not used in Send Queues.
+ */
mana_gd_ring_doorbell(gc, queue->gdma_dev->doorbell, queue->type,
- queue->id, queue->head * GDMA_WQE_BU_SIZE, 1);
+ queue->id, queue->head * GDMA_WQE_BU_SIZE, 0);
}
void mana_gd_ring_cq(struct gdma_queue *cq, u8 arm_bit)
@@ -879,8 +901,10 @@ int mana_gd_verify_vf_version(struct pci_dev *pdev)
struct gdma_context *gc = pci_get_drvdata(pdev);
struct gdma_verify_ver_resp resp = {};
struct gdma_verify_ver_req req = {};
+ struct hw_channel_context *hwc;
int err;
+ hwc = gc->hwc.driver_data;
mana_gd_init_req_hdr(&req.hdr, GDMA_VERIFY_VF_DRIVER_VERSION,
sizeof(req), sizeof(resp));
@@ -907,7 +931,14 @@ int mana_gd_verify_vf_version(struct pci_dev *pdev)
err, resp.hdr.status);
return err ? err : -EPROTO;
}
-
+ if (resp.pf_cap_flags1 & GDMA_DRV_CAP_FLAG_1_HWC_TIMEOUT_RECONFIG) {
+ err = mana_gd_query_hwc_timeout(pdev, &hwc->hwc_timeout);
+ if (err) {
+ dev_err(gc->dev, "Failed to set the hwc timeout %d\n", err);
+ return err;
+ }
+ dev_dbg(gc->dev, "set the hwc timeout to %u\n", hwc->hwc_timeout);
+ }
return 0;
}
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 2bd1d74021f7..9d1cd3bfcf66 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -174,7 +174,25 @@ static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self,
complete(&hwc->hwc_init_eqe_comp);
break;
+ case GDMA_EQE_HWC_SOC_RECONFIG_DATA:
+ type_data.as_uint32 = event->details[0];
+ type = type_data.type;
+ val = type_data.value;
+
+ switch (type) {
+ case HWC_DATA_CFG_HWC_TIMEOUT:
+ hwc->hwc_timeout = val;
+ break;
+
+ default:
+ dev_warn(hwc->dev, "Received unknown reconfig type %u\n", type);
+ break;
+ }
+
+ break;
+
default:
+ dev_warn(hwc->dev, "Received unknown gdma event %u\n", event->type);
/* Ignore unknown events, which should never happen. */
break;
}
@@ -696,6 +714,7 @@ int mana_hwc_create_channel(struct gdma_context *gc)
gd->driver_data = hwc;
hwc->gdma_dev = gd;
hwc->dev = gc->dev;
+ hwc->hwc_timeout = HW_CHANNEL_WAIT_RESOURCE_TIMEOUT_MS;
/* HWC's instance number is always 0. */
gd->dev_id.as_uint32 = 0;
@@ -770,6 +789,8 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
hwc->gdma_dev->doorbell = INVALID_DOORBELL;
hwc->gdma_dev->pdid = INVALID_PDID;
+ hwc->hwc_timeout = 0;
+
kfree(hwc);
gc->hwc.driver_data = NULL;
gc->hwc.gdma_context = NULL;
@@ -825,7 +846,8 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
goto out;
}
- if (!wait_for_completion_timeout(&ctx->comp_event, 30 * HZ)) {
+ if (!wait_for_completion_timeout(&ctx->comp_event,
+ (msecs_to_jiffies(hwc->hwc_timeout) * HZ))) {
dev_err(hwc->dev, "HWC: Request timed out!\n");
err = -ETIMEDOUT;
goto out;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index c2ad0921e893..4a16ebff3d1d 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -12,6 +12,8 @@
#include <net/checksum.h>
#include <net/ip6_checksum.h>
+#include <net/page_pool/helpers.h>
+#include <net/xdp.h>
#include <net/mana/mana.h>
#include <net/mana/mana_auxiliary.h>
@@ -1387,8 +1389,8 @@ static void mana_post_pkt_rxq(struct mana_rxq *rxq)
recv_buf_oob = &rxq->rx_oobs[curr_index];
- err = mana_gd_post_and_ring(rxq->gdma_rq, &recv_buf_oob->wqe_req,
- &recv_buf_oob->wqe_inf);
+ err = mana_gd_post_work_request(rxq->gdma_rq, &recv_buf_oob->wqe_req,
+ &recv_buf_oob->wqe_inf);
if (WARN_ON_ONCE(err))
return;
@@ -1415,8 +1417,8 @@ static struct sk_buff *mana_build_skb(struct mana_rxq *rxq, void *buf_va,
return skb;
}
-static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
- struct mana_rxq *rxq)
+static void mana_rx_skb(void *buf_va, bool from_pool,
+ struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq)
{
struct mana_stats_rx *rx_stats = &rxq->stats;
struct net_device *ndev = rxq->ndev;
@@ -1449,6 +1451,9 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
if (!skb)
goto drop;
+ if (from_pool)
+ skb_mark_for_recycle(skb);
+
skb->dev = napi->dev;
skb->protocol = eth_type_trans(skb, ndev);
@@ -1499,9 +1504,14 @@ drop_xdp:
u64_stats_update_end(&rx_stats->syncp);
drop:
- WARN_ON_ONCE(rxq->xdp_save_va);
- /* Save for reuse */
- rxq->xdp_save_va = buf_va;
+ if (from_pool) {
+ page_pool_recycle_direct(rxq->page_pool,
+ virt_to_head_page(buf_va));
+ } else {
+ WARN_ON_ONCE(rxq->xdp_save_va);
+ /* Save for reuse */
+ rxq->xdp_save_va = buf_va;
+ }
++ndev->stats.rx_dropped;
@@ -1509,11 +1519,13 @@ drop:
}
static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
- dma_addr_t *da, bool is_napi)
+ dma_addr_t *da, bool *from_pool, bool is_napi)
{
struct page *page;
void *va;
+ *from_pool = false;
+
/* Reuse XDP dropped page if available */
if (rxq->xdp_save_va) {
va = rxq->xdp_save_va;
@@ -1534,17 +1546,22 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
return NULL;
}
} else {
- page = dev_alloc_page();
+ page = page_pool_dev_alloc_pages(rxq->page_pool);
if (!page)
return NULL;
+ *from_pool = true;
va = page_to_virt(page);
}
*da = dma_map_single(dev, va + rxq->headroom, rxq->datasize,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, *da)) {
- put_page(virt_to_head_page(va));
+ if (*from_pool)
+ page_pool_put_full_page(rxq->page_pool, page, false);
+ else
+ put_page(virt_to_head_page(va));
+
return NULL;
}
@@ -1553,21 +1570,25 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
/* Allocate frag for rx buffer, and save the old buf */
static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
- struct mana_recv_buf_oob *rxoob, void **old_buf)
+ struct mana_recv_buf_oob *rxoob, void **old_buf,
+ bool *old_fp)
{
+ bool from_pool;
dma_addr_t da;
void *va;
- va = mana_get_rxfrag(rxq, dev, &da, true);
+ va = mana_get_rxfrag(rxq, dev, &da, &from_pool, true);
if (!va)
return;
dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize,
DMA_FROM_DEVICE);
*old_buf = rxoob->buf_va;
+ *old_fp = rxoob->from_pool;
rxoob->buf_va = va;
rxoob->sgl[0].address = da;
+ rxoob->from_pool = from_pool;
}
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
@@ -1581,6 +1602,7 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
struct device *dev = gc->dev;
void *old_buf = NULL;
u32 curr, pktlen;
+ bool old_fp;
apc = netdev_priv(ndev);
@@ -1623,12 +1645,12 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
rxbuf_oob = &rxq->rx_oobs[curr];
WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
- mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf);
+ mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp);
/* Unsuccessful refill will have old_buf == NULL.
* In this case, mana_rx_skb() will drop the packet.
*/
- mana_rx_skb(old_buf, oob, rxq);
+ mana_rx_skb(old_buf, old_fp, oob, rxq);
drop:
mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu);
@@ -1658,6 +1680,12 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
mana_process_rx_cqe(rxq, cq, &comp[i]);
}
+ if (comp_read > 0) {
+ struct gdma_context *gc = rxq->gdma_rq->gdma_dev->gdma_context;
+
+ mana_gd_wq_ring_doorbell(gc, rxq->gdma_rq);
+ }
+
if (rxq->xdp_flush)
xdp_do_flush();
}
@@ -1882,6 +1910,7 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
struct mana_recv_buf_oob *rx_oob;
struct device *dev = gc->dev;
struct napi_struct *napi;
+ struct page *page;
int i;
if (!rxq)
@@ -1914,10 +1943,18 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
dma_unmap_single(dev, rx_oob->sgl[0].address,
rx_oob->sgl[0].size, DMA_FROM_DEVICE);
- put_page(virt_to_head_page(rx_oob->buf_va));
+ page = virt_to_head_page(rx_oob->buf_va);
+
+ if (rx_oob->from_pool)
+ page_pool_put_full_page(rxq->page_pool, page, false);
+ else
+ put_page(page);
+
rx_oob->buf_va = NULL;
}
+ page_pool_destroy(rxq->page_pool);
+
if (rxq->gdma_rq)
mana_gd_destroy_queue(gc, rxq->gdma_rq);
@@ -1928,18 +1965,20 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
struct mana_rxq *rxq, struct device *dev)
{
struct mana_port_context *mpc = netdev_priv(rxq->ndev);
+ bool from_pool = false;
dma_addr_t da;
void *va;
if (mpc->rxbufs_pre)
va = mana_get_rxbuf_pre(rxq, &da);
else
- va = mana_get_rxfrag(rxq, dev, &da, false);
+ va = mana_get_rxfrag(rxq, dev, &da, &from_pool, false);
if (!va)
return -ENOMEM;
rx_oob->buf_va = va;
+ rx_oob->from_pool = from_pool;
rx_oob->sgl[0].address = da;
rx_oob->sgl[0].size = rxq->datasize;
@@ -2009,6 +2048,26 @@ static int mana_push_wqe(struct mana_rxq *rxq)
return 0;
}
+static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc)
+{
+ struct page_pool_params pprm = {};
+ int ret;
+
+ pprm.pool_size = RX_BUFFERS_PER_QUEUE;
+ pprm.nid = gc->numa_node;
+ pprm.napi = &rxq->rx_cq.napi;
+
+ rxq->page_pool = page_pool_create(&pprm);
+
+ if (IS_ERR(rxq->page_pool)) {
+ ret = PTR_ERR(rxq->page_pool);
+ rxq->page_pool = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
u32 rxq_idx, struct mana_eq *eq,
struct net_device *ndev)
@@ -2038,6 +2097,13 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
mana_get_rxbuf_cfg(ndev->mtu, &rxq->datasize, &rxq->alloc_size,
&rxq->headroom);
+ /* Create page pool for RX queue */
+ err = mana_create_page_pool(rxq, gc);
+ if (err) {
+ netdev_err(ndev, "Create page pool err:%d\n", err);
+ goto out;
+ }
+
err = mana_alloc_rx_wqe(apc, rxq, &rq_size, &cq_size);
if (err)
goto out;
@@ -2109,8 +2175,8 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
WARN_ON(xdp_rxq_info_reg(&rxq->xdp_rxq, ndev, rxq_idx,
cq->napi.napi_id));
- WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq,
- MEM_TYPE_PAGE_SHARED, NULL));
+ WARN_ON(xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL,
+ rxq->page_pool));
napi_enable(&cq->napi);
@@ -2229,6 +2295,46 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
return 0;
}
+void mana_query_gf_stats(struct mana_port_context *apc)
+{
+ struct mana_query_gf_stat_resp resp = {};
+ struct mana_query_gf_stat_req req = {};
+ struct net_device *ndev = apc->ndev;
+ int err;
+
+ mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT,
+ sizeof(req), sizeof(resp));
+ req.req_stats = STATISTICS_FLAGS_HC_TX_BYTES |
+ STATISTICS_FLAGS_HC_TX_UCAST_PACKETS |
+ STATISTICS_FLAGS_HC_TX_UCAST_BYTES |
+ STATISTICS_FLAGS_HC_TX_MCAST_PACKETS |
+ STATISTICS_FLAGS_HC_TX_MCAST_BYTES |
+ STATISTICS_FLAGS_HC_TX_BCAST_PACKETS |
+ STATISTICS_FLAGS_HC_TX_BCAST_BYTES;
+
+ err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+ sizeof(resp));
+ if (err) {
+ netdev_err(ndev, "Failed to query GF stats: %d\n", err);
+ return;
+ }
+ err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT,
+ sizeof(resp));
+ if (err || resp.hdr.status) {
+ netdev_err(ndev, "Failed to query GF stats: %d, 0x%x\n", err,
+ resp.hdr.status);
+ return;
+ }
+
+ apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes;
+ apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts;
+ apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes;
+ apc->eth_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts;
+ apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes;
+ apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts;
+ apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes;
+}
+
static int mana_init_port(struct net_device *ndev)
{
struct mana_port_context *apc = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 0dc78679f620..607150165ab4 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -13,6 +13,19 @@ static const struct {
} mana_eth_stats[] = {
{"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)},
{"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)},
+ {"hc_tx_bytes", offsetof(struct mana_ethtool_stats, hc_tx_bytes)},
+ {"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_tx_ucast_pkts)},
+ {"hc_tx_ucast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_tx_ucast_bytes)},
+ {"hc_tx_bcast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_tx_bcast_pkts)},
+ {"hc_tx_bcast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_tx_bcast_bytes)},
+ {"hc_tx_mcast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_tx_mcast_pkts)},
+ {"hc_tx_mcast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_tx_mcast_bytes)},
{"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
{"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
tx_cqe_unknown_type)},
@@ -114,6 +127,8 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
if (!apc->port_is_up)
return;
+ /* we call mana function to update stats from GDMA */
+ mana_query_gf_stats(apc);
for (q = 0; q < ARRAY_SIZE(mana_eth_stats); q++)
data[i++] = *(u64 *)(eth_stats + mana_eth_stats[q].offset);
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 87f2055c242c..e50be508c166 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -97,8 +97,6 @@ int ocelot_netdev_to_port(struct net_device *dev);
int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
struct device_node *portnp);
void ocelot_release_port(struct ocelot_port *ocelot_port);
-int ocelot_devlink_init(struct ocelot *ocelot);
-void ocelot_devlink_teardown(struct ocelot *ocelot);
int ocelot_port_devlink_init(struct ocelot *ocelot, int port,
enum devlink_port_flavour flavour);
void ocelot_port_devlink_teardown(struct ocelot *ocelot, int port);
diff --git a/drivers/net/ethernet/mscc/ocelot_fdma.c b/drivers/net/ethernet/mscc/ocelot_fdma.c
index 83a3ce0c568e..312a46832154 100644
--- a/drivers/net/ethernet/mscc/ocelot_fdma.c
+++ b/drivers/net/ethernet/mscc/ocelot_fdma.c
@@ -12,7 +12,6 @@
#include <linux/dmapool.h>
#include <linux/dsa/ocelot.h>
#include <linux/netdevice.h>
-#include <linux/of_platform.h>
#include <linux/skbuff.h>
#include "ocelot_fdma.h"
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index e0916afcddfb..33b438c6aec5 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -581,14 +581,14 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
int ret;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_META) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_META) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
return -EOPNOTSUPP;
}
@@ -641,12 +641,12 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
* then just bail out
*/
if ((dissector->used_keys &
- (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
- (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL)))
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) !=
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)))
return -EOPNOTSUPP;
flow_rule_match_eth_addrs(rule, &match);
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.h b/drivers/net/ethernet/mscc/ocelot_vcap.h
index 523611ccc48f..6f546695faa5 100644
--- a/drivers/net/ethernet/mscc/ocelot_vcap.h
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.h
@@ -15,7 +15,6 @@
int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
struct ocelot_vcap_filter *rule);
-void ocelot_detect_vcap_constants(struct ocelot *ocelot);
int ocelot_vcap_init(struct ocelot *ocelot);
int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index 97e90e2869d4..151b42465348 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -10,8 +10,9 @@
#include <linux/of_net.h>
#include <linux/netdevice.h>
#include <linux/phylink.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/skbuff.h>
#include <net/switchdev.h>
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 700c05fb05b9..61d8bfd12d5f 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -5091,13 +5091,10 @@ static void do_s2io_restore_unicast_mc(struct s2io_nic *sp)
static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr)
{
int i;
- u64 mac_addr = 0;
+ u64 mac_addr;
struct config_param *config = &sp->config;
- for (i = 0; i < ETH_ALEN; i++) {
- mac_addr <<= 8;
- mac_addr |= addr[i];
- }
+ mac_addr = ether_addr_to_u64(addr);
if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY))
return SUCCESS;
@@ -5220,7 +5217,7 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p)
static int do_s2io_prog_unicast(struct net_device *dev, const u8 *addr)
{
struct s2io_nic *sp = netdev_priv(dev);
- register u64 mac_addr = 0, perm_addr = 0;
+ register u64 mac_addr, perm_addr;
int i;
u64 tmp64;
struct config_param *config = &sp->config;
@@ -5230,12 +5227,8 @@ static int do_s2io_prog_unicast(struct net_device *dev, const u8 *addr)
* change on the device address registered with the OS. It will be
* at offset 0.
*/
- for (i = 0; i < ETH_ALEN; i++) {
- mac_addr <<= 8;
- mac_addr |= addr[i];
- perm_addr <<= 8;
- perm_addr |= sp->def_mac_addr[0].mac_addr[i];
- }
+ mac_addr = ether_addr_to_u64(addr);
+ perm_addr = ether_addr_to_u64(sp->def_mac_addr[0].mac_addr);
/* check if the dev_addr is different than perm_addr */
if (mac_addr == perm_addr)
diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
index 73032173ac4e..2643c4b3ff1f 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
@@ -61,7 +61,7 @@ bool is_pre_ct_flow(struct flow_cls_offload *flow)
struct flow_match_ct ct;
int i;
- if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT)) {
+ if (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CT)) {
flow_rule_match_ct(rule, &ct);
if (ct.key->ct_state)
return false;
@@ -94,7 +94,7 @@ bool is_post_ct_flow(struct flow_cls_offload *flow)
struct flow_match_ct ct;
int i;
- if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT)) {
+ if (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CT)) {
flow_rule_match_ct(rule, &ct);
if (ct.key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED)
return true;
@@ -236,10 +236,11 @@ static bool nfp_ct_merge_check_cannot_skip(struct nfp_fl_ct_flow_entry *entry1,
static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
struct nfp_fl_ct_flow_entry *entry2)
{
- unsigned int ovlp_keys = entry1->rule->match.dissector->used_keys &
- entry2->rule->match.dissector->used_keys;
+ unsigned long long ovlp_keys;
bool out, is_v6 = false;
u8 ip_proto = 0;
+ ovlp_keys = entry1->rule->match.dissector->used_keys &
+ entry2->rule->match.dissector->used_keys;
/* Temporary buffer for mangling keys, 64 is enough to cover max
* struct size of key in various fields that may be mangled.
* Supported fields to mangle:
@@ -257,7 +258,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
/* Check the overlapped fields one by one, the unmasked part
* should not conflict with each other.
*/
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match1, match2;
flow_rule_match_control(entry1->rule, &match1);
@@ -267,7 +268,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match1, match2;
flow_rule_match_basic(entry1->rule, &match1);
@@ -289,7 +290,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
* will be do merge check when do nft and post ct merge,
* so skip this ip merge check here.
*/
- if ((ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS)) &&
+ if ((ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS)) &&
nfp_ct_merge_check_cannot_skip(entry1, entry2)) {
struct flow_match_ipv4_addrs match1, match2;
@@ -311,7 +312,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
* will be do merge check when do nft and post ct merge,
* so skip this ip merge check here.
*/
- if ((ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS)) &&
+ if ((ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS)) &&
nfp_ct_merge_check_cannot_skip(entry1, entry2)) {
struct flow_match_ipv6_addrs match1, match2;
@@ -333,7 +334,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
* will be do merge check when do nft and post ct merge,
* so skip this tport merge check here.
*/
- if ((ovlp_keys & BIT(FLOW_DISSECTOR_KEY_PORTS)) &&
+ if ((ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_PORTS)) &&
nfp_ct_merge_check_cannot_skip(entry1, entry2)) {
enum flow_action_mangle_base htype = FLOW_ACT_MANGLE_UNSPEC;
struct flow_match_ports match1, match2;
@@ -355,7 +356,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match1, match2;
flow_rule_match_eth_addrs(entry1->rule, &match1);
@@ -371,7 +372,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_VLAN)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match1, match2;
flow_rule_match_vlan(entry1->rule, &match1);
@@ -381,7 +382,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_MPLS)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_MPLS)) {
struct flow_match_mpls match1, match2;
flow_rule_match_mpls(entry1->rule, &match1);
@@ -391,7 +392,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_TCP)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_TCP)) {
struct flow_match_tcp match1, match2;
flow_rule_match_tcp(entry1->rule, &match1);
@@ -401,7 +402,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IP)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_IP)) {
struct flow_match_ip match1, match2;
flow_rule_match_ip(entry1->rule, &match1);
@@ -413,7 +414,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid match1, match2;
flow_rule_match_enc_keyid(entry1->rule, &match1);
@@ -423,7 +424,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match1, match2;
flow_rule_match_enc_ipv4_addrs(entry1->rule, &match1);
@@ -433,7 +434,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
struct flow_match_ipv6_addrs match1, match2;
flow_rule_match_enc_ipv6_addrs(entry1->rule, &match1);
@@ -443,7 +444,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
struct flow_match_control match1, match2;
flow_rule_match_enc_control(entry1->rule, &match1);
@@ -453,7 +454,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IP)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP)) {
struct flow_match_ip match1, match2;
flow_rule_match_enc_ip(entry1->rule, &match1);
@@ -463,7 +464,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
goto check_failed;
}
- if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_OPTS)) {
+ if (ovlp_keys & BIT_ULL(FLOW_DISSECTOR_KEY_ENC_OPTS)) {
struct flow_match_enc_opts match1, match2;
flow_rule_match_enc_opts(entry1->rule, &match1);
@@ -589,7 +590,7 @@ static int nfp_ct_check_meta(struct nfp_fl_ct_flow_entry *post_ct_entry,
int i;
ct_met = get_flow_act(nft_entry->rule, FLOW_ACTION_CT_METADATA);
- if (ct_met && (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT))) {
+ if (ct_met && (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CT))) {
u32 *act_lbl;
act_lbl = ct_met->ct_metadata.labels;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 18328eb7f5c3..c153f0575b92 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -24,43 +24,43 @@
FLOW_DIS_FIRST_FRAG)
#define NFP_FLOWER_WHITELIST_DISSECTOR \
- (BIT(FLOW_DISSECTOR_KEY_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_BASIC) | \
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_TCP) | \
- BIT(FLOW_DISSECTOR_KEY_PORTS) | \
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_VLAN) | \
- BIT(FLOW_DISSECTOR_KEY_CVLAN) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IP) | \
- BIT(FLOW_DISSECTOR_KEY_MPLS) | \
- BIT(FLOW_DISSECTOR_KEY_CT) | \
- BIT(FLOW_DISSECTOR_KEY_META) | \
- BIT(FLOW_DISSECTOR_KEY_IP))
+ (BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_MPLS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_CT) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_META) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP))
#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR \
- (BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IP))
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_OPTS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP))
#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R \
- (BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS))
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS))
#define NFP_FLOWER_WHITELIST_TUN_DISSECTOR_V6_R \
- (BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS))
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) | \
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS))
#define NFP_FLOWER_MERGE_FIELDS \
(NFP_FLOWER_LAYER_PORT | \
@@ -1303,7 +1303,7 @@ static bool offload_pre_check(struct flow_cls_offload *flow)
struct flow_dissector *dissector = rule->match.dissector;
struct flow_match_ct ct;
- if (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CT)) {
+ if (dissector->used_keys & BIT_ULL(FLOW_DISSECTOR_KEY_CT)) {
flow_rule_match_ct(rule, &ct);
/* Allow special case where CT match is all 0 */
if (memchr_inv(ct.key, 0, sizeof(*ct.key)))
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 6b1fb5708434..de0a5d5ded30 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -924,7 +924,7 @@ static void nfp_net_write_mac_addr(struct nfp_net *nn, const u8 *addr)
*/
static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
{
- u32 new_ctrl, update;
+ u32 new_ctrl, new_ctrl_w1, update;
unsigned int r;
int err;
@@ -937,14 +937,29 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
if (nn->cap & NFP_NET_CFG_CTRL_RINGCFG)
new_ctrl &= ~NFP_NET_CFG_CTRL_RINGCFG;
- nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
- nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
+ if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN)) {
+ nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
+ nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
+ }
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
err = nfp_net_reconfig(nn, update);
if (err)
nn_err(nn, "Could not disable device: %d\n", err);
+ if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN) {
+ new_ctrl_w1 = nn->dp.ctrl_w1;
+ new_ctrl_w1 &= ~NFP_NET_CFG_CTRL_FREELIST_EN;
+ nn_writeq(nn, NFP_NET_CFG_TXRS_ENABLE, 0);
+ nn_writeq(nn, NFP_NET_CFG_RXRS_ENABLE, 0);
+
+ nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, new_ctrl_w1);
+ err = nfp_net_reconfig(nn, update);
+ if (err)
+ nn_err(nn, "Could not disable FREELIST_EN: %d\n", err);
+ nn->dp.ctrl_w1 = new_ctrl_w1;
+ }
+
for (r = 0; r < nn->dp.num_rx_rings; r++) {
nfp_net_rx_ring_reset(&nn->dp.rx_rings[r]);
if (nfp_net_has_xsk_pool_slow(&nn->dp, nn->dp.rx_rings[r].idx))
@@ -964,11 +979,12 @@ static void nfp_net_clear_config_and_disable(struct nfp_net *nn)
*/
static int nfp_net_set_config_and_enable(struct nfp_net *nn)
{
- u32 bufsz, new_ctrl, update = 0;
+ u32 bufsz, new_ctrl, new_ctrl_w1, update = 0;
unsigned int r;
int err;
new_ctrl = nn->dp.ctrl;
+ new_ctrl_w1 = nn->dp.ctrl_w1;
if (nn->dp.ctrl & NFP_NET_CFG_CTRL_RSS_ANY) {
nfp_net_rss_write_key(nn);
@@ -1001,16 +1017,25 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn)
bufsz = nn->dp.fl_bufsz - nn->dp.rx_dma_off - NFP_NET_RX_BUF_NON_DATA;
nn_writel(nn, NFP_NET_CFG_FLBUFSZ, bufsz);
- /* Enable device */
- new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
+ /* Enable device
+ * Step 1: Replace the CTRL_ENABLE by NFP_NET_CFG_CTRL_FREELIST_EN if
+ * FREELIST_EN exits.
+ */
+ if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN)
+ new_ctrl_w1 |= NFP_NET_CFG_CTRL_FREELIST_EN;
+ else
+ new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
update |= NFP_NET_CFG_UPDATE_GEN;
update |= NFP_NET_CFG_UPDATE_MSIX;
update |= NFP_NET_CFG_UPDATE_RING;
if (nn->cap & NFP_NET_CFG_CTRL_RINGCFG)
new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG;
+ /* Step 2: Send the configuration and write the freelist.
+ * - The freelist only need to be written once.
+ */
nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
- nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, nn->dp.ctrl_w1);
+ nn_writel(nn, NFP_NET_CFG_CTRL_WORD1, new_ctrl_w1);
err = nfp_net_reconfig(nn, update);
if (err) {
nfp_net_clear_config_and_disable(nn);
@@ -1018,10 +1043,25 @@ static int nfp_net_set_config_and_enable(struct nfp_net *nn)
}
nn->dp.ctrl = new_ctrl;
+ nn->dp.ctrl_w1 = new_ctrl_w1;
for (r = 0; r < nn->dp.num_rx_rings; r++)
nfp_net_rx_ring_fill_freelist(&nn->dp, &nn->dp.rx_rings[r]);
+ /* Step 3: Do the NFP_NET_CFG_CTRL_ENABLE. Send the configuration.
+ */
+ if (nn->cap_w1 & NFP_NET_CFG_CTRL_FREELIST_EN) {
+ new_ctrl |= NFP_NET_CFG_CTRL_ENABLE;
+ nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
+
+ err = nfp_net_reconfig(nn, update);
+ if (err) {
+ nfp_net_clear_config_and_disable(nn);
+ return err;
+ }
+ nn->dp.ctrl = new_ctrl;
+ }
+
return 0;
}
@@ -2068,9 +2108,6 @@ static int nfp_net_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
if (nla_type(attr) != IFLA_BRIDGE_MODE)
continue;
- if (nla_len(attr) < sizeof(mode))
- return -EINVAL;
-
new_ctrl = nn->dp.ctrl;
mode = nla_get_u16(attr);
if (mode == BRIDGE_MODE_VEPA)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index 669b9dccb6a9..3e63f6d6a563 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -268,6 +268,7 @@
#define NFP_NET_CFG_CTRL_PKT_TYPE (0x1 << 0) /* Pkttype offload */
#define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /* IPsec offload */
#define NFP_NET_CFG_CTRL_MCAST_FILTER (0x1 << 2) /* Multicast Filter */
+#define NFP_NET_CFG_CTRL_FREELIST_EN (0x1 << 6) /* Freelist enable flag bit */
#define NFP_NET_CFG_CAP_WORD1 0x00a4
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 0fd156286d4d..ba27bbc68f85 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -7,11 +7,10 @@
#include <linux/etherdevice.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/phy.h>
#include <linux/mii.h>
diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h
index 602f4d45d529..2453a40f6ee8 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic.h
@@ -81,7 +81,6 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
int ionic_dev_cmd_wait_nomsg(struct ionic *ionic, unsigned long max_wait);
void ionic_dev_cmd_dev_err_print(struct ionic *ionic, u8 opcode, u8 status,
int err);
-int ionic_set_dma_mask(struct ionic *ionic);
int ionic_setup(struct ionic *ionic);
int ionic_identify(struct ionic *ionic);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
index ab7d217b98b3..d6ce113a4210 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
@@ -213,29 +213,18 @@ out:
return ret;
}
-static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void ionic_clear_pci(struct ionic *ionic)
{
- struct device *dev = &pdev->dev;
- struct ionic *ionic;
- int num_vfs;
- int err;
-
- ionic = ionic_devlink_alloc(dev);
- if (!ionic)
- return -ENOMEM;
-
- ionic->pdev = pdev;
- ionic->dev = dev;
- pci_set_drvdata(pdev, ionic);
- mutex_init(&ionic->dev_cmd_lock);
+ ionic_unmap_bars(ionic);
+ pci_release_regions(ionic->pdev);
+ pci_disable_device(ionic->pdev);
+}
- /* Query system for DMA addressing limitation for the device. */
- err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
- if (err) {
- dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n",
- err);
- goto err_out_clear_drvdata;
- }
+static int ionic_setup_one(struct ionic *ionic)
+{
+ struct pci_dev *pdev = ionic->pdev;
+ struct device *dev = ionic->dev;
+ int err;
ionic_debugfs_add_dev(ionic);
@@ -249,20 +238,19 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = pci_request_regions(pdev, IONIC_DRV_NAME);
if (err) {
dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err);
- goto err_out_pci_disable_device;
+ goto err_out_clear_pci;
}
-
pcie_print_link_status(pdev);
err = ionic_map_bars(ionic);
if (err)
- goto err_out_pci_release_regions;
+ goto err_out_clear_pci;
/* Configure the device */
err = ionic_setup(ionic);
if (err) {
dev_err(dev, "Cannot setup device: %d, aborting\n", err);
- goto err_out_unmap_bars;
+ goto err_out_clear_pci;
}
pci_set_master(pdev);
@@ -279,24 +267,64 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_teardown;
}
- /* Configure the ports */
+ /* Configure the port */
err = ionic_port_identify(ionic);
if (err) {
dev_err(dev, "Cannot identify port: %d, aborting\n", err);
- goto err_out_reset;
+ goto err_out_teardown;
}
err = ionic_port_init(ionic);
if (err) {
dev_err(dev, "Cannot init port: %d, aborting\n", err);
- goto err_out_reset;
+ goto err_out_teardown;
+ }
+
+ return 0;
+
+err_out_teardown:
+ ionic_dev_teardown(ionic);
+err_out_clear_pci:
+ ionic_clear_pci(ionic);
+err_out_debugfs_del_dev:
+ ionic_debugfs_del_dev(ionic);
+
+ return err;
+}
+
+static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct ionic *ionic;
+ int num_vfs;
+ int err;
+
+ ionic = ionic_devlink_alloc(dev);
+ if (!ionic)
+ return -ENOMEM;
+
+ ionic->pdev = pdev;
+ ionic->dev = dev;
+ pci_set_drvdata(pdev, ionic);
+ mutex_init(&ionic->dev_cmd_lock);
+
+ /* Query system for DMA addressing limitation for the device. */
+ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
+ if (err) {
+ dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n",
+ err);
+ goto err_out;
}
+ err = ionic_setup_one(ionic);
+ if (err)
+ goto err_out;
+
/* Allocate and init the LIF */
err = ionic_lif_size(ionic);
if (err) {
dev_err(dev, "Cannot size LIF: %d, aborting\n", err);
- goto err_out_port_reset;
+ goto err_out_pci;
}
err = ionic_lif_alloc(ionic);
@@ -347,21 +375,10 @@ err_out_free_lifs:
ionic->lif = NULL;
err_out_free_irqs:
ionic_bus_free_irq_vectors(ionic);
-err_out_port_reset:
- ionic_port_reset(ionic);
-err_out_reset:
- ionic_reset(ionic);
-err_out_teardown:
+err_out_pci:
ionic_dev_teardown(ionic);
-err_out_unmap_bars:
- ionic_unmap_bars(ionic);
-err_out_pci_release_regions:
- pci_release_regions(pdev);
-err_out_pci_disable_device:
- pci_disable_device(pdev);
-err_out_debugfs_del_dev:
- ionic_debugfs_del_dev(ionic);
-err_out_clear_drvdata:
+ ionic_clear_pci(ionic);
+err_out:
mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic);
@@ -386,20 +403,71 @@ static void ionic_remove(struct pci_dev *pdev)
ionic_port_reset(ionic);
ionic_reset(ionic);
ionic_dev_teardown(ionic);
- ionic_unmap_bars(ionic);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
+ ionic_clear_pci(ionic);
ionic_debugfs_del_dev(ionic);
mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic);
}
+static void ionic_reset_prepare(struct pci_dev *pdev)
+{
+ struct ionic *ionic = pci_get_drvdata(pdev);
+ struct ionic_lif *lif = ionic->lif;
+
+ dev_dbg(ionic->dev, "%s: device stopping\n", __func__);
+
+ del_timer_sync(&ionic->watchdog_timer);
+ cancel_work_sync(&lif->deferred.work);
+
+ mutex_lock(&lif->queue_lock);
+ ionic_stop_queues_reconfig(lif);
+ ionic_txrx_free(lif);
+ ionic_lif_deinit(lif);
+ ionic_qcqs_free(lif);
+ mutex_unlock(&lif->queue_lock);
+
+ ionic_dev_teardown(ionic);
+ ionic_clear_pci(ionic);
+ ionic_debugfs_del_dev(ionic);
+}
+
+static void ionic_reset_done(struct pci_dev *pdev)
+{
+ struct ionic *ionic = pci_get_drvdata(pdev);
+ struct ionic_lif *lif = ionic->lif;
+ int err;
+
+ err = ionic_setup_one(ionic);
+ if (err)
+ goto err_out;
+
+ ionic_debugfs_add_sizes(ionic);
+ ionic_debugfs_add_lif(ionic->lif);
+
+ err = ionic_restart_lif(lif);
+ if (err)
+ goto err_out;
+
+ mod_timer(&ionic->watchdog_timer, jiffies + 1);
+
+err_out:
+ dev_dbg(ionic->dev, "%s: device recovery %s\n",
+ __func__, err ? "failed" : "done");
+}
+
+static const struct pci_error_handlers ionic_err_handler = {
+ /* FLR handling */
+ .reset_prepare = ionic_reset_prepare,
+ .reset_done = ionic_reset_done,
+};
+
static struct pci_driver ionic_driver = {
.name = IONIC_DRV_NAME,
.id_table = ionic_id_table,
.probe = ionic_probe,
.remove = ionic_remove,
.sriov_configure = ionic_sriov_configure,
+ .err_handler = &ionic_err_handler
};
int ionic_bus_register_driver(void)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
index 0bea208bfba2..6aac98bcb9f4 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
@@ -376,7 +376,6 @@ void ionic_q_cmb_map(struct ionic_queue *q, void __iomem *base, dma_addr_t base_
void ionic_q_sg_map(struct ionic_queue *q, void *base, dma_addr_t base_pa);
void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb,
void *cb_arg);
-void ionic_q_rewind(struct ionic_queue *q, struct ionic_desc_info *start);
void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
unsigned int stop_index);
int ionic_heartbeat_check(struct ionic *ionic);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 432fb93aa801..2c3e36b2dd7f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -434,7 +434,7 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
}
}
-static void ionic_qcqs_free(struct ionic_lif *lif)
+void ionic_qcqs_free(struct ionic_lif *lif)
{
struct device *dev = lif->ionic->dev;
struct ionic_qcq *adminqcq;
@@ -1754,7 +1754,7 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
return ionic_lif_addr_add(netdev_priv(netdev), mac);
}
-static void ionic_stop_queues_reconfig(struct ionic_lif *lif)
+void ionic_stop_queues_reconfig(struct ionic_lif *lif)
{
/* Stop and clean the queues before reconfiguration */
netif_device_detach(lif->netdev);
@@ -2013,7 +2013,7 @@ static void ionic_txrx_deinit(struct ionic_lif *lif)
}
}
-static void ionic_txrx_free(struct ionic_lif *lif)
+void ionic_txrx_free(struct ionic_lif *lif)
{
unsigned int i;
@@ -3275,27 +3275,11 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
dev_info(ionic->dev, "FW Down: LIFs stopped\n");
}
-static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
+int ionic_restart_lif(struct ionic_lif *lif)
{
struct ionic *ionic = lif->ionic;
int err;
- if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
- return;
-
- dev_info(ionic->dev, "FW Up: restarting LIFs\n");
-
- ionic_init_devinfo(ionic);
- err = ionic_identify(ionic);
- if (err)
- goto err_out;
- err = ionic_port_identify(ionic);
- if (err)
- goto err_out;
- err = ionic_port_init(ionic);
- if (err)
- goto err_out;
-
mutex_lock(&lif->queue_lock);
if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
@@ -3331,12 +3315,8 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
ionic_link_status_check_request(lif, CAN_SLEEP);
netif_device_attach(lif->netdev);
- dev_info(ionic->dev, "FW Up: LIFs restarted\n");
-
- /* restore the hardware timestamping queues */
- ionic_lif_hwstamp_replay(lif);
- return;
+ return 0;
err_txrx_free:
ionic_txrx_free(lif);
@@ -3346,6 +3326,46 @@ err_qcqs_free:
ionic_qcqs_free(lif);
err_unlock:
mutex_unlock(&lif->queue_lock);
+
+ return err;
+}
+
+static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
+{
+ struct ionic *ionic = lif->ionic;
+ int err;
+
+ if (!test_bit(IONIC_LIF_F_FW_RESET, lif->state))
+ return;
+
+ dev_info(ionic->dev, "FW Up: restarting LIFs\n");
+
+ /* This is a little different from what happens at
+ * probe time because the LIF already exists so we
+ * just need to reanimate it.
+ */
+ ionic_init_devinfo(ionic);
+ err = ionic_identify(ionic);
+ if (err)
+ goto err_out;
+ err = ionic_port_identify(ionic);
+ if (err)
+ goto err_out;
+ err = ionic_port_init(ionic);
+ if (err)
+ goto err_out;
+
+ err = ionic_restart_lif(lif);
+ if (err)
+ goto err_out;
+
+ dev_info(ionic->dev, "FW Up: LIFs restarted\n");
+
+ /* restore the hardware timestamping queues */
+ ionic_lif_hwstamp_replay(lif);
+
+ return;
+
err_out:
dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index fd2ea670e7d8..457c24195ca6 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -325,6 +325,11 @@ void ionic_lif_deinit(struct ionic_lif *lif);
int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
+void ionic_stop_queues_reconfig(struct ionic_lif *lif);
+void ionic_txrx_free(struct ionic_lif *lif);
+void ionic_qcqs_free(struct ionic_lif *lif);
+int ionic_restart_lif(struct ionic_lif *lif);
+
int ionic_lif_register(struct ionic_lif *lif);
void ionic_lif_unregister(struct ionic_lif *lif);
int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
index 87b2666f248b..ee9e99cd1b5e 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h
@@ -43,7 +43,6 @@ struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif, const u8
struct ionic_rx_filter *ionic_rx_filter_rxsteer(struct ionic_lif *lif);
void ionic_rx_filter_sync(struct ionic_lif *lif);
int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode);
-int ionic_rx_filters_need_sync(struct ionic_lif *lif);
int ionic_lif_vlan_add(struct ionic_lif *lif, const u16 vid);
int ionic_lif_vlan_del(struct ionic_lif *lif, const u16 vid);
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index d613095b78e0..1d719726f72b 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -909,7 +909,6 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
u32 min_pf_rate);
void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
-int qed_device_num_engines(struct qed_dev *cdev);
void qed_set_fw_mac_addr(__le16 *fw_msb,
__le16 *fw_mid, __le16 *fw_lsb, u8 *mac);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c
index 7b0e390c0b07..0e265ed1f501 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_vf.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c
@@ -60,7 +60,7 @@ static void qed_vf_pf_req_end(struct qed_hwfn *p_hwfn, int req_status)
#define QED_VF_CHANNEL_MSLEEP_ITERATIONS 10
#define QED_VF_CHANNEL_MSLEEP_DELAY 25
-static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size)
+static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done)
{
union vfpf_tlvs *p_req = p_hwfn->vf_iov_info->vf2pf_request;
struct ustorm_trigger_vf_zone trigger;
@@ -72,9 +72,6 @@ static int qed_send_msg2pf(struct qed_hwfn *p_hwfn, u8 *done, u32 resp_size)
/* output tlvs list */
qed_dp_tlv_list(p_hwfn, p_req);
- /* need to add the END TLV to the message size */
- resp_size += sizeof(struct channel_list_end_tlv);
-
/* Send TLVs over HW channel */
memset(&trigger, 0, sizeof(struct ustorm_trigger_vf_zone));
trigger.vf_pf_msg_valid = 1;
@@ -172,7 +169,7 @@ static int _qed_vf_pf_release(struct qed_hwfn *p_hwfn, bool b_final)
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (!rc && resp->hdr.status != PFVF_STATUS_SUCCESS)
rc = -EAGAIN;
@@ -301,7 +298,7 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn)
memset(p_iov->pf2vf_reply, 0, sizeof(union pfvf_tlvs));
/* send acquire request */
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
/* Re-try acquire in case of vf-pf hw channel timeout */
if (retry_cnt && rc == -EBUSY) {
@@ -705,7 +702,7 @@ int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
sizeof(struct channel_list_end_tlv));
p_resp = &p_iov->pf2vf_reply->tunn_param_resp;
- rc = qed_send_msg2pf(p_hwfn, &p_resp->hdr.status, sizeof(*p_resp));
+ rc = qed_send_msg2pf(p_hwfn, &p_resp->hdr.status);
if (rc)
goto exit;
@@ -772,7 +769,7 @@ qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->queue_start;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -822,7 +819,7 @@ int qed_vf_pf_rxq_stop(struct qed_hwfn *p_hwfn,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -867,7 +864,7 @@ qed_vf_pf_txq_start(struct qed_hwfn *p_hwfn,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->queue_start;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -918,7 +915,7 @@ int qed_vf_pf_txq_stop(struct qed_hwfn *p_hwfn, struct qed_queue_cid *p_cid)
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -968,7 +965,7 @@ int qed_vf_pf_vport_start(struct qed_hwfn *p_hwfn,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -997,7 +994,7 @@ int qed_vf_pf_vport_stop(struct qed_hwfn *p_hwfn)
qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1075,12 +1072,10 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
struct vfpf_vport_update_tlv *req;
struct pfvf_def_resp_tlv *resp;
u8 update_rx, update_tx;
- u32 resp_size = 0;
u16 size, tlv;
int rc;
resp = &p_iov->pf2vf_reply->default_resp;
- resp_size = sizeof(*resp);
update_rx = p_params->update_vport_active_rx_flg;
update_tx = p_params->update_vport_active_tx_flg;
@@ -1096,7 +1091,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
p_act_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_VPORT_UPDATE_ACTIVATE,
size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
if (update_rx) {
p_act_tlv->update_rx = update_rx;
@@ -1116,7 +1110,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
tlv = CHANNEL_TLV_VPORT_UPDATE_TX_SWITCH;
p_tx_switch_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
tlv, size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
p_tx_switch_tlv->tx_switching = p_params->tx_switching_flg;
}
@@ -1127,7 +1120,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
size = sizeof(struct vfpf_vport_update_mcast_bin_tlv);
p_mcast_tlv = qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_VPORT_UPDATE_MCAST, size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
memcpy(p_mcast_tlv->bins, p_params->bins,
sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS);
@@ -1142,7 +1134,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_PARAM;
size = sizeof(struct vfpf_vport_update_accept_param_tlv);
p_accept_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, tlv, size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
if (update_rx) {
p_accept_tlv->update_rx_mode = update_rx;
@@ -1166,7 +1157,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
p_rss_tlv = qed_add_tlv(p_hwfn,
&p_iov->offset,
CHANNEL_TLV_VPORT_UPDATE_RSS, size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
if (rss_params->update_rss_config)
p_rss_tlv->update_rss_flags |=
@@ -1203,7 +1193,6 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
tlv = CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN;
p_any_vlan_tlv = qed_add_tlv(p_hwfn, &p_iov->offset, tlv, size);
- resp_size += sizeof(struct pfvf_def_resp_tlv);
p_any_vlan_tlv->accept_any_vlan = p_params->accept_any_vlan;
p_any_vlan_tlv->update_accept_any_vlan_flg =
p_params->update_accept_any_vlan_flg;
@@ -1213,7 +1202,7 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn,
qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, resp_size);
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1245,7 +1234,7 @@ int qed_vf_pf_reset(struct qed_hwfn *p_hwfn)
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1303,7 +1292,7 @@ int qed_vf_pf_filter_ucast(struct qed_hwfn *p_hwfn,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1332,7 +1321,7 @@ int qed_vf_pf_int_cleanup(struct qed_hwfn *p_hwfn)
qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_LIST_END, sizeof(struct channel_list_end_tlv));
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1364,7 +1353,7 @@ int qed_vf_pf_get_coalesce(struct qed_hwfn *p_hwfn,
sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->read_coal_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
@@ -1402,7 +1391,7 @@ qed_vf_pf_bulletin_update_mac(struct qed_hwfn *p_hwfn,
sizeof(struct channel_list_end_tlv));
p_resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &p_resp->hdr.status, sizeof(*p_resp));
+ rc = qed_send_msg2pf(p_hwfn, &p_resp->hdr.status);
qed_vf_pf_req_end(p_hwfn, rc);
return rc;
}
@@ -1433,7 +1422,7 @@ qed_vf_pf_set_coalesce(struct qed_hwfn *p_hwfn,
sizeof(struct channel_list_end_tlv));
resp = &p_iov->pf2vf_reply->default_resp;
- rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp));
+ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status);
if (rc)
goto exit;
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h
index 4d83ceebdc49..042a75f34060 100644
--- a/drivers/net/ethernet/qlogic/qede/qede.h
+++ b/drivers/net/ethernet/qlogic/qede/qede.h
@@ -556,9 +556,6 @@ void qede_config_rx_mode(struct net_device *ndev);
void qede_fill_rss_params(struct qede_dev *edev,
struct qed_update_vport_rss_params *rss, u8 *update);
-void qede_udp_tunnel_add(struct net_device *dev, struct udp_tunnel_info *ti);
-void qede_udp_tunnel_del(struct net_device *dev, struct udp_tunnel_info *ti);
-
int qede_xdp(struct net_device *dev, struct netdev_bpf *xdp);
#ifdef CONFIG_DCB
diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
index 3010833ddde3..a5ac21a0ee33 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
@@ -1827,12 +1827,12 @@ qede_parse_flow_attr(struct qede_dev *edev, __be16 proto,
memset(tuple, 0, sizeof(*tuple));
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS))) {
- DP_NOTICE(edev, "Unsupported key set:0x%x\n",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS))) {
+ DP_NOTICE(edev, "Unsupported key set:0x%llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index 802ef81493e0..e4bc18009d08 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -8,7 +8,9 @@
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/acpi.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include "emac.h"
#include "emac-mac.h"
#include "emac-sgmii.h"
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index eaa50050aa0b..19bb16daf4e7 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_net.h>
-#include <linux/of_device.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 4a1b94e5a8ea..bec723028e96 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -35,7 +35,6 @@
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 26646cb6a20a..9adec91f35e9 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/sched.h>
#include <linux/serdev.h>
@@ -404,7 +403,7 @@ static struct serdev_device_driver qca_uart_driver = {
.remove = qca_uart_remove,
.driver = {
.name = QCAUART_DRV_NAME,
- .of_match_table = of_match_ptr(qca_uart_of_match),
+ .of_match_table = qca_uart_of_match,
},
};
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 5eb50b265c0b..6351a2dc13bc 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -5239,13 +5239,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disable ASPM L1 as that cause random device stop working
* problems as well as full system hangs for some PCIe devices users.
- * Chips from RTL8168h partially have issues with L1.2, but seem
- * to work fine with L1 and L1.1.
*/
if (rtl_aspm_is_safe(tp))
rc = 0;
- else if (tp->mac_version >= RTL_GIGA_MAC_VER_46)
- rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2);
else
rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1);
tp->aspm_manageable = !rc;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 4d6b3b7d6abb..7df9f9f8e134 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -21,10 +21,9 @@
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c
index 4e412ac0965a..6083b1c8e4fb 100644
--- a/drivers/net/ethernet/renesas/rswitch.c
+++ b/drivers/net/ethernet/renesas/rswitch.c
@@ -12,15 +12,15 @@
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/sys_soc.h>
#include "rswitch.h"
@@ -1244,7 +1244,6 @@ static void rswitch_adjust_link(struct net_device *ndev)
struct rswitch_device *rdev = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
- /* Current hardware has a restriction not to change speed at runtime */
if (phydev->link != rdev->etha->link) {
phy_print_status(phydev);
if (phydev->link)
@@ -1253,13 +1252,23 @@ static void rswitch_adjust_link(struct net_device *ndev)
phy_power_off(rdev->serdes);
rdev->etha->link = phydev->link;
+
+ if (!rdev->priv->etha_no_runtime_change &&
+ phydev->speed != rdev->etha->speed) {
+ rdev->etha->speed = phydev->speed;
+
+ rswitch_etha_hw_init(rdev->etha, rdev->ndev->dev_addr);
+ phy_set_speed(rdev->serdes, rdev->etha->speed);
+ }
}
}
static void rswitch_phy_remove_link_mode(struct rswitch_device *rdev,
struct phy_device *phydev)
{
- /* Current hardware has a restriction not to change speed at runtime */
+ if (!rdev->priv->etha_no_runtime_change)
+ return;
+
switch (rdev->etha->speed) {
case SPEED_2500:
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
@@ -1348,7 +1357,8 @@ static int rswitch_ether_port_init_one(struct rswitch_device *rdev)
err = rswitch_etha_hw_init(rdev->etha, rdev->ndev->dev_addr);
if (err < 0)
return err;
- rdev->etha->operated = true;
+ if (rdev->priv->etha_no_runtime_change)
+ rdev->etha->operated = true;
}
err = rswitch_mii_register(rdev);
@@ -1654,6 +1664,8 @@ static int rswitch_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *
static const struct ethtool_ops rswitch_ethtool_ops = {
.get_ts_info = rswitch_get_ts_info,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
};
static const struct of_device_id renesas_eth_sw_of_table[] = {
@@ -1854,8 +1866,14 @@ err_ts_queue_alloc:
return err;
}
+static const struct soc_device_attribute rswitch_soc_no_speed_change[] = {
+ { .soc_id = "r8a779f0", .revision = "ES1.0" },
+ { /* Sentinel */ }
+};
+
static int renesas_eth_sw_probe(struct platform_device *pdev)
{
+ const struct soc_device_attribute *attr;
struct rswitch_private *priv;
struct resource *res;
int ret;
@@ -1870,6 +1888,10 @@ static int renesas_eth_sw_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ attr = soc_device_match(rswitch_soc_no_speed_change);
+ if (attr)
+ priv->etha_no_runtime_change = true;
+
priv->ptp_priv = rcar_gen4_ptp_alloc(pdev);
if (!priv->ptp_priv)
return -ENOMEM;
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index bb9ed971a97c..54f397effbc6 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -1011,6 +1011,7 @@ struct rswitch_private {
struct rswitch_etha etha[RSWITCH_NUM_PORTS];
struct rswitch_mfwd mfwd;
+ bool etha_no_runtime_change;
bool gwca_halt;
};
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index d8ec729825be..274ea16c0a1f 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -19,8 +19,6 @@
#include <linux/mdio-bitbang.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/cache.h>
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 16293b58e0a8..8f446b9bd5ee 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -11,7 +11,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
sfc-$(CONFIG_SFC_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
mae.o tc.o tc_bindings.o tc_counters.o \
- tc_encap_actions.o
+ tc_encap_actions.o tc_conntrack.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/ethernet/sfc/bitfield.h b/drivers/net/ethernet/sfc/bitfield.h
index 1f981dfe4bdc..89665fc9b8d0 100644
--- a/drivers/net/ethernet/sfc/bitfield.h
+++ b/drivers/net/ethernet/sfc/bitfield.h
@@ -26,6 +26,8 @@
/* Lowest bit numbers and widths */
#define EFX_DUMMY_FIELD_LBN 0
#define EFX_DUMMY_FIELD_WIDTH 0
+#define EFX_BYTE_0_LBN 0
+#define EFX_BYTE_0_WIDTH 8
#define EFX_WORD_0_LBN 0
#define EFX_WORD_0_WIDTH 16
#define EFX_WORD_1_LBN 16
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 8c019f382a7f..6dfa062feebc 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -2209,7 +2209,7 @@ static int efx_ef10_tx_probe(struct efx_tx_queue *tx_queue)
/* low two bits of label are what we want for type */
BUILD_BUG_ON((EFX_TXQ_TYPE_OUTER_CSUM | EFX_TXQ_TYPE_INNER_CSUM) != 3);
tx_queue->type = tx_queue->label & 3;
- return efx_nic_alloc_buffer(tx_queue->efx, &tx_queue->txd.buf,
+ return efx_nic_alloc_buffer(tx_queue->efx, &tx_queue->txd,
(tx_queue->ptr_mask + 1) *
sizeof(efx_qword_t),
GFP_KERNEL);
@@ -4267,8 +4267,6 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.sriov_init = efx_ef10_sriov_init,
.sriov_fini = efx_ef10_sriov_fini,
.sriov_wanted = efx_ef10_sriov_wanted,
- .sriov_reset = efx_ef10_sriov_reset,
- .sriov_flr = efx_ef10_sriov_flr,
.sriov_set_vf_mac = efx_ef10_sriov_set_vf_mac,
.sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan,
.sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk,
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 35d8e9811998..6da06931187d 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -224,7 +224,7 @@ int efx_ef100_init_datapath_caps(struct efx_nic *efx)
static int ef100_ev_probe(struct efx_channel *channel)
{
/* Allocate an extra descriptor for the QMDA status completion entry */
- return efx_nic_alloc_buffer(channel->efx, &channel->eventq.buf,
+ return efx_nic_alloc_buffer(channel->efx, &channel->eventq,
(channel->eventq_mask + 2) *
sizeof(efx_qword_t),
GFP_KERNEL);
diff --git a/drivers/net/ethernet/sfc/ef100_tx.c b/drivers/net/ethernet/sfc/ef100_tx.c
index 849e5555bd12..e6b6be549581 100644
--- a/drivers/net/ethernet/sfc/ef100_tx.c
+++ b/drivers/net/ethernet/sfc/ef100_tx.c
@@ -23,7 +23,7 @@
int ef100_tx_probe(struct efx_tx_queue *tx_queue)
{
/* Allocate an extra descriptor for the QMDA status completion entry */
- return efx_nic_alloc_buffer(tx_queue->efx, &tx_queue->txd.buf,
+ return efx_nic_alloc_buffer(tx_queue->efx, &tx_queue->txd,
(tx_queue->ptr_mask + 2) *
sizeof(efx_oword_t),
GFP_KERNEL);
@@ -101,8 +101,8 @@ static bool ef100_tx_can_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
static efx_oword_t *ef100_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
{
- if (likely(tx_queue->txd.buf.addr))
- return ((efx_oword_t *)tx_queue->txd.buf.addr) + index;
+ if (likely(tx_queue->txd.addr))
+ return ((efx_oword_t *)tx_queue->txd.addr) + index;
else
return NULL;
}
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h
index 3c703ca878b0..be419c9c5dec 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.h
+++ b/drivers/net/ethernet/sfc/ef10_sriov.h
@@ -35,9 +35,7 @@ static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx)
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs);
int efx_ef10_sriov_init(struct efx_nic *efx);
-static inline void efx_ef10_sriov_reset(struct efx_nic *efx) {}
void efx_ef10_sriov_fini(struct efx_nic *efx);
-static inline void efx_ef10_sriov_flr(struct efx_nic *efx, unsigned vf_i) {}
int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf, const u8 *mac);
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index d670a319b379..19f4b4d0b851 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -605,7 +605,6 @@ static const struct net_device_ops efx_netdev_ops = {
#endif
.ndo_get_phys_port_id = efx_get_phys_port_id,
.ndo_get_phys_port_name = efx_get_phys_port_name,
- .ndo_setup_tc = efx_setup_tc,
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = efx_filter_rfs,
#endif
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 4239c7ece123..48d3623735ba 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -30,8 +30,6 @@ static inline netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct
tx_queue, skb);
}
void efx_xmit_done_single(struct efx_tx_queue *tx_queue);
-int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
- void *type_data);
extern unsigned int efx_piobuf_size;
/* RX */
diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c
index 41b33a75333c..8d2d7ea2ebef 100644
--- a/drivers/net/ethernet/sfc/efx_channels.c
+++ b/drivers/net/ethernet/sfc/efx_channels.c
@@ -713,9 +713,6 @@ int efx_probe_channels(struct efx_nic *efx)
struct efx_channel *channel;
int rc;
- /* Restart special buffer allocation */
- efx->next_buffer_table = 0;
-
/* Probe channels in reverse, so that any 'extra' channels
* use the start of the buffer table. This allows the traffic
* channels to be resized without moving them or wasting the
@@ -849,36 +846,14 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel,
*ptp_channel = efx_ptp_channel(efx);
struct efx_ptp_data *ptp_data = efx->ptp_data;
- unsigned int i, next_buffer_table = 0;
u32 old_rxq_entries, old_txq_entries;
+ unsigned int i;
int rc, rc2;
rc = efx_check_disabled(efx);
if (rc)
return rc;
- /* Not all channels should be reallocated. We must avoid
- * reallocating their buffer table entries.
- */
- efx_for_each_channel(channel, efx) {
- struct efx_rx_queue *rx_queue;
- struct efx_tx_queue *tx_queue;
-
- if (channel->type->copy)
- continue;
- next_buffer_table = max(next_buffer_table,
- channel->eventq.index +
- channel->eventq.entries);
- efx_for_each_channel_rx_queue(rx_queue, channel)
- next_buffer_table = max(next_buffer_table,
- rx_queue->rxd.index +
- rx_queue->rxd.entries);
- efx_for_each_channel_tx_queue(tx_queue, channel)
- next_buffer_table = max(next_buffer_table,
- tx_queue->txd.index +
- tx_queue->txd.entries);
- }
-
efx_device_detach_sync(efx);
efx_stop_all(efx);
efx_soft_disable_interrupts(efx);
@@ -904,9 +879,6 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
for (i = 0; i < efx->n_channels; i++)
swap(efx->channel[i], other_channel[i]);
- /* Restart buffer table allocation */
- efx->next_buffer_table = next_buffer_table;
-
for (i = 0; i < efx->n_channels; i++) {
channel = efx->channel[i];
if (!channel->type->copy)
diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c
index 361687de308d..175bd9cdfdac 100644
--- a/drivers/net/ethernet/sfc/efx_common.c
+++ b/drivers/net/ethernet/sfc/efx_common.c
@@ -35,11 +35,6 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
/* This is the time (in jiffies) between invocations of the hardware
* monitor.
- * On Falcon-based NICs, this will:
- * - Check the on-board hardware monitor;
- * - Poll the link state and reconfigure the hardware as necessary.
- * On Siena-based NICs for power systems with EEH support, this will give EEH a
- * chance to start.
*/
static unsigned int efx_monitor_interval = 1 * HZ;
@@ -785,8 +780,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
mutex_unlock(&efx->rss_lock);
efx->type->filter_table_restore(efx);
up_write(&efx->filter_sem);
- if (efx->type->sriov_reset)
- efx->type->sriov_reset(efx);
mutex_unlock(&efx->mac_lock);
diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c
index cf1d67b6d86d..c3dc88e6c26c 100644
--- a/drivers/net/ethernet/sfc/falcon/selftest.c
+++ b/drivers/net/ethernet/sfc/falcon/selftest.c
@@ -428,7 +428,7 @@ static int ef4_begin_loopback(struct ef4_tx_queue *tx_queue)
for (i = 0; i < state->packet_count; i++) {
/* Allocate an skb, holding an extra reference for
* transmit completion counting */
- skb = alloc_skb(EF4_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL);
+ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
if (!skb)
return -ENOMEM;
state->skbs[i] = skb;
diff --git a/drivers/net/ethernet/sfc/farch_regs.h b/drivers/net/ethernet/sfc/farch_regs.h
deleted file mode 100644
index d138be423e63..000000000000
--- a/drivers/net/ethernet/sfc/farch_regs.h
+++ /dev/null
@@ -1,2929 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/****************************************************************************
- * Driver for Solarflare network controllers and boards
- * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2012 Solarflare Communications Inc.
- */
-
-#ifndef EFX_FARCH_REGS_H
-#define EFX_FARCH_REGS_H
-
-/*
- * Falcon hardware architecture definitions have a name prefix following
- * the format:
- *
- * F<type>_<min-rev><max-rev>_
- *
- * The following <type> strings are used:
- *
- * MMIO register MC register Host memory structure
- * -------------------------------------------------------------
- * Address R MCR
- * Bitfield RF MCRF SF
- * Enumerator FE MCFE SE
- *
- * <min-rev> is the first revision to which the definition applies:
- *
- * A: Falcon A1 (SFC4000AB)
- * B: Falcon B0 (SFC4000BA)
- * C: Siena A0 (SFL9021AA)
- *
- * If the definition has been changed or removed in later revisions
- * then <max-rev> is the last revision to which the definition applies;
- * otherwise it is "Z".
- */
-
-/**************************************************************************
- *
- * Falcon/Siena registers and descriptors
- *
- **************************************************************************
- */
-
-/* ADR_REGION_REG: Address region register */
-#define FR_AZ_ADR_REGION 0x00000000
-#define FRF_AZ_ADR_REGION3_LBN 96
-#define FRF_AZ_ADR_REGION3_WIDTH 18
-#define FRF_AZ_ADR_REGION2_LBN 64
-#define FRF_AZ_ADR_REGION2_WIDTH 18
-#define FRF_AZ_ADR_REGION1_LBN 32
-#define FRF_AZ_ADR_REGION1_WIDTH 18
-#define FRF_AZ_ADR_REGION0_LBN 0
-#define FRF_AZ_ADR_REGION0_WIDTH 18
-
-/* INT_EN_REG_KER: Kernel driver Interrupt enable register */
-#define FR_AZ_INT_EN_KER 0x00000010
-#define FRF_AZ_KER_INT_LEVE_SEL_LBN 8
-#define FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6
-#define FRF_AZ_KER_INT_CHAR_LBN 4
-#define FRF_AZ_KER_INT_CHAR_WIDTH 1
-#define FRF_AZ_KER_INT_KER_LBN 3
-#define FRF_AZ_KER_INT_KER_WIDTH 1
-#define FRF_AZ_DRV_INT_EN_KER_LBN 0
-#define FRF_AZ_DRV_INT_EN_KER_WIDTH 1
-
-/* INT_EN_REG_CHAR: Char Driver interrupt enable register */
-#define FR_BZ_INT_EN_CHAR 0x00000020
-#define FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8
-#define FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6
-#define FRF_BZ_CHAR_INT_CHAR_LBN 4
-#define FRF_BZ_CHAR_INT_CHAR_WIDTH 1
-#define FRF_BZ_CHAR_INT_KER_LBN 3
-#define FRF_BZ_CHAR_INT_KER_WIDTH 1
-#define FRF_BZ_DRV_INT_EN_CHAR_LBN 0
-#define FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1
-
-/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */
-#define FR_AZ_INT_ADR_KER 0x00000030
-#define FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64
-#define FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1
-#define FRF_AZ_INT_ADR_KER_LBN 0
-#define FRF_AZ_INT_ADR_KER_WIDTH 64
-
-/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */
-#define FR_BZ_INT_ADR_CHAR 0x00000040
-#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64
-#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1
-#define FRF_BZ_INT_ADR_CHAR_LBN 0
-#define FRF_BZ_INT_ADR_CHAR_WIDTH 64
-
-/* INT_ACK_KER: Kernel interrupt acknowledge register */
-#define FR_AA_INT_ACK_KER 0x00000050
-#define FRF_AA_INT_ACK_KER_FIELD_LBN 0
-#define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32
-
-/* INT_ISR0_REG: Function 0 Interrupt Acknowledge Status register */
-#define FR_BZ_INT_ISR0 0x00000090
-#define FRF_BZ_INT_ISR_REG_LBN 0
-#define FRF_BZ_INT_ISR_REG_WIDTH 64
-
-/* HW_INIT_REG: Hardware initialization register */
-#define FR_AZ_HW_INIT 0x000000c0
-#define FRF_BB_BDMRD_CPLF_FULL_LBN 124
-#define FRF_BB_BDMRD_CPLF_FULL_WIDTH 1
-#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121
-#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3
-#define FRF_CZ_TX_MRG_TAGS_LBN 120
-#define FRF_CZ_TX_MRG_TAGS_WIDTH 1
-#define FRF_AB_TRGT_MASK_ALL_LBN 100
-#define FRF_AB_TRGT_MASK_ALL_WIDTH 1
-#define FRF_AZ_DOORBELL_DROP_LBN 92
-#define FRF_AZ_DOORBELL_DROP_WIDTH 8
-#define FRF_AB_TX_RREQ_MASK_EN_LBN 76
-#define FRF_AB_TX_RREQ_MASK_EN_WIDTH 1
-#define FRF_AB_PE_EIDLE_DIS_LBN 75
-#define FRF_AB_PE_EIDLE_DIS_WIDTH 1
-#define FRF_AA_FC_BLOCKING_EN_LBN 45
-#define FRF_AA_FC_BLOCKING_EN_WIDTH 1
-#define FRF_BZ_B2B_REQ_EN_LBN 45
-#define FRF_BZ_B2B_REQ_EN_WIDTH 1
-#define FRF_AA_B2B_REQ_EN_LBN 44
-#define FRF_AA_B2B_REQ_EN_WIDTH 1
-#define FRF_BB_FC_BLOCKING_EN_LBN 44
-#define FRF_BB_FC_BLOCKING_EN_WIDTH 1
-#define FRF_AZ_POST_WR_MASK_LBN 40
-#define FRF_AZ_POST_WR_MASK_WIDTH 4
-#define FRF_AZ_TLP_TC_LBN 34
-#define FRF_AZ_TLP_TC_WIDTH 3
-#define FRF_AZ_TLP_ATTR_LBN 32
-#define FRF_AZ_TLP_ATTR_WIDTH 2
-#define FRF_AB_INTB_VEC_LBN 24
-#define FRF_AB_INTB_VEC_WIDTH 5
-#define FRF_AB_INTA_VEC_LBN 16
-#define FRF_AB_INTA_VEC_WIDTH 5
-#define FRF_AZ_WD_TIMER_LBN 8
-#define FRF_AZ_WD_TIMER_WIDTH 8
-#define FRF_AZ_US_DISABLE_LBN 5
-#define FRF_AZ_US_DISABLE_WIDTH 1
-#define FRF_AZ_TLP_EP_LBN 4
-#define FRF_AZ_TLP_EP_WIDTH 1
-#define FRF_AZ_ATTR_SEL_LBN 3
-#define FRF_AZ_ATTR_SEL_WIDTH 1
-#define FRF_AZ_TD_SEL_LBN 1
-#define FRF_AZ_TD_SEL_WIDTH 1
-#define FRF_AZ_TLP_TD_LBN 0
-#define FRF_AZ_TLP_TD_WIDTH 1
-
-/* EE_SPI_HCMD_REG: SPI host command register */
-#define FR_AB_EE_SPI_HCMD 0x00000100
-#define FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31
-#define FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1
-#define FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28
-#define FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1
-#define FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24
-#define FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1
-#define FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16
-#define FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5
-#define FRF_AB_EE_SPI_HCMD_READ_LBN 15
-#define FRF_AB_EE_SPI_HCMD_READ_WIDTH 1
-#define FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12
-#define FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2
-#define FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8
-#define FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2
-#define FRF_AB_EE_SPI_HCMD_ENC_LBN 0
-#define FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8
-
-/* USR_EV_CFG: User Level Event Configuration register */
-#define FR_CZ_USR_EV_CFG 0x00000100
-#define FRF_CZ_USREV_DIS_LBN 16
-#define FRF_CZ_USREV_DIS_WIDTH 1
-#define FRF_CZ_DFLT_EVQ_LBN 0
-#define FRF_CZ_DFLT_EVQ_WIDTH 10
-
-/* EE_SPI_HADR_REG: SPI host address register */
-#define FR_AB_EE_SPI_HADR 0x00000110
-#define FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24
-#define FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8
-#define FRF_AB_EE_SPI_HADR_ADR_LBN 0
-#define FRF_AB_EE_SPI_HADR_ADR_WIDTH 24
-
-/* EE_SPI_HDATA_REG: SPI host data register */
-#define FR_AB_EE_SPI_HDATA 0x00000120
-#define FRF_AB_EE_SPI_HDATA3_LBN 96
-#define FRF_AB_EE_SPI_HDATA3_WIDTH 32
-#define FRF_AB_EE_SPI_HDATA2_LBN 64
-#define FRF_AB_EE_SPI_HDATA2_WIDTH 32
-#define FRF_AB_EE_SPI_HDATA1_LBN 32
-#define FRF_AB_EE_SPI_HDATA1_WIDTH 32
-#define FRF_AB_EE_SPI_HDATA0_LBN 0
-#define FRF_AB_EE_SPI_HDATA0_WIDTH 32
-
-/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */
-#define FR_AB_EE_BASE_PAGE 0x00000130
-#define FRF_AB_EE_EXPROM_MASK_LBN 16
-#define FRF_AB_EE_EXPROM_MASK_WIDTH 13
-#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0
-#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13
-
-/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */
-#define FR_AB_EE_VPD_CFG0 0x00000140
-#define FRF_AB_EE_SF_FASTRD_EN_LBN 127
-#define FRF_AB_EE_SF_FASTRD_EN_WIDTH 1
-#define FRF_AB_EE_SF_CLOCK_DIV_LBN 120
-#define FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7
-#define FRF_AB_EE_VPD_WIP_POLL_LBN 119
-#define FRF_AB_EE_VPD_WIP_POLL_WIDTH 1
-#define FRF_AB_EE_EE_CLOCK_DIV_LBN 112
-#define FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7
-#define FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96
-#define FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16
-#define FRF_AB_EE_VPDW_LENGTH_LBN 80
-#define FRF_AB_EE_VPDW_LENGTH_WIDTH 15
-#define FRF_AB_EE_VPDW_BASE_LBN 64
-#define FRF_AB_EE_VPDW_BASE_WIDTH 15
-#define FRF_AB_EE_VPD_WR_CMD_EN_LBN 56
-#define FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8
-#define FRF_AB_EE_VPD_BASE_LBN 32
-#define FRF_AB_EE_VPD_BASE_WIDTH 24
-#define FRF_AB_EE_VPD_LENGTH_LBN 16
-#define FRF_AB_EE_VPD_LENGTH_WIDTH 15
-#define FRF_AB_EE_VPD_AD_SIZE_LBN 8
-#define FRF_AB_EE_VPD_AD_SIZE_WIDTH 5
-#define FRF_AB_EE_VPD_ACCESS_ON_LBN 5
-#define FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1
-#define FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4
-#define FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1
-#define FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2
-#define FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1
-#define FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1
-#define FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1
-#define FRF_AB_EE_VPD_EN_LBN 0
-#define FRF_AB_EE_VPD_EN_WIDTH 1
-
-/* EE_VPD_SW_CNTL_REG: VPD access SW control register */
-#define FR_AB_EE_VPD_SW_CNTL 0x00000150
-#define FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31
-#define FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1
-#define FRF_AB_EE_VPD_CYC_WRITE_LBN 28
-#define FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1
-#define FRF_AB_EE_VPD_CYC_ADR_LBN 0
-#define FRF_AB_EE_VPD_CYC_ADR_WIDTH 15
-
-/* EE_VPD_SW_DATA_REG: VPD access SW data register */
-#define FR_AB_EE_VPD_SW_DATA 0x00000160
-#define FRF_AB_EE_VPD_CYC_DAT_LBN 0
-#define FRF_AB_EE_VPD_CYC_DAT_WIDTH 32
-
-/* PBMX_DBG_IADDR_REG: Capture Module address register */
-#define FR_CZ_PBMX_DBG_IADDR 0x000001f0
-#define FRF_CZ_PBMX_DBG_IADDR_LBN 0
-#define FRF_CZ_PBMX_DBG_IADDR_WIDTH 32
-
-/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */
-#define FR_BB_PCIE_CORE_INDIRECT 0x000001f0
-#define FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32
-#define FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32
-#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15
-#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1
-#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0
-#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12
-
-/* PBMX_DBG_IDATA_REG: Capture Module data register */
-#define FR_CZ_PBMX_DBG_IDATA 0x000001f8
-#define FRF_CZ_PBMX_DBG_IDATA_LBN 0
-#define FRF_CZ_PBMX_DBG_IDATA_WIDTH 64
-
-/* NIC_STAT_REG: NIC status register */
-#define FR_AB_NIC_STAT 0x00000200
-#define FRF_BB_AER_DIS_LBN 34
-#define FRF_BB_AER_DIS_WIDTH 1
-#define FRF_BB_EE_STRAP_EN_LBN 31
-#define FRF_BB_EE_STRAP_EN_WIDTH 1
-#define FRF_BB_EE_STRAP_LBN 24
-#define FRF_BB_EE_STRAP_WIDTH 4
-#define FRF_BB_REVISION_ID_LBN 17
-#define FRF_BB_REVISION_ID_WIDTH 7
-#define FRF_AB_ONCHIP_SRAM_LBN 16
-#define FRF_AB_ONCHIP_SRAM_WIDTH 1
-#define FRF_AB_SF_PRST_LBN 9
-#define FRF_AB_SF_PRST_WIDTH 1
-#define FRF_AB_EE_PRST_LBN 8
-#define FRF_AB_EE_PRST_WIDTH 1
-#define FRF_AB_ATE_MODE_LBN 3
-#define FRF_AB_ATE_MODE_WIDTH 1
-#define FRF_AB_STRAP_PINS_LBN 0
-#define FRF_AB_STRAP_PINS_WIDTH 3
-
-/* GPIO_CTL_REG: GPIO control register */
-#define FR_AB_GPIO_CTL 0x00000210
-#define FRF_AB_GPIO_OUT3_LBN 112
-#define FRF_AB_GPIO_OUT3_WIDTH 16
-#define FRF_AB_GPIO_IN3_LBN 104
-#define FRF_AB_GPIO_IN3_WIDTH 8
-#define FRF_AB_GPIO_PWRUP_VALUE3_LBN 96
-#define FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8
-#define FRF_AB_GPIO_OUT2_LBN 80
-#define FRF_AB_GPIO_OUT2_WIDTH 16
-#define FRF_AB_GPIO_IN2_LBN 72
-#define FRF_AB_GPIO_IN2_WIDTH 8
-#define FRF_AB_GPIO_PWRUP_VALUE2_LBN 64
-#define FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8
-#define FRF_AB_GPIO15_OEN_LBN 63
-#define FRF_AB_GPIO15_OEN_WIDTH 1
-#define FRF_AB_GPIO14_OEN_LBN 62
-#define FRF_AB_GPIO14_OEN_WIDTH 1
-#define FRF_AB_GPIO13_OEN_LBN 61
-#define FRF_AB_GPIO13_OEN_WIDTH 1
-#define FRF_AB_GPIO12_OEN_LBN 60
-#define FRF_AB_GPIO12_OEN_WIDTH 1
-#define FRF_AB_GPIO11_OEN_LBN 59
-#define FRF_AB_GPIO11_OEN_WIDTH 1
-#define FRF_AB_GPIO10_OEN_LBN 58
-#define FRF_AB_GPIO10_OEN_WIDTH 1
-#define FRF_AB_GPIO9_OEN_LBN 57
-#define FRF_AB_GPIO9_OEN_WIDTH 1
-#define FRF_AB_GPIO8_OEN_LBN 56
-#define FRF_AB_GPIO8_OEN_WIDTH 1
-#define FRF_AB_GPIO15_OUT_LBN 55
-#define FRF_AB_GPIO15_OUT_WIDTH 1
-#define FRF_AB_GPIO14_OUT_LBN 54
-#define FRF_AB_GPIO14_OUT_WIDTH 1
-#define FRF_AB_GPIO13_OUT_LBN 53
-#define FRF_AB_GPIO13_OUT_WIDTH 1
-#define FRF_AB_GPIO12_OUT_LBN 52
-#define FRF_AB_GPIO12_OUT_WIDTH 1
-#define FRF_AB_GPIO11_OUT_LBN 51
-#define FRF_AB_GPIO11_OUT_WIDTH 1
-#define FRF_AB_GPIO10_OUT_LBN 50
-#define FRF_AB_GPIO10_OUT_WIDTH 1
-#define FRF_AB_GPIO9_OUT_LBN 49
-#define FRF_AB_GPIO9_OUT_WIDTH 1
-#define FRF_AB_GPIO8_OUT_LBN 48
-#define FRF_AB_GPIO8_OUT_WIDTH 1
-#define FRF_AB_GPIO15_IN_LBN 47
-#define FRF_AB_GPIO15_IN_WIDTH 1
-#define FRF_AB_GPIO14_IN_LBN 46
-#define FRF_AB_GPIO14_IN_WIDTH 1
-#define FRF_AB_GPIO13_IN_LBN 45
-#define FRF_AB_GPIO13_IN_WIDTH 1
-#define FRF_AB_GPIO12_IN_LBN 44
-#define FRF_AB_GPIO12_IN_WIDTH 1
-#define FRF_AB_GPIO11_IN_LBN 43
-#define FRF_AB_GPIO11_IN_WIDTH 1
-#define FRF_AB_GPIO10_IN_LBN 42
-#define FRF_AB_GPIO10_IN_WIDTH 1
-#define FRF_AB_GPIO9_IN_LBN 41
-#define FRF_AB_GPIO9_IN_WIDTH 1
-#define FRF_AB_GPIO8_IN_LBN 40
-#define FRF_AB_GPIO8_IN_WIDTH 1
-#define FRF_AB_GPIO15_PWRUP_VALUE_LBN 39
-#define FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO14_PWRUP_VALUE_LBN 38
-#define FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO13_PWRUP_VALUE_LBN 37
-#define FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO12_PWRUP_VALUE_LBN 36
-#define FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO11_PWRUP_VALUE_LBN 35
-#define FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO10_PWRUP_VALUE_LBN 34
-#define FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO9_PWRUP_VALUE_LBN 33
-#define FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO8_PWRUP_VALUE_LBN 32
-#define FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_CLK156_OUT_EN_LBN 31
-#define FRF_AB_CLK156_OUT_EN_WIDTH 1
-#define FRF_AB_USE_NIC_CLK_LBN 30
-#define FRF_AB_USE_NIC_CLK_WIDTH 1
-#define FRF_AB_GPIO5_OEN_LBN 29
-#define FRF_AB_GPIO5_OEN_WIDTH 1
-#define FRF_AB_GPIO4_OEN_LBN 28
-#define FRF_AB_GPIO4_OEN_WIDTH 1
-#define FRF_AB_GPIO3_OEN_LBN 27
-#define FRF_AB_GPIO3_OEN_WIDTH 1
-#define FRF_AB_GPIO2_OEN_LBN 26
-#define FRF_AB_GPIO2_OEN_WIDTH 1
-#define FRF_AB_GPIO1_OEN_LBN 25
-#define FRF_AB_GPIO1_OEN_WIDTH 1
-#define FRF_AB_GPIO0_OEN_LBN 24
-#define FRF_AB_GPIO0_OEN_WIDTH 1
-#define FRF_AB_GPIO7_OUT_LBN 23
-#define FRF_AB_GPIO7_OUT_WIDTH 1
-#define FRF_AB_GPIO6_OUT_LBN 22
-#define FRF_AB_GPIO6_OUT_WIDTH 1
-#define FRF_AB_GPIO5_OUT_LBN 21
-#define FRF_AB_GPIO5_OUT_WIDTH 1
-#define FRF_AB_GPIO4_OUT_LBN 20
-#define FRF_AB_GPIO4_OUT_WIDTH 1
-#define FRF_AB_GPIO3_OUT_LBN 19
-#define FRF_AB_GPIO3_OUT_WIDTH 1
-#define FRF_AB_GPIO2_OUT_LBN 18
-#define FRF_AB_GPIO2_OUT_WIDTH 1
-#define FRF_AB_GPIO1_OUT_LBN 17
-#define FRF_AB_GPIO1_OUT_WIDTH 1
-#define FRF_AB_GPIO0_OUT_LBN 16
-#define FRF_AB_GPIO0_OUT_WIDTH 1
-#define FRF_AB_GPIO7_IN_LBN 15
-#define FRF_AB_GPIO7_IN_WIDTH 1
-#define FRF_AB_GPIO6_IN_LBN 14
-#define FRF_AB_GPIO6_IN_WIDTH 1
-#define FRF_AB_GPIO5_IN_LBN 13
-#define FRF_AB_GPIO5_IN_WIDTH 1
-#define FRF_AB_GPIO4_IN_LBN 12
-#define FRF_AB_GPIO4_IN_WIDTH 1
-#define FRF_AB_GPIO3_IN_LBN 11
-#define FRF_AB_GPIO3_IN_WIDTH 1
-#define FRF_AB_GPIO2_IN_LBN 10
-#define FRF_AB_GPIO2_IN_WIDTH 1
-#define FRF_AB_GPIO1_IN_LBN 9
-#define FRF_AB_GPIO1_IN_WIDTH 1
-#define FRF_AB_GPIO0_IN_LBN 8
-#define FRF_AB_GPIO0_IN_WIDTH 1
-#define FRF_AB_GPIO7_PWRUP_VALUE_LBN 7
-#define FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO6_PWRUP_VALUE_LBN 6
-#define FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO5_PWRUP_VALUE_LBN 5
-#define FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO4_PWRUP_VALUE_LBN 4
-#define FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO3_PWRUP_VALUE_LBN 3
-#define FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO2_PWRUP_VALUE_LBN 2
-#define FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO1_PWRUP_VALUE_LBN 1
-#define FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1
-#define FRF_AB_GPIO0_PWRUP_VALUE_LBN 0
-#define FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1
-
-/* GLB_CTL_REG: Global control register */
-#define FR_AB_GLB_CTL 0x00000220
-#define FRF_AB_EXT_PHY_RST_CTL_LBN 63
-#define FRF_AB_EXT_PHY_RST_CTL_WIDTH 1
-#define FRF_AB_XAUI_SD_RST_CTL_LBN 62
-#define FRF_AB_XAUI_SD_RST_CTL_WIDTH 1
-#define FRF_AB_PCIE_SD_RST_CTL_LBN 61
-#define FRF_AB_PCIE_SD_RST_CTL_WIDTH 1
-#define FRF_AA_PCIX_RST_CTL_LBN 60
-#define FRF_AA_PCIX_RST_CTL_WIDTH 1
-#define FRF_BB_BIU_RST_CTL_LBN 60
-#define FRF_BB_BIU_RST_CTL_WIDTH 1
-#define FRF_AB_PCIE_STKY_RST_CTL_LBN 59
-#define FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1
-#define FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58
-#define FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1
-#define FRF_AB_PCIE_CORE_RST_CTL_LBN 57
-#define FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1
-#define FRF_AB_XGRX_RST_CTL_LBN 56
-#define FRF_AB_XGRX_RST_CTL_WIDTH 1
-#define FRF_AB_XGTX_RST_CTL_LBN 55
-#define FRF_AB_XGTX_RST_CTL_WIDTH 1
-#define FRF_AB_EM_RST_CTL_LBN 54
-#define FRF_AB_EM_RST_CTL_WIDTH 1
-#define FRF_AB_EV_RST_CTL_LBN 53
-#define FRF_AB_EV_RST_CTL_WIDTH 1
-#define FRF_AB_SR_RST_CTL_LBN 52
-#define FRF_AB_SR_RST_CTL_WIDTH 1
-#define FRF_AB_RX_RST_CTL_LBN 51
-#define FRF_AB_RX_RST_CTL_WIDTH 1
-#define FRF_AB_TX_RST_CTL_LBN 50
-#define FRF_AB_TX_RST_CTL_WIDTH 1
-#define FRF_AB_EE_RST_CTL_LBN 49
-#define FRF_AB_EE_RST_CTL_WIDTH 1
-#define FRF_AB_CS_RST_CTL_LBN 48
-#define FRF_AB_CS_RST_CTL_WIDTH 1
-#define FRF_AB_HOT_RST_CTL_LBN 40
-#define FRF_AB_HOT_RST_CTL_WIDTH 2
-#define FRF_AB_RST_EXT_PHY_LBN 31
-#define FRF_AB_RST_EXT_PHY_WIDTH 1
-#define FRF_AB_RST_XAUI_SD_LBN 30
-#define FRF_AB_RST_XAUI_SD_WIDTH 1
-#define FRF_AB_RST_PCIE_SD_LBN 29
-#define FRF_AB_RST_PCIE_SD_WIDTH 1
-#define FRF_AA_RST_PCIX_LBN 28
-#define FRF_AA_RST_PCIX_WIDTH 1
-#define FRF_BB_RST_BIU_LBN 28
-#define FRF_BB_RST_BIU_WIDTH 1
-#define FRF_AB_RST_PCIE_STKY_LBN 27
-#define FRF_AB_RST_PCIE_STKY_WIDTH 1
-#define FRF_AB_RST_PCIE_NSTKY_LBN 26
-#define FRF_AB_RST_PCIE_NSTKY_WIDTH 1
-#define FRF_AB_RST_PCIE_CORE_LBN 25
-#define FRF_AB_RST_PCIE_CORE_WIDTH 1
-#define FRF_AB_RST_XGRX_LBN 24
-#define FRF_AB_RST_XGRX_WIDTH 1
-#define FRF_AB_RST_XGTX_LBN 23
-#define FRF_AB_RST_XGTX_WIDTH 1
-#define FRF_AB_RST_EM_LBN 22
-#define FRF_AB_RST_EM_WIDTH 1
-#define FRF_AB_RST_EV_LBN 21
-#define FRF_AB_RST_EV_WIDTH 1
-#define FRF_AB_RST_SR_LBN 20
-#define FRF_AB_RST_SR_WIDTH 1
-#define FRF_AB_RST_RX_LBN 19
-#define FRF_AB_RST_RX_WIDTH 1
-#define FRF_AB_RST_TX_LBN 18
-#define FRF_AB_RST_TX_WIDTH 1
-#define FRF_AB_RST_SF_LBN 17
-#define FRF_AB_RST_SF_WIDTH 1
-#define FRF_AB_RST_CS_LBN 16
-#define FRF_AB_RST_CS_WIDTH 1
-#define FRF_AB_INT_RST_DUR_LBN 4
-#define FRF_AB_INT_RST_DUR_WIDTH 3
-#define FRF_AB_EXT_PHY_RST_DUR_LBN 1
-#define FRF_AB_EXT_PHY_RST_DUR_WIDTH 3
-#define FFE_AB_EXT_PHY_RST_DUR_10240US 7
-#define FFE_AB_EXT_PHY_RST_DUR_5120US 6
-#define FFE_AB_EXT_PHY_RST_DUR_2560US 5
-#define FFE_AB_EXT_PHY_RST_DUR_1280US 4
-#define FFE_AB_EXT_PHY_RST_DUR_640US 3
-#define FFE_AB_EXT_PHY_RST_DUR_320US 2
-#define FFE_AB_EXT_PHY_RST_DUR_160US 1
-#define FFE_AB_EXT_PHY_RST_DUR_80US 0
-#define FRF_AB_SWRST_LBN 0
-#define FRF_AB_SWRST_WIDTH 1
-
-/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
-#define FR_AZ_FATAL_INTR_KER 0x00000230
-#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44
-#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1
-#define FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43
-#define FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1
-#define FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43
-#define FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1
-#define FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42
-#define FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1
-#define FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41
-#define FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1
-#define FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40
-#define FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1
-#define FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39
-#define FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1
-#define FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38
-#define FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1
-#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37
-#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1
-#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36
-#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1
-#define FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35
-#define FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1
-#define FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34
-#define FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1
-#define FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33
-#define FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1
-#define FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32
-#define FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1
-#define FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12
-#define FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1
-#define FRF_AB_PCI_BUSERR_INT_KER_LBN 11
-#define FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1
-#define FRF_CZ_MBU_PERR_INT_KER_LBN 11
-#define FRF_CZ_MBU_PERR_INT_KER_WIDTH 1
-#define FRF_AZ_SRAM_OOB_INT_KER_LBN 10
-#define FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1
-#define FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9
-#define FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1
-#define FRF_AZ_MEM_PERR_INT_KER_LBN 8
-#define FRF_AZ_MEM_PERR_INT_KER_WIDTH 1
-#define FRF_AZ_RBUF_OWN_INT_KER_LBN 7
-#define FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1
-#define FRF_AZ_TBUF_OWN_INT_KER_LBN 6
-#define FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1
-#define FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5
-#define FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1
-#define FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4
-#define FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1
-#define FRF_AZ_EVQ_OWN_INT_KER_LBN 3
-#define FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1
-#define FRF_AZ_EVF_OFLO_INT_KER_LBN 2
-#define FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1
-#define FRF_AZ_ILL_ADR_INT_KER_LBN 1
-#define FRF_AZ_ILL_ADR_INT_KER_WIDTH 1
-#define FRF_AZ_SRM_PERR_INT_KER_LBN 0
-#define FRF_AZ_SRM_PERR_INT_KER_WIDTH 1
-
-/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */
-#define FR_BZ_FATAL_INTR_CHAR 0x00000240
-#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44
-#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1
-#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43
-#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1
-#define FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43
-#define FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42
-#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41
-#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40
-#define FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39
-#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38
-#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37
-#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36
-#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35
-#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34
-#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33
-#define FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1
-#define FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32
-#define FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1
-#define FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12
-#define FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1
-#define FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11
-#define FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1
-#define FRF_CZ_MBU_PERR_INT_CHAR_LBN 11
-#define FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1
-#define FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10
-#define FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1
-#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9
-#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1
-#define FRF_BZ_MEM_PERR_INT_CHAR_LBN 8
-#define FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1
-#define FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7
-#define FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1
-#define FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6
-#define FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1
-#define FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5
-#define FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1
-#define FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4
-#define FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1
-#define FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3
-#define FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1
-#define FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2
-#define FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1
-#define FRF_BZ_ILL_ADR_INT_CHAR_LBN 1
-#define FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1
-#define FRF_BZ_SRM_PERR_INT_CHAR_LBN 0
-#define FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1
-
-/* DP_CTRL_REG: Datapath control register */
-#define FR_BZ_DP_CTRL 0x00000250
-#define FRF_BZ_FLS_EVQ_ID_LBN 0
-#define FRF_BZ_FLS_EVQ_ID_WIDTH 12
-
-/* MEM_STAT_REG: Memory status register */
-#define FR_AZ_MEM_STAT 0x00000260
-#define FRF_AB_MEM_PERR_VEC_LBN 53
-#define FRF_AB_MEM_PERR_VEC_WIDTH 38
-#define FRF_AB_MBIST_CORR_LBN 38
-#define FRF_AB_MBIST_CORR_WIDTH 15
-#define FRF_AB_MBIST_ERR_LBN 0
-#define FRF_AB_MBIST_ERR_WIDTH 40
-#define FRF_CZ_MEM_PERR_VEC_LBN 0
-#define FRF_CZ_MEM_PERR_VEC_WIDTH 35
-
-/* CS_DEBUG_REG: Debug register */
-#define FR_AZ_CS_DEBUG 0x00000270
-#define FRF_AB_GLB_DEBUG2_SEL_LBN 50
-#define FRF_AB_GLB_DEBUG2_SEL_WIDTH 3
-#define FRF_AB_DEBUG_BLK_SEL2_LBN 47
-#define FRF_AB_DEBUG_BLK_SEL2_WIDTH 3
-#define FRF_AB_DEBUG_BLK_SEL1_LBN 44
-#define FRF_AB_DEBUG_BLK_SEL1_WIDTH 3
-#define FRF_AB_DEBUG_BLK_SEL0_LBN 41
-#define FRF_AB_DEBUG_BLK_SEL0_WIDTH 3
-#define FRF_CZ_CS_PORT_NUM_LBN 40
-#define FRF_CZ_CS_PORT_NUM_WIDTH 2
-#define FRF_AB_MISC_DEBUG_ADDR_LBN 36
-#define FRF_AB_MISC_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_SERDES_DEBUG_ADDR_LBN 31
-#define FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5
-#define FRF_CZ_CS_PORT_FPE_LBN 1
-#define FRF_CZ_CS_PORT_FPE_WIDTH 35
-#define FRF_AB_EM_DEBUG_ADDR_LBN 26
-#define FRF_AB_EM_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_SR_DEBUG_ADDR_LBN 21
-#define FRF_AB_SR_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_EV_DEBUG_ADDR_LBN 16
-#define FRF_AB_EV_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_RX_DEBUG_ADDR_LBN 11
-#define FRF_AB_RX_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_TX_DEBUG_ADDR_LBN 6
-#define FRF_AB_TX_DEBUG_ADDR_WIDTH 5
-#define FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1
-#define FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5
-#define FRF_AZ_CS_DEBUG_EN_LBN 0
-#define FRF_AZ_CS_DEBUG_EN_WIDTH 1
-
-/* DRIVER_REG: Driver scratch register [0-7] */
-#define FR_AZ_DRIVER 0x00000280
-#define FR_AZ_DRIVER_STEP 16
-#define FR_AZ_DRIVER_ROWS 8
-#define FRF_AZ_DRIVER_DW0_LBN 0
-#define FRF_AZ_DRIVER_DW0_WIDTH 32
-
-/* ALTERA_BUILD_REG: Altera build register */
-#define FR_AZ_ALTERA_BUILD 0x00000300
-#define FRF_AZ_ALTERA_BUILD_VER_LBN 0
-#define FRF_AZ_ALTERA_BUILD_VER_WIDTH 32
-
-/* CSR_SPARE_REG: Spare register */
-#define FR_AZ_CSR_SPARE 0x00000310
-#define FRF_AB_MEM_PERR_EN_LBN 64
-#define FRF_AB_MEM_PERR_EN_WIDTH 38
-#define FRF_CZ_MEM_PERR_EN_LBN 64
-#define FRF_CZ_MEM_PERR_EN_WIDTH 35
-#define FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72
-#define FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2
-#define FRF_AZ_CSR_SPARE_BITS_LBN 0
-#define FRF_AZ_CSR_SPARE_BITS_WIDTH 32
-
-/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */
-#define FR_AB_PCIE_SD_CTL0123 0x00000320
-#define FRF_AB_PCIE_TESTSIG_H_LBN 96
-#define FRF_AB_PCIE_TESTSIG_H_WIDTH 19
-#define FRF_AB_PCIE_TESTSIG_L_LBN 64
-#define FRF_AB_PCIE_TESTSIG_L_WIDTH 19
-#define FRF_AB_PCIE_OFFSET_LBN 56
-#define FRF_AB_PCIE_OFFSET_WIDTH 8
-#define FRF_AB_PCIE_OFFSETEN_H_LBN 55
-#define FRF_AB_PCIE_OFFSETEN_H_WIDTH 1
-#define FRF_AB_PCIE_OFFSETEN_L_LBN 54
-#define FRF_AB_PCIE_OFFSETEN_L_WIDTH 1
-#define FRF_AB_PCIE_HIVMODE_H_LBN 53
-#define FRF_AB_PCIE_HIVMODE_H_WIDTH 1
-#define FRF_AB_PCIE_HIVMODE_L_LBN 52
-#define FRF_AB_PCIE_HIVMODE_L_WIDTH 1
-#define FRF_AB_PCIE_PARRESET_H_LBN 51
-#define FRF_AB_PCIE_PARRESET_H_WIDTH 1
-#define FRF_AB_PCIE_PARRESET_L_LBN 50
-#define FRF_AB_PCIE_PARRESET_L_WIDTH 1
-#define FRF_AB_PCIE_LPBKWDRV_H_LBN 49
-#define FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1
-#define FRF_AB_PCIE_LPBKWDRV_L_LBN 48
-#define FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1
-#define FRF_AB_PCIE_LPBK_LBN 40
-#define FRF_AB_PCIE_LPBK_WIDTH 8
-#define FRF_AB_PCIE_PARLPBK_LBN 32
-#define FRF_AB_PCIE_PARLPBK_WIDTH 8
-#define FRF_AB_PCIE_RXTERMADJ_H_LBN 30
-#define FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2
-#define FRF_AB_PCIE_RXTERMADJ_L_LBN 28
-#define FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2
-#define FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3
-#define FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2
-#define FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1
-#define FFE_AB_PCIE_RXTERMADJ_NOMNL 0
-#define FRF_AB_PCIE_TXTERMADJ_H_LBN 26
-#define FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2
-#define FRF_AB_PCIE_TXTERMADJ_L_LBN 24
-#define FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2
-#define FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3
-#define FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2
-#define FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1
-#define FFE_AB_PCIE_TXTERMADJ_NOMNL 0
-#define FRF_AB_PCIE_RXEQCTL_H_LBN 18
-#define FRF_AB_PCIE_RXEQCTL_H_WIDTH 2
-#define FRF_AB_PCIE_RXEQCTL_L_LBN 16
-#define FRF_AB_PCIE_RXEQCTL_L_WIDTH 2
-#define FFE_AB_PCIE_RXEQCTL_OFF_ALT 3
-#define FFE_AB_PCIE_RXEQCTL_OFF 2
-#define FFE_AB_PCIE_RXEQCTL_MIN 1
-#define FFE_AB_PCIE_RXEQCTL_MAX 0
-#define FRF_AB_PCIE_HIDRV_LBN 8
-#define FRF_AB_PCIE_HIDRV_WIDTH 8
-#define FRF_AB_PCIE_LODRV_LBN 0
-#define FRF_AB_PCIE_LODRV_WIDTH 8
-
-/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */
-#define FR_AB_PCIE_SD_CTL45 0x00000330
-#define FRF_AB_PCIE_DTX7_LBN 60
-#define FRF_AB_PCIE_DTX7_WIDTH 4
-#define FRF_AB_PCIE_DTX6_LBN 56
-#define FRF_AB_PCIE_DTX6_WIDTH 4
-#define FRF_AB_PCIE_DTX5_LBN 52
-#define FRF_AB_PCIE_DTX5_WIDTH 4
-#define FRF_AB_PCIE_DTX4_LBN 48
-#define FRF_AB_PCIE_DTX4_WIDTH 4
-#define FRF_AB_PCIE_DTX3_LBN 44
-#define FRF_AB_PCIE_DTX3_WIDTH 4
-#define FRF_AB_PCIE_DTX2_LBN 40
-#define FRF_AB_PCIE_DTX2_WIDTH 4
-#define FRF_AB_PCIE_DTX1_LBN 36
-#define FRF_AB_PCIE_DTX1_WIDTH 4
-#define FRF_AB_PCIE_DTX0_LBN 32
-#define FRF_AB_PCIE_DTX0_WIDTH 4
-#define FRF_AB_PCIE_DEQ7_LBN 28
-#define FRF_AB_PCIE_DEQ7_WIDTH 4
-#define FRF_AB_PCIE_DEQ6_LBN 24
-#define FRF_AB_PCIE_DEQ6_WIDTH 4
-#define FRF_AB_PCIE_DEQ5_LBN 20
-#define FRF_AB_PCIE_DEQ5_WIDTH 4
-#define FRF_AB_PCIE_DEQ4_LBN 16
-#define FRF_AB_PCIE_DEQ4_WIDTH 4
-#define FRF_AB_PCIE_DEQ3_LBN 12
-#define FRF_AB_PCIE_DEQ3_WIDTH 4
-#define FRF_AB_PCIE_DEQ2_LBN 8
-#define FRF_AB_PCIE_DEQ2_WIDTH 4
-#define FRF_AB_PCIE_DEQ1_LBN 4
-#define FRF_AB_PCIE_DEQ1_WIDTH 4
-#define FRF_AB_PCIE_DEQ0_LBN 0
-#define FRF_AB_PCIE_DEQ0_WIDTH 4
-
-/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */
-#define FR_AB_PCIE_PCS_CTL_STAT 0x00000340
-#define FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52
-#define FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4
-#define FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48
-#define FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4
-#define FRF_AB_PCIE_PRBSERR_LBN 40
-#define FRF_AB_PCIE_PRBSERR_WIDTH 8
-#define FRF_AB_PCIE_PRBSERRH0_LBN 32
-#define FRF_AB_PCIE_PRBSERRH0_WIDTH 8
-#define FRF_AB_PCIE_FASTINIT_H_LBN 15
-#define FRF_AB_PCIE_FASTINIT_H_WIDTH 1
-#define FRF_AB_PCIE_FASTINIT_L_LBN 14
-#define FRF_AB_PCIE_FASTINIT_L_WIDTH 1
-#define FRF_AB_PCIE_CTCDISABLE_H_LBN 13
-#define FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1
-#define FRF_AB_PCIE_CTCDISABLE_L_LBN 12
-#define FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1
-#define FRF_AB_PCIE_PRBSSYNC_H_LBN 11
-#define FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1
-#define FRF_AB_PCIE_PRBSSYNC_L_LBN 10
-#define FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1
-#define FRF_AB_PCIE_PRBSERRACK_H_LBN 9
-#define FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1
-#define FRF_AB_PCIE_PRBSERRACK_L_LBN 8
-#define FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1
-#define FRF_AB_PCIE_PRBSSEL_LBN 0
-#define FRF_AB_PCIE_PRBSSEL_WIDTH 8
-
-/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */
-#define FR_BB_DEBUG_DATA_OUT 0x00000350
-#define FRF_BB_DEBUG2_PORT_LBN 25
-#define FRF_BB_DEBUG2_PORT_WIDTH 15
-#define FRF_BB_DEBUG1_PORT_LBN 0
-#define FRF_BB_DEBUG1_PORT_WIDTH 25
-
-/* EVQ_RPTR_REGP0: Event queue read pointer register */
-#define FR_BZ_EVQ_RPTR_P0 0x00000400
-#define FR_BZ_EVQ_RPTR_P0_STEP 8192
-#define FR_BZ_EVQ_RPTR_P0_ROWS 1024
-/* EVQ_RPTR_REG_KER: Event queue read pointer register */
-#define FR_AA_EVQ_RPTR_KER 0x00011b00
-#define FR_AA_EVQ_RPTR_KER_STEP 4
-#define FR_AA_EVQ_RPTR_KER_ROWS 4
-/* EVQ_RPTR_REG: Event queue read pointer register */
-#define FR_BZ_EVQ_RPTR 0x00fa0000
-#define FR_BZ_EVQ_RPTR_STEP 16
-#define FR_BB_EVQ_RPTR_ROWS 4096
-#define FR_CZ_EVQ_RPTR_ROWS 1024
-/* EVQ_RPTR_REGP123: Event queue read pointer register */
-#define FR_BB_EVQ_RPTR_P123 0x01000400
-#define FR_BB_EVQ_RPTR_P123_STEP 8192
-#define FR_BB_EVQ_RPTR_P123_ROWS 3072
-#define FRF_AZ_EVQ_RPTR_VLD_LBN 15
-#define FRF_AZ_EVQ_RPTR_VLD_WIDTH 1
-#define FRF_AZ_EVQ_RPTR_LBN 0
-#define FRF_AZ_EVQ_RPTR_WIDTH 15
-
-/* TIMER_COMMAND_REGP0: Timer Command Registers */
-#define FR_BZ_TIMER_COMMAND_P0 0x00000420
-#define FR_BZ_TIMER_COMMAND_P0_STEP 8192
-#define FR_BZ_TIMER_COMMAND_P0_ROWS 1024
-/* TIMER_COMMAND_REG_KER: Timer Command Registers */
-#define FR_AA_TIMER_COMMAND_KER 0x00000420
-#define FR_AA_TIMER_COMMAND_KER_STEP 8192
-#define FR_AA_TIMER_COMMAND_KER_ROWS 4
-/* TIMER_COMMAND_REGP123: Timer Command Registers */
-#define FR_BB_TIMER_COMMAND_P123 0x01000420
-#define FR_BB_TIMER_COMMAND_P123_STEP 8192
-#define FR_BB_TIMER_COMMAND_P123_ROWS 3072
-#define FRF_CZ_TC_TIMER_MODE_LBN 14
-#define FRF_CZ_TC_TIMER_MODE_WIDTH 2
-#define FRF_AB_TC_TIMER_MODE_LBN 12
-#define FRF_AB_TC_TIMER_MODE_WIDTH 2
-#define FRF_CZ_TC_TIMER_VAL_LBN 0
-#define FRF_CZ_TC_TIMER_VAL_WIDTH 14
-#define FRF_AB_TC_TIMER_VAL_LBN 0
-#define FRF_AB_TC_TIMER_VAL_WIDTH 12
-
-/* DRV_EV_REG: Driver generated event register */
-#define FR_AZ_DRV_EV 0x00000440
-#define FRF_AZ_DRV_EV_QID_LBN 64
-#define FRF_AZ_DRV_EV_QID_WIDTH 12
-#define FRF_AZ_DRV_EV_DATA_LBN 0
-#define FRF_AZ_DRV_EV_DATA_WIDTH 64
-
-/* EVQ_CTL_REG: Event queue control register */
-#define FR_AZ_EVQ_CTL 0x00000450
-#define FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15
-#define FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10
-#define FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15
-#define FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6
-#define FRF_AZ_EVQ_OWNERR_CTL_LBN 14
-#define FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1
-#define FRF_AZ_EVQ_FIFO_AF_TH_LBN 7
-#define FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7
-#define FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0
-#define FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7
-
-/* EVQ_CNT1_REG: Event counter 1 register */
-#define FR_AZ_EVQ_CNT1 0x00000460
-#define FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120
-#define FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7
-#define FRF_AZ_EVQ_CNT_TOBIU_LBN 100
-#define FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20
-#define FRF_AZ_EVQ_TX_REQ_CNT_LBN 80
-#define FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_RX_REQ_CNT_LBN 60
-#define FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_EM_REQ_CNT_LBN 40
-#define FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20
-#define FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0
-#define FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20
-
-/* EVQ_CNT2_REG: Event counter 2 register */
-#define FR_AZ_EVQ_CNT2 0x00000470
-#define FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104
-#define FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84
-#define FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_RDY_CNT_LBN 80
-#define FRF_AZ_EVQ_RDY_CNT_WIDTH 4
-#define FRF_AZ_EVQ_WU_REQ_CNT_LBN 60
-#define FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_WET_REQ_CNT_LBN 40
-#define FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20
-#define FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20
-#define FRF_AZ_EVQ_TM_REQ_CNT_LBN 0
-#define FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20
-
-/* USR_EV_REG: Event mailbox register */
-#define FR_CZ_USR_EV 0x00000540
-#define FR_CZ_USR_EV_STEP 8192
-#define FR_CZ_USR_EV_ROWS 1024
-#define FRF_CZ_USR_EV_DATA_LBN 0
-#define FRF_CZ_USR_EV_DATA_WIDTH 32
-
-/* BUF_TBL_CFG_REG: Buffer table configuration register */
-#define FR_AZ_BUF_TBL_CFG 0x00000600
-#define FRF_AZ_BUF_TBL_MODE_LBN 3
-#define FRF_AZ_BUF_TBL_MODE_WIDTH 1
-
-/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */
-#define FR_AZ_SRM_RX_DC_CFG 0x00000610
-#define FRF_AZ_SRM_CLK_TMP_EN_LBN 21
-#define FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1
-#define FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0
-#define FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21
-
-/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */
-#define FR_AZ_SRM_TX_DC_CFG 0x00000620
-#define FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0
-#define FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21
-
-/* SRM_CFG_REG: SRAM configuration register */
-#define FR_AZ_SRM_CFG 0x00000630
-#define FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5
-#define FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1
-#define FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4
-#define FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1
-#define FRF_AZ_SRM_INIT_EN_LBN 3
-#define FRF_AZ_SRM_INIT_EN_WIDTH 1
-#define FRF_AZ_SRM_NUM_BANK_LBN 2
-#define FRF_AZ_SRM_NUM_BANK_WIDTH 1
-#define FRF_AZ_SRM_BANK_SIZE_LBN 0
-#define FRF_AZ_SRM_BANK_SIZE_WIDTH 2
-
-/* BUF_TBL_UPD_REG: Buffer table update register */
-#define FR_AZ_BUF_TBL_UPD 0x00000650
-#define FRF_AZ_BUF_UPD_CMD_LBN 63
-#define FRF_AZ_BUF_UPD_CMD_WIDTH 1
-#define FRF_AZ_BUF_CLR_CMD_LBN 62
-#define FRF_AZ_BUF_CLR_CMD_WIDTH 1
-#define FRF_AZ_BUF_CLR_END_ID_LBN 32
-#define FRF_AZ_BUF_CLR_END_ID_WIDTH 20
-#define FRF_AZ_BUF_CLR_START_ID_LBN 0
-#define FRF_AZ_BUF_CLR_START_ID_WIDTH 20
-
-/* SRM_UPD_EVQ_REG: Buffer table update register */
-#define FR_AZ_SRM_UPD_EVQ 0x00000660
-#define FRF_AZ_SRM_UPD_EVQ_ID_LBN 0
-#define FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12
-
-/* SRAM_PARITY_REG: SRAM parity register. */
-#define FR_AZ_SRAM_PARITY 0x00000670
-#define FRF_CZ_BYPASS_ECC_LBN 3
-#define FRF_CZ_BYPASS_ECC_WIDTH 1
-#define FRF_CZ_SEC_INT_LBN 2
-#define FRF_CZ_SEC_INT_WIDTH 1
-#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1
-#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1
-#define FRF_AB_FORCE_SRAM_PERR_LBN 0
-#define FRF_AB_FORCE_SRAM_PERR_WIDTH 1
-#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0
-#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1
-
-/* RX_CFG_REG: Receive configuration register */
-#define FR_AZ_RX_CFG 0x00000800
-#define FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72
-#define FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14
-#define FRF_CZ_RX_HDR_SPLIT_EN_LBN 71
-#define FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1
-#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62
-#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9
-#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53
-#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9
-#define FRF_CZ_RX_PRE_RFF_IPG_LBN 49
-#define FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4
-#define FRF_BZ_RX_TCP_SUP_LBN 48
-#define FRF_BZ_RX_TCP_SUP_WIDTH 1
-#define FRF_BZ_RX_INGR_EN_LBN 47
-#define FRF_BZ_RX_INGR_EN_WIDTH 1
-#define FRF_BZ_RX_IP_HASH_LBN 46
-#define FRF_BZ_RX_IP_HASH_WIDTH 1
-#define FRF_BZ_RX_HASH_ALG_LBN 45
-#define FRF_BZ_RX_HASH_ALG_WIDTH 1
-#define FRF_BZ_RX_HASH_INSRT_HDR_LBN 44
-#define FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1
-#define FRF_BZ_RX_DESC_PUSH_EN_LBN 43
-#define FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1
-#define FRF_BZ_RX_RDW_PATCH_EN_LBN 42
-#define FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1
-#define FRF_BB_RX_PCI_BURST_SIZE_LBN 39
-#define FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3
-#define FRF_BZ_RX_OWNERR_CTL_LBN 38
-#define FRF_BZ_RX_OWNERR_CTL_WIDTH 1
-#define FRF_BZ_RX_XON_TX_TH_LBN 33
-#define FRF_BZ_RX_XON_TX_TH_WIDTH 5
-#define FRF_AA_RX_DESC_PUSH_EN_LBN 35
-#define FRF_AA_RX_DESC_PUSH_EN_WIDTH 1
-#define FRF_AA_RX_RDW_PATCH_EN_LBN 34
-#define FRF_AA_RX_RDW_PATCH_EN_WIDTH 1
-#define FRF_AA_RX_PCI_BURST_SIZE_LBN 31
-#define FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3
-#define FRF_BZ_RX_XOFF_TX_TH_LBN 28
-#define FRF_BZ_RX_XOFF_TX_TH_WIDTH 5
-#define FRF_AA_RX_OWNERR_CTL_LBN 30
-#define FRF_AA_RX_OWNERR_CTL_WIDTH 1
-#define FRF_AA_RX_XON_TX_TH_LBN 25
-#define FRF_AA_RX_XON_TX_TH_WIDTH 5
-#define FRF_BZ_RX_USR_BUF_SIZE_LBN 19
-#define FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9
-#define FRF_AA_RX_XOFF_TX_TH_LBN 20
-#define FRF_AA_RX_XOFF_TX_TH_WIDTH 5
-#define FRF_AA_RX_USR_BUF_SIZE_LBN 11
-#define FRF_AA_RX_USR_BUF_SIZE_WIDTH 9
-#define FRF_BZ_RX_XON_MAC_TH_LBN 10
-#define FRF_BZ_RX_XON_MAC_TH_WIDTH 9
-#define FRF_AA_RX_XON_MAC_TH_LBN 6
-#define FRF_AA_RX_XON_MAC_TH_WIDTH 5
-#define FRF_BZ_RX_XOFF_MAC_TH_LBN 1
-#define FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9
-#define FRF_AA_RX_XOFF_MAC_TH_LBN 1
-#define FRF_AA_RX_XOFF_MAC_TH_WIDTH 5
-#define FRF_AZ_RX_XOFF_MAC_EN_LBN 0
-#define FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1
-
-/* RX_FILTER_CTL_REG: Receive filter control registers */
-#define FR_BZ_RX_FILTER_CTL 0x00000810
-#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94
-#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8
-#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86
-#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8
-#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85
-#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1
-#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69
-#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16
-#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57
-#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12
-#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56
-#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1
-#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55
-#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
-#define FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43
-#define FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12
-#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42
-#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1
-#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41
-#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
-#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40
-#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1
-#define FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32
-#define FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8
-#define FRF_BZ_NUM_KER_LBN 24
-#define FRF_BZ_NUM_KER_WIDTH 2
-#define FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16
-#define FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8
-#define FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8
-#define FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8
-#define FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0
-#define FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8
-
-/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */
-#define FR_AZ_RX_FLUSH_DESCQ 0x00000820
-#define FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24
-#define FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1
-#define FRF_AZ_RX_FLUSH_DESCQ_LBN 0
-#define FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12
-
-/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
-#define FR_BZ_RX_DESC_UPD_P0 0x00000830
-#define FR_BZ_RX_DESC_UPD_P0_STEP 8192
-#define FR_BZ_RX_DESC_UPD_P0_ROWS 1024
-/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */
-#define FR_AA_RX_DESC_UPD_KER 0x00000830
-#define FR_AA_RX_DESC_UPD_KER_STEP 8192
-#define FR_AA_RX_DESC_UPD_KER_ROWS 4
-/* RX_DESC_UPD_REGP123: Receive descriptor update register. */
-#define FR_BB_RX_DESC_UPD_P123 0x01000830
-#define FR_BB_RX_DESC_UPD_P123_STEP 8192
-#define FR_BB_RX_DESC_UPD_P123_ROWS 3072
-#define FRF_AZ_RX_DESC_WPTR_LBN 96
-#define FRF_AZ_RX_DESC_WPTR_WIDTH 12
-#define FRF_AZ_RX_DESC_PUSH_CMD_LBN 95
-#define FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1
-#define FRF_AZ_RX_DESC_LBN 0
-#define FRF_AZ_RX_DESC_WIDTH 64
-
-/* RX_DC_CFG_REG: Receive descriptor cache configuration register */
-#define FR_AZ_RX_DC_CFG 0x00000840
-#define FRF_AB_RX_MAX_PF_LBN 2
-#define FRF_AB_RX_MAX_PF_WIDTH 2
-#define FRF_AZ_RX_DC_SIZE_LBN 0
-#define FRF_AZ_RX_DC_SIZE_WIDTH 2
-#define FFE_AZ_RX_DC_SIZE_64 3
-#define FFE_AZ_RX_DC_SIZE_32 2
-#define FFE_AZ_RX_DC_SIZE_16 1
-#define FFE_AZ_RX_DC_SIZE_8 0
-
-/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */
-#define FR_AZ_RX_DC_PF_WM 0x00000850
-#define FRF_AZ_RX_DC_PF_HWM_LBN 6
-#define FRF_AZ_RX_DC_PF_HWM_WIDTH 6
-#define FRF_AZ_RX_DC_PF_LWM_LBN 0
-#define FRF_AZ_RX_DC_PF_LWM_WIDTH 6
-
-/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */
-#define FR_BZ_RX_RSS_TKEY 0x00000860
-#define FRF_BZ_RX_RSS_TKEY_HI_LBN 64
-#define FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64
-#define FRF_BZ_RX_RSS_TKEY_LO_LBN 0
-#define FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64
-
-/* RX_NODESC_DROP_REG: Receive dropped packet counter register */
-#define FR_AZ_RX_NODESC_DROP 0x00000880
-#define FRF_CZ_RX_NODESC_DROP_CNT_LBN 0
-#define FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32
-#define FRF_AB_RX_NODESC_DROP_CNT_LBN 0
-#define FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16
-
-/* RX_SELF_RST_REG: Receive self reset register */
-#define FR_AA_RX_SELF_RST 0x00000890
-#define FRF_AA_RX_ISCSI_DIS_LBN 17
-#define FRF_AA_RX_ISCSI_DIS_WIDTH 1
-#define FRF_AA_RX_SW_RST_REG_LBN 16
-#define FRF_AA_RX_SW_RST_REG_WIDTH 1
-#define FRF_AA_RX_NODESC_WAIT_DIS_LBN 9
-#define FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1
-#define FRF_AA_RX_SELF_RST_EN_LBN 8
-#define FRF_AA_RX_SELF_RST_EN_WIDTH 1
-#define FRF_AA_RX_MAX_PF_LAT_LBN 4
-#define FRF_AA_RX_MAX_PF_LAT_WIDTH 4
-#define FRF_AA_RX_MAX_LU_LAT_LBN 0
-#define FRF_AA_RX_MAX_LU_LAT_WIDTH 4
-
-/* RX_DEBUG_REG: undocumented register */
-#define FR_AZ_RX_DEBUG 0x000008a0
-#define FRF_AZ_RX_DEBUG_LBN 0
-#define FRF_AZ_RX_DEBUG_WIDTH 64
-
-/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */
-#define FR_AZ_RX_PUSH_DROP 0x000008b0
-#define FRF_AZ_RX_PUSH_DROP_CNT_LBN 0
-#define FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32
-
-/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */
-#define FR_CZ_RX_RSS_IPV6_REG1 0x000008d0
-#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0
-#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128
-
-/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */
-#define FR_CZ_RX_RSS_IPV6_REG2 0x000008e0
-#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0
-#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128
-
-/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */
-#define FR_CZ_RX_RSS_IPV6_REG3 0x000008f0
-#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66
-#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1
-#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65
-#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1
-#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64
-#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1
-#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0
-#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64
-
-/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */
-#define FR_AZ_TX_FLUSH_DESCQ 0x00000a00
-#define FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12
-#define FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1
-#define FRF_AZ_TX_FLUSH_DESCQ_LBN 0
-#define FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12
-
-/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
-#define FR_BZ_TX_DESC_UPD_P0 0x00000a10
-#define FR_BZ_TX_DESC_UPD_P0_STEP 8192
-#define FR_BZ_TX_DESC_UPD_P0_ROWS 1024
-/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */
-#define FR_AA_TX_DESC_UPD_KER 0x00000a10
-#define FR_AA_TX_DESC_UPD_KER_STEP 8192
-#define FR_AA_TX_DESC_UPD_KER_ROWS 8
-/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */
-#define FR_BB_TX_DESC_UPD_P123 0x01000a10
-#define FR_BB_TX_DESC_UPD_P123_STEP 8192
-#define FR_BB_TX_DESC_UPD_P123_ROWS 3072
-#define FRF_AZ_TX_DESC_WPTR_LBN 96
-#define FRF_AZ_TX_DESC_WPTR_WIDTH 12
-#define FRF_AZ_TX_DESC_PUSH_CMD_LBN 95
-#define FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1
-#define FRF_AZ_TX_DESC_LBN 0
-#define FRF_AZ_TX_DESC_WIDTH 95
-
-/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */
-#define FR_AZ_TX_DC_CFG 0x00000a20
-#define FRF_AZ_TX_DC_SIZE_LBN 0
-#define FRF_AZ_TX_DC_SIZE_WIDTH 2
-#define FFE_AZ_TX_DC_SIZE_32 2
-#define FFE_AZ_TX_DC_SIZE_16 1
-#define FFE_AZ_TX_DC_SIZE_8 0
-
-/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */
-#define FR_AA_TX_CHKSM_CFG 0x00000a30
-#define FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96
-#define FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32
-#define FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64
-#define FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32
-#define FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32
-#define FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32
-#define FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0
-#define FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32
-
-/* TX_CFG_REG: Transmit configuration register */
-#define FR_AZ_TX_CFG 0x00000a50
-#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114
-#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8
-#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113
-#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1
-#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105
-#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97
-#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89
-#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81
-#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73
-#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65
-#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
-#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64
-#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1
-#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48
-#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16
-#define FRF_CZ_TX_FILTER_EN_BIT_LBN 47
-#define FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1
-#define FRF_AZ_TX_IP_ID_P0_OFS_LBN 16
-#define FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15
-#define FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5
-#define FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1
-#define FRF_AZ_TX_P1_PRI_EN_LBN 4
-#define FRF_AZ_TX_P1_PRI_EN_WIDTH 1
-#define FRF_AZ_TX_OWNERR_CTL_LBN 2
-#define FRF_AZ_TX_OWNERR_CTL_WIDTH 1
-#define FRF_AA_TX_NON_IP_DROP_DIS_LBN 1
-#define FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1
-#define FRF_AZ_TX_IP_ID_REP_EN_LBN 0
-#define FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1
-
-/* TX_PUSH_DROP_REG: Transmit push dropped register */
-#define FR_AZ_TX_PUSH_DROP 0x00000a60
-#define FRF_AZ_TX_PUSH_DROP_CNT_LBN 0
-#define FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32
-
-/* TX_RESERVED_REG: Transmit configuration register */
-#define FR_AZ_TX_RESERVED 0x00000a80
-#define FRF_AZ_TX_EVT_CNT_LBN 121
-#define FRF_AZ_TX_EVT_CNT_WIDTH 7
-#define FRF_AZ_TX_PREF_AGE_CNT_LBN 119
-#define FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2
-#define FRF_AZ_TX_RD_COMP_TMR_LBN 96
-#define FRF_AZ_TX_RD_COMP_TMR_WIDTH 23
-#define FRF_AZ_TX_PUSH_EN_LBN 89
-#define FRF_AZ_TX_PUSH_EN_WIDTH 1
-#define FRF_AZ_TX_PUSH_CHK_DIS_LBN 88
-#define FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1
-#define FRF_AZ_TX_D_FF_FULL_P0_LBN 85
-#define FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1
-#define FRF_AZ_TX_DMAR_ST_P0_LBN 81
-#define FRF_AZ_TX_DMAR_ST_P0_WIDTH 1
-#define FRF_AZ_TX_DMAQ_ST_LBN 78
-#define FRF_AZ_TX_DMAQ_ST_WIDTH 1
-#define FRF_AZ_TX_RX_SPACER_LBN 64
-#define FRF_AZ_TX_RX_SPACER_WIDTH 8
-#define FRF_AZ_TX_DROP_ABORT_EN_LBN 60
-#define FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1
-#define FRF_AZ_TX_SOFT_EVT_EN_LBN 59
-#define FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1
-#define FRF_AZ_TX_PS_EVT_DIS_LBN 58
-#define FRF_AZ_TX_PS_EVT_DIS_WIDTH 1
-#define FRF_AZ_TX_RX_SPACER_EN_LBN 57
-#define FRF_AZ_TX_RX_SPACER_EN_WIDTH 1
-#define FRF_AZ_TX_XP_TIMER_LBN 52
-#define FRF_AZ_TX_XP_TIMER_WIDTH 5
-#define FRF_AZ_TX_PREF_SPACER_LBN 44
-#define FRF_AZ_TX_PREF_SPACER_WIDTH 8
-#define FRF_AZ_TX_PREF_WD_TMR_LBN 22
-#define FRF_AZ_TX_PREF_WD_TMR_WIDTH 22
-#define FRF_AZ_TX_ONLY1TAG_LBN 21
-#define FRF_AZ_TX_ONLY1TAG_WIDTH 1
-#define FRF_AZ_TX_PREF_THRESHOLD_LBN 19
-#define FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2
-#define FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18
-#define FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1
-#define FRF_AZ_TX_DIS_NON_IP_EV_LBN 17
-#define FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1
-#define FRF_AA_TX_DMA_FF_THR_LBN 16
-#define FRF_AA_TX_DMA_FF_THR_WIDTH 1
-#define FRF_AZ_TX_DMA_SPACER_LBN 8
-#define FRF_AZ_TX_DMA_SPACER_WIDTH 8
-#define FRF_AA_TX_TCP_DIS_LBN 7
-#define FRF_AA_TX_TCP_DIS_WIDTH 1
-#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7
-#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1
-#define FRF_AA_TX_IP_DIS_LBN 6
-#define FRF_AA_TX_IP_DIS_WIDTH 1
-#define FRF_AZ_TX_MAX_CPL_LBN 2
-#define FRF_AZ_TX_MAX_CPL_WIDTH 2
-#define FFE_AZ_TX_MAX_CPL_16 3
-#define FFE_AZ_TX_MAX_CPL_8 2
-#define FFE_AZ_TX_MAX_CPL_4 1
-#define FFE_AZ_TX_MAX_CPL_NOLIMIT 0
-#define FRF_AZ_TX_MAX_PREF_LBN 0
-#define FRF_AZ_TX_MAX_PREF_WIDTH 2
-#define FFE_AZ_TX_MAX_PREF_32 3
-#define FFE_AZ_TX_MAX_PREF_16 2
-#define FFE_AZ_TX_MAX_PREF_8 1
-#define FFE_AZ_TX_MAX_PREF_OFF 0
-
-/* TX_PACE_REG: Transmit pace control register */
-#define FR_BZ_TX_PACE 0x00000a90
-#define FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19
-#define FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10
-#define FRF_BZ_TX_PACE_SB_AF_LBN 9
-#define FRF_BZ_TX_PACE_SB_AF_WIDTH 10
-#define FRF_BZ_TX_PACE_FB_BASE_LBN 5
-#define FRF_BZ_TX_PACE_FB_BASE_WIDTH 4
-#define FRF_BZ_TX_PACE_BIN_TH_LBN 0
-#define FRF_BZ_TX_PACE_BIN_TH_WIDTH 5
-
-/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */
-#define FR_BZ_TX_PACE_DROP_QID 0x00000aa0
-#define FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0
-#define FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16
-
-/* TX_VLAN_REG: Transmit VLAN tag register */
-#define FR_BB_TX_VLAN 0x00000ae0
-#define FRF_BB_TX_VLAN_EN_LBN 127
-#define FRF_BB_TX_VLAN_EN_WIDTH 1
-#define FRF_BB_TX_VLAN7_PORT1_EN_LBN 125
-#define FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN7_PORT0_EN_LBN 124
-#define FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN7_LBN 112
-#define FRF_BB_TX_VLAN7_WIDTH 12
-#define FRF_BB_TX_VLAN6_PORT1_EN_LBN 109
-#define FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN6_PORT0_EN_LBN 108
-#define FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN6_LBN 96
-#define FRF_BB_TX_VLAN6_WIDTH 12
-#define FRF_BB_TX_VLAN5_PORT1_EN_LBN 93
-#define FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN5_PORT0_EN_LBN 92
-#define FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN5_LBN 80
-#define FRF_BB_TX_VLAN5_WIDTH 12
-#define FRF_BB_TX_VLAN4_PORT1_EN_LBN 77
-#define FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN4_PORT0_EN_LBN 76
-#define FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN4_LBN 64
-#define FRF_BB_TX_VLAN4_WIDTH 12
-#define FRF_BB_TX_VLAN3_PORT1_EN_LBN 61
-#define FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN3_PORT0_EN_LBN 60
-#define FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN3_LBN 48
-#define FRF_BB_TX_VLAN3_WIDTH 12
-#define FRF_BB_TX_VLAN2_PORT1_EN_LBN 45
-#define FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN2_PORT0_EN_LBN 44
-#define FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN2_LBN 32
-#define FRF_BB_TX_VLAN2_WIDTH 12
-#define FRF_BB_TX_VLAN1_PORT1_EN_LBN 29
-#define FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN1_PORT0_EN_LBN 28
-#define FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN1_LBN 16
-#define FRF_BB_TX_VLAN1_WIDTH 12
-#define FRF_BB_TX_VLAN0_PORT1_EN_LBN 13
-#define FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1
-#define FRF_BB_TX_VLAN0_PORT0_EN_LBN 12
-#define FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1
-#define FRF_BB_TX_VLAN0_LBN 0
-#define FRF_BB_TX_VLAN0_WIDTH 12
-
-/* TX_IPFIL_PORTEN_REG: Transmit filter control register */
-#define FR_BZ_TX_IPFIL_PORTEN 0x00000af0
-#define FRF_BZ_TX_MADR0_FIL_EN_LBN 64
-#define FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL31_PORT_EN_LBN 62
-#define FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL30_PORT_EN_LBN 60
-#define FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL29_PORT_EN_LBN 58
-#define FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL28_PORT_EN_LBN 56
-#define FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL27_PORT_EN_LBN 54
-#define FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL26_PORT_EN_LBN 52
-#define FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL25_PORT_EN_LBN 50
-#define FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL24_PORT_EN_LBN 48
-#define FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL23_PORT_EN_LBN 46
-#define FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL22_PORT_EN_LBN 44
-#define FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL21_PORT_EN_LBN 42
-#define FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL20_PORT_EN_LBN 40
-#define FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL19_PORT_EN_LBN 38
-#define FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL18_PORT_EN_LBN 36
-#define FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL17_PORT_EN_LBN 34
-#define FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL16_PORT_EN_LBN 32
-#define FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL15_PORT_EN_LBN 30
-#define FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL14_PORT_EN_LBN 28
-#define FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL13_PORT_EN_LBN 26
-#define FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL12_PORT_EN_LBN 24
-#define FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL11_PORT_EN_LBN 22
-#define FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL10_PORT_EN_LBN 20
-#define FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL9_PORT_EN_LBN 18
-#define FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL8_PORT_EN_LBN 16
-#define FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL7_PORT_EN_LBN 14
-#define FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL6_PORT_EN_LBN 12
-#define FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL5_PORT_EN_LBN 10
-#define FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL4_PORT_EN_LBN 8
-#define FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL3_PORT_EN_LBN 6
-#define FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL2_PORT_EN_LBN 4
-#define FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL1_PORT_EN_LBN 2
-#define FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1
-#define FRF_BB_TX_IPFIL0_PORT_EN_LBN 0
-#define FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1
-
-/* TX_IPFIL_TBL: Transmit IP source address filter table */
-#define FR_BB_TX_IPFIL_TBL 0x00000b00
-#define FR_BB_TX_IPFIL_TBL_STEP 16
-#define FR_BB_TX_IPFIL_TBL_ROWS 16
-#define FRF_BB_TX_IPFIL_MASK_1_LBN 96
-#define FRF_BB_TX_IPFIL_MASK_1_WIDTH 32
-#define FRF_BB_TX_IP_SRC_ADR_1_LBN 64
-#define FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32
-#define FRF_BB_TX_IPFIL_MASK_0_LBN 32
-#define FRF_BB_TX_IPFIL_MASK_0_WIDTH 32
-#define FRF_BB_TX_IP_SRC_ADR_0_LBN 0
-#define FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32
-
-/* MD_TXD_REG: PHY management transmit data register */
-#define FR_AB_MD_TXD 0x00000c00
-#define FRF_AB_MD_TXD_LBN 0
-#define FRF_AB_MD_TXD_WIDTH 16
-
-/* MD_RXD_REG: PHY management receive data register */
-#define FR_AB_MD_RXD 0x00000c10
-#define FRF_AB_MD_RXD_LBN 0
-#define FRF_AB_MD_RXD_WIDTH 16
-
-/* MD_CS_REG: PHY management configuration & status register */
-#define FR_AB_MD_CS 0x00000c20
-#define FRF_AB_MD_RD_EN_CMD_LBN 15
-#define FRF_AB_MD_RD_EN_CMD_WIDTH 1
-#define FRF_AB_MD_WR_EN_CMD_LBN 14
-#define FRF_AB_MD_WR_EN_CMD_WIDTH 1
-#define FRF_AB_MD_ADDR_CMD_LBN 13
-#define FRF_AB_MD_ADDR_CMD_WIDTH 1
-#define FRF_AB_MD_PT_LBN 7
-#define FRF_AB_MD_PT_WIDTH 3
-#define FRF_AB_MD_PL_LBN 6
-#define FRF_AB_MD_PL_WIDTH 1
-#define FRF_AB_MD_INT_CLR_LBN 5
-#define FRF_AB_MD_INT_CLR_WIDTH 1
-#define FRF_AB_MD_GC_LBN 4
-#define FRF_AB_MD_GC_WIDTH 1
-#define FRF_AB_MD_PRSP_LBN 3
-#define FRF_AB_MD_PRSP_WIDTH 1
-#define FRF_AB_MD_RIC_LBN 2
-#define FRF_AB_MD_RIC_WIDTH 1
-#define FRF_AB_MD_RDC_LBN 1
-#define FRF_AB_MD_RDC_WIDTH 1
-#define FRF_AB_MD_WRC_LBN 0
-#define FRF_AB_MD_WRC_WIDTH 1
-
-/* MD_PHY_ADR_REG: PHY management PHY address register */
-#define FR_AB_MD_PHY_ADR 0x00000c30
-#define FRF_AB_MD_PHY_ADR_LBN 0
-#define FRF_AB_MD_PHY_ADR_WIDTH 16
-
-/* MD_ID_REG: PHY management ID register */
-#define FR_AB_MD_ID 0x00000c40
-#define FRF_AB_MD_PRT_ADR_LBN 11
-#define FRF_AB_MD_PRT_ADR_WIDTH 5
-#define FRF_AB_MD_DEV_ADR_LBN 6
-#define FRF_AB_MD_DEV_ADR_WIDTH 5
-
-/* MD_STAT_REG: PHY management status & mask register */
-#define FR_AB_MD_STAT 0x00000c50
-#define FRF_AB_MD_PINT_LBN 4
-#define FRF_AB_MD_PINT_WIDTH 1
-#define FRF_AB_MD_DONE_LBN 3
-#define FRF_AB_MD_DONE_WIDTH 1
-#define FRF_AB_MD_BSERR_LBN 2
-#define FRF_AB_MD_BSERR_WIDTH 1
-#define FRF_AB_MD_LNFL_LBN 1
-#define FRF_AB_MD_LNFL_WIDTH 1
-#define FRF_AB_MD_BSY_LBN 0
-#define FRF_AB_MD_BSY_WIDTH 1
-
-/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */
-#define FR_AB_MAC_STAT_DMA 0x00000c60
-#define FRF_AB_MAC_STAT_DMA_CMD_LBN 48
-#define FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1
-#define FRF_AB_MAC_STAT_DMA_ADR_LBN 0
-#define FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48
-
-/* MAC_CTRL_REG: Port MAC control register */
-#define FR_AB_MAC_CTRL 0x00000c80
-#define FRF_AB_MAC_XOFF_VAL_LBN 16
-#define FRF_AB_MAC_XOFF_VAL_WIDTH 16
-#define FRF_BB_TXFIFO_DRAIN_EN_LBN 7
-#define FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1
-#define FRF_AB_MAC_XG_DISTXCRC_LBN 5
-#define FRF_AB_MAC_XG_DISTXCRC_WIDTH 1
-#define FRF_AB_MAC_BCAD_ACPT_LBN 4
-#define FRF_AB_MAC_BCAD_ACPT_WIDTH 1
-#define FRF_AB_MAC_UC_PROM_LBN 3
-#define FRF_AB_MAC_UC_PROM_WIDTH 1
-#define FRF_AB_MAC_LINK_STATUS_LBN 2
-#define FRF_AB_MAC_LINK_STATUS_WIDTH 1
-#define FRF_AB_MAC_SPEED_LBN 0
-#define FRF_AB_MAC_SPEED_WIDTH 2
-#define FFE_AB_MAC_SPEED_10G 3
-#define FFE_AB_MAC_SPEED_1G 2
-#define FFE_AB_MAC_SPEED_100M 1
-#define FFE_AB_MAC_SPEED_10M 0
-
-/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */
-#define FR_BB_GEN_MODE 0x00000c90
-#define FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3
-#define FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1
-#define FRF_BB_XG_PHY_INT_POL_SEL_LBN 2
-#define FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1
-#define FRF_BB_XFP_PHY_INT_MASK_LBN 1
-#define FRF_BB_XFP_PHY_INT_MASK_WIDTH 1
-#define FRF_BB_XG_PHY_INT_MASK_LBN 0
-#define FRF_BB_XG_PHY_INT_MASK_WIDTH 1
-
-/* MAC_MC_HASH_REG0: Multicast address hash table */
-#define FR_AB_MAC_MC_HASH_REG0 0x00000ca0
-#define FRF_AB_MAC_MCAST_HASH0_LBN 0
-#define FRF_AB_MAC_MCAST_HASH0_WIDTH 128
-
-/* MAC_MC_HASH_REG1: Multicast address hash table */
-#define FR_AB_MAC_MC_HASH_REG1 0x00000cb0
-#define FRF_AB_MAC_MCAST_HASH1_LBN 0
-#define FRF_AB_MAC_MCAST_HASH1_WIDTH 128
-
-/* GM_CFG1_REG: GMAC configuration register 1 */
-#define FR_AB_GM_CFG1 0x00000e00
-#define FRF_AB_GM_SW_RST_LBN 31
-#define FRF_AB_GM_SW_RST_WIDTH 1
-#define FRF_AB_GM_SIM_RST_LBN 30
-#define FRF_AB_GM_SIM_RST_WIDTH 1
-#define FRF_AB_GM_RST_RX_MAC_CTL_LBN 19
-#define FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1
-#define FRF_AB_GM_RST_TX_MAC_CTL_LBN 18
-#define FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1
-#define FRF_AB_GM_RST_RX_FUNC_LBN 17
-#define FRF_AB_GM_RST_RX_FUNC_WIDTH 1
-#define FRF_AB_GM_RST_TX_FUNC_LBN 16
-#define FRF_AB_GM_RST_TX_FUNC_WIDTH 1
-#define FRF_AB_GM_LOOP_LBN 8
-#define FRF_AB_GM_LOOP_WIDTH 1
-#define FRF_AB_GM_RX_FC_EN_LBN 5
-#define FRF_AB_GM_RX_FC_EN_WIDTH 1
-#define FRF_AB_GM_TX_FC_EN_LBN 4
-#define FRF_AB_GM_TX_FC_EN_WIDTH 1
-#define FRF_AB_GM_SYNC_RXEN_LBN 3
-#define FRF_AB_GM_SYNC_RXEN_WIDTH 1
-#define FRF_AB_GM_RX_EN_LBN 2
-#define FRF_AB_GM_RX_EN_WIDTH 1
-#define FRF_AB_GM_SYNC_TXEN_LBN 1
-#define FRF_AB_GM_SYNC_TXEN_WIDTH 1
-#define FRF_AB_GM_TX_EN_LBN 0
-#define FRF_AB_GM_TX_EN_WIDTH 1
-
-/* GM_CFG2_REG: GMAC configuration register 2 */
-#define FR_AB_GM_CFG2 0x00000e10
-#define FRF_AB_GM_PAMBL_LEN_LBN 12
-#define FRF_AB_GM_PAMBL_LEN_WIDTH 4
-#define FRF_AB_GM_IF_MODE_LBN 8
-#define FRF_AB_GM_IF_MODE_WIDTH 2
-#define FFE_AB_IF_MODE_BYTE_MODE 2
-#define FFE_AB_IF_MODE_NIBBLE_MODE 1
-#define FRF_AB_GM_HUGE_FRM_EN_LBN 5
-#define FRF_AB_GM_HUGE_FRM_EN_WIDTH 1
-#define FRF_AB_GM_LEN_CHK_LBN 4
-#define FRF_AB_GM_LEN_CHK_WIDTH 1
-#define FRF_AB_GM_PAD_CRC_EN_LBN 2
-#define FRF_AB_GM_PAD_CRC_EN_WIDTH 1
-#define FRF_AB_GM_CRC_EN_LBN 1
-#define FRF_AB_GM_CRC_EN_WIDTH 1
-#define FRF_AB_GM_FD_LBN 0
-#define FRF_AB_GM_FD_WIDTH 1
-
-/* GM_IPG_REG: GMAC IPG register */
-#define FR_AB_GM_IPG 0x00000e20
-#define FRF_AB_GM_NONB2B_IPG1_LBN 24
-#define FRF_AB_GM_NONB2B_IPG1_WIDTH 7
-#define FRF_AB_GM_NONB2B_IPG2_LBN 16
-#define FRF_AB_GM_NONB2B_IPG2_WIDTH 7
-#define FRF_AB_GM_MIN_IPG_ENF_LBN 8
-#define FRF_AB_GM_MIN_IPG_ENF_WIDTH 8
-#define FRF_AB_GM_B2B_IPG_LBN 0
-#define FRF_AB_GM_B2B_IPG_WIDTH 7
-
-/* GM_HD_REG: GMAC half duplex register */
-#define FR_AB_GM_HD 0x00000e30
-#define FRF_AB_GM_ALT_BOFF_VAL_LBN 20
-#define FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4
-#define FRF_AB_GM_ALT_BOFF_EN_LBN 19
-#define FRF_AB_GM_ALT_BOFF_EN_WIDTH 1
-#define FRF_AB_GM_BP_NO_BOFF_LBN 18
-#define FRF_AB_GM_BP_NO_BOFF_WIDTH 1
-#define FRF_AB_GM_DIS_BOFF_LBN 17
-#define FRF_AB_GM_DIS_BOFF_WIDTH 1
-#define FRF_AB_GM_EXDEF_TX_EN_LBN 16
-#define FRF_AB_GM_EXDEF_TX_EN_WIDTH 1
-#define FRF_AB_GM_RTRY_LIMIT_LBN 12
-#define FRF_AB_GM_RTRY_LIMIT_WIDTH 4
-#define FRF_AB_GM_COL_WIN_LBN 0
-#define FRF_AB_GM_COL_WIN_WIDTH 10
-
-/* GM_MAX_FLEN_REG: GMAC maximum frame length register */
-#define FR_AB_GM_MAX_FLEN 0x00000e40
-#define FRF_AB_GM_MAX_FLEN_LBN 0
-#define FRF_AB_GM_MAX_FLEN_WIDTH 16
-
-/* GM_TEST_REG: GMAC test register */
-#define FR_AB_GM_TEST 0x00000e70
-#define FRF_AB_GM_MAX_BOFF_LBN 3
-#define FRF_AB_GM_MAX_BOFF_WIDTH 1
-#define FRF_AB_GM_REG_TX_FLOW_EN_LBN 2
-#define FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1
-#define FRF_AB_GM_TEST_PAUSE_LBN 1
-#define FRF_AB_GM_TEST_PAUSE_WIDTH 1
-#define FRF_AB_GM_SHORT_SLOT_LBN 0
-#define FRF_AB_GM_SHORT_SLOT_WIDTH 1
-
-/* GM_ADR1_REG: GMAC station address register 1 */
-#define FR_AB_GM_ADR1 0x00000f00
-#define FRF_AB_GM_ADR_B0_LBN 24
-#define FRF_AB_GM_ADR_B0_WIDTH 8
-#define FRF_AB_GM_ADR_B1_LBN 16
-#define FRF_AB_GM_ADR_B1_WIDTH 8
-#define FRF_AB_GM_ADR_B2_LBN 8
-#define FRF_AB_GM_ADR_B2_WIDTH 8
-#define FRF_AB_GM_ADR_B3_LBN 0
-#define FRF_AB_GM_ADR_B3_WIDTH 8
-
-/* GM_ADR2_REG: GMAC station address register 2 */
-#define FR_AB_GM_ADR2 0x00000f10
-#define FRF_AB_GM_ADR_B4_LBN 24
-#define FRF_AB_GM_ADR_B4_WIDTH 8
-#define FRF_AB_GM_ADR_B5_LBN 16
-#define FRF_AB_GM_ADR_B5_WIDTH 8
-
-/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */
-#define FR_AB_GMF_CFG0 0x00000f20
-#define FRF_AB_GMF_FTFENRPLY_LBN 20
-#define FRF_AB_GMF_FTFENRPLY_WIDTH 1
-#define FRF_AB_GMF_STFENRPLY_LBN 19
-#define FRF_AB_GMF_STFENRPLY_WIDTH 1
-#define FRF_AB_GMF_FRFENRPLY_LBN 18
-#define FRF_AB_GMF_FRFENRPLY_WIDTH 1
-#define FRF_AB_GMF_SRFENRPLY_LBN 17
-#define FRF_AB_GMF_SRFENRPLY_WIDTH 1
-#define FRF_AB_GMF_WTMENRPLY_LBN 16
-#define FRF_AB_GMF_WTMENRPLY_WIDTH 1
-#define FRF_AB_GMF_FTFENREQ_LBN 12
-#define FRF_AB_GMF_FTFENREQ_WIDTH 1
-#define FRF_AB_GMF_STFENREQ_LBN 11
-#define FRF_AB_GMF_STFENREQ_WIDTH 1
-#define FRF_AB_GMF_FRFENREQ_LBN 10
-#define FRF_AB_GMF_FRFENREQ_WIDTH 1
-#define FRF_AB_GMF_SRFENREQ_LBN 9
-#define FRF_AB_GMF_SRFENREQ_WIDTH 1
-#define FRF_AB_GMF_WTMENREQ_LBN 8
-#define FRF_AB_GMF_WTMENREQ_WIDTH 1
-#define FRF_AB_GMF_HSTRSTFT_LBN 4
-#define FRF_AB_GMF_HSTRSTFT_WIDTH 1
-#define FRF_AB_GMF_HSTRSTST_LBN 3
-#define FRF_AB_GMF_HSTRSTST_WIDTH 1
-#define FRF_AB_GMF_HSTRSTFR_LBN 2
-#define FRF_AB_GMF_HSTRSTFR_WIDTH 1
-#define FRF_AB_GMF_HSTRSTSR_LBN 1
-#define FRF_AB_GMF_HSTRSTSR_WIDTH 1
-#define FRF_AB_GMF_HSTRSTWT_LBN 0
-#define FRF_AB_GMF_HSTRSTWT_WIDTH 1
-
-/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */
-#define FR_AB_GMF_CFG1 0x00000f30
-#define FRF_AB_GMF_CFGFRTH_LBN 16
-#define FRF_AB_GMF_CFGFRTH_WIDTH 5
-#define FRF_AB_GMF_CFGXOFFRTX_LBN 0
-#define FRF_AB_GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */
-#define FR_AB_GMF_CFG2 0x00000f40
-#define FRF_AB_GMF_CFGHWM_LBN 16
-#define FRF_AB_GMF_CFGHWM_WIDTH 6
-#define FRF_AB_GMF_CFGLWM_LBN 0
-#define FRF_AB_GMF_CFGLWM_WIDTH 6
-
-/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */
-#define FR_AB_GMF_CFG3 0x00000f50
-#define FRF_AB_GMF_CFGHWMFT_LBN 16
-#define FRF_AB_GMF_CFGHWMFT_WIDTH 6
-#define FRF_AB_GMF_CFGFTTH_LBN 0
-#define FRF_AB_GMF_CFGFTTH_WIDTH 6
-
-/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
-#define FR_AB_GMF_CFG4 0x00000f60
-#define FRF_AB_GMF_HSTFLTRFRM_LBN 0
-#define FRF_AB_GMF_HSTFLTRFRM_WIDTH 18
-
-/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
-#define FR_AB_GMF_CFG5 0x00000f70
-#define FRF_AB_GMF_CFGHDPLX_LBN 22
-#define FRF_AB_GMF_CFGHDPLX_WIDTH 1
-#define FRF_AB_GMF_SRFULL_LBN 21
-#define FRF_AB_GMF_SRFULL_WIDTH 1
-#define FRF_AB_GMF_HSTSRFULLCLR_LBN 20
-#define FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1
-#define FRF_AB_GMF_CFGBYTMODE_LBN 19
-#define FRF_AB_GMF_CFGBYTMODE_WIDTH 1
-#define FRF_AB_GMF_HSTDRPLT64_LBN 18
-#define FRF_AB_GMF_HSTDRPLT64_WIDTH 1
-#define FRF_AB_GMF_HSTFLTRFRMDC_LBN 0
-#define FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18
-
-/* TX_SRC_MAC_TBL: Transmit IP source address filter table */
-#define FR_BB_TX_SRC_MAC_TBL 0x00001000
-#define FR_BB_TX_SRC_MAC_TBL_STEP 16
-#define FR_BB_TX_SRC_MAC_TBL_ROWS 16
-#define FRF_BB_TX_SRC_MAC_ADR_1_LBN 64
-#define FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48
-#define FRF_BB_TX_SRC_MAC_ADR_0_LBN 0
-#define FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48
-
-/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */
-#define FR_BB_TX_SRC_MAC_CTL 0x00001100
-#define FRF_BB_TX_SRC_DROP_CTR_LBN 16
-#define FRF_BB_TX_SRC_DROP_CTR_WIDTH 16
-#define FRF_BB_TX_SRC_FLTR_EN_LBN 15
-#define FRF_BB_TX_SRC_FLTR_EN_WIDTH 1
-#define FRF_BB_TX_DROP_CTR_CLR_LBN 12
-#define FRF_BB_TX_DROP_CTR_CLR_WIDTH 1
-#define FRF_BB_TX_MAC_QID_SEL_LBN 0
-#define FRF_BB_TX_MAC_QID_SEL_WIDTH 3
-
-/* XM_ADR_LO_REG: XGMAC address register low */
-#define FR_AB_XM_ADR_LO 0x00001200
-#define FRF_AB_XM_ADR_LO_LBN 0
-#define FRF_AB_XM_ADR_LO_WIDTH 32
-
-/* XM_ADR_HI_REG: XGMAC address register high */
-#define FR_AB_XM_ADR_HI 0x00001210
-#define FRF_AB_XM_ADR_HI_LBN 0
-#define FRF_AB_XM_ADR_HI_WIDTH 16
-
-/* XM_GLB_CFG_REG: XGMAC global configuration */
-#define FR_AB_XM_GLB_CFG 0x00001220
-#define FRF_AB_XM_RMTFLT_GEN_LBN 17
-#define FRF_AB_XM_RMTFLT_GEN_WIDTH 1
-#define FRF_AB_XM_DEBUG_MODE_LBN 16
-#define FRF_AB_XM_DEBUG_MODE_WIDTH 1
-#define FRF_AB_XM_RX_STAT_EN_LBN 11
-#define FRF_AB_XM_RX_STAT_EN_WIDTH 1
-#define FRF_AB_XM_TX_STAT_EN_LBN 10
-#define FRF_AB_XM_TX_STAT_EN_WIDTH 1
-#define FRF_AB_XM_RX_JUMBO_MODE_LBN 6
-#define FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1
-#define FRF_AB_XM_WAN_MODE_LBN 5
-#define FRF_AB_XM_WAN_MODE_WIDTH 1
-#define FRF_AB_XM_INTCLR_MODE_LBN 3
-#define FRF_AB_XM_INTCLR_MODE_WIDTH 1
-#define FRF_AB_XM_CORE_RST_LBN 0
-#define FRF_AB_XM_CORE_RST_WIDTH 1
-
-/* XM_TX_CFG_REG: XGMAC transmit configuration */
-#define FR_AB_XM_TX_CFG 0x00001230
-#define FRF_AB_XM_TX_PROG_LBN 24
-#define FRF_AB_XM_TX_PROG_WIDTH 1
-#define FRF_AB_XM_IPG_LBN 16
-#define FRF_AB_XM_IPG_WIDTH 4
-#define FRF_AB_XM_FCNTL_LBN 10
-#define FRF_AB_XM_FCNTL_WIDTH 1
-#define FRF_AB_XM_TXCRC_LBN 8
-#define FRF_AB_XM_TXCRC_WIDTH 1
-#define FRF_AB_XM_EDRC_LBN 6
-#define FRF_AB_XM_EDRC_WIDTH 1
-#define FRF_AB_XM_AUTO_PAD_LBN 5
-#define FRF_AB_XM_AUTO_PAD_WIDTH 1
-#define FRF_AB_XM_TX_PRMBL_LBN 2
-#define FRF_AB_XM_TX_PRMBL_WIDTH 1
-#define FRF_AB_XM_TXEN_LBN 1
-#define FRF_AB_XM_TXEN_WIDTH 1
-#define FRF_AB_XM_TX_RST_LBN 0
-#define FRF_AB_XM_TX_RST_WIDTH 1
-
-/* XM_RX_CFG_REG: XGMAC receive configuration */
-#define FR_AB_XM_RX_CFG 0x00001240
-#define FRF_AB_XM_PASS_LENERR_LBN 26
-#define FRF_AB_XM_PASS_LENERR_WIDTH 1
-#define FRF_AB_XM_PASS_CRC_ERR_LBN 25
-#define FRF_AB_XM_PASS_CRC_ERR_WIDTH 1
-#define FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24
-#define FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1
-#define FRF_AB_XM_REJ_BCAST_LBN 20
-#define FRF_AB_XM_REJ_BCAST_WIDTH 1
-#define FRF_AB_XM_ACPT_ALL_MCAST_LBN 11
-#define FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1
-#define FRF_AB_XM_ACPT_ALL_UCAST_LBN 9
-#define FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1
-#define FRF_AB_XM_AUTO_DEPAD_LBN 8
-#define FRF_AB_XM_AUTO_DEPAD_WIDTH 1
-#define FRF_AB_XM_RXCRC_LBN 3
-#define FRF_AB_XM_RXCRC_WIDTH 1
-#define FRF_AB_XM_RX_PRMBL_LBN 2
-#define FRF_AB_XM_RX_PRMBL_WIDTH 1
-#define FRF_AB_XM_RXEN_LBN 1
-#define FRF_AB_XM_RXEN_WIDTH 1
-#define FRF_AB_XM_RX_RST_LBN 0
-#define FRF_AB_XM_RX_RST_WIDTH 1
-
-/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */
-#define FR_AB_XM_MGT_INT_MASK 0x00001250
-#define FRF_AB_XM_MSK_STA_INTR_LBN 16
-#define FRF_AB_XM_MSK_STA_INTR_WIDTH 1
-#define FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9
-#define FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1
-#define FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8
-#define FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1
-#define FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2
-#define FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1
-#define FRF_AB_XM_MSK_RMTFLT_LBN 1
-#define FRF_AB_XM_MSK_RMTFLT_WIDTH 1
-#define FRF_AB_XM_MSK_LCLFLT_LBN 0
-#define FRF_AB_XM_MSK_LCLFLT_WIDTH 1
-
-/* XM_FC_REG: XGMAC flow control register */
-#define FR_AB_XM_FC 0x00001270
-#define FRF_AB_XM_PAUSE_TIME_LBN 16
-#define FRF_AB_XM_PAUSE_TIME_WIDTH 16
-#define FRF_AB_XM_RX_MAC_STAT_LBN 11
-#define FRF_AB_XM_RX_MAC_STAT_WIDTH 1
-#define FRF_AB_XM_TX_MAC_STAT_LBN 10
-#define FRF_AB_XM_TX_MAC_STAT_WIDTH 1
-#define FRF_AB_XM_MCNTL_PASS_LBN 8
-#define FRF_AB_XM_MCNTL_PASS_WIDTH 2
-#define FRF_AB_XM_REJ_CNTL_UCAST_LBN 6
-#define FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1
-#define FRF_AB_XM_REJ_CNTL_MCAST_LBN 5
-#define FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1
-#define FRF_AB_XM_ZPAUSE_LBN 2
-#define FRF_AB_XM_ZPAUSE_WIDTH 1
-#define FRF_AB_XM_XMIT_PAUSE_LBN 1
-#define FRF_AB_XM_XMIT_PAUSE_WIDTH 1
-#define FRF_AB_XM_DIS_FCNTL_LBN 0
-#define FRF_AB_XM_DIS_FCNTL_WIDTH 1
-
-/* XM_PAUSE_TIME_REG: XGMAC pause time register */
-#define FR_AB_XM_PAUSE_TIME 0x00001290
-#define FRF_AB_XM_TX_PAUSE_CNT_LBN 16
-#define FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16
-#define FRF_AB_XM_RX_PAUSE_CNT_LBN 0
-#define FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16
-
-/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
-#define FR_AB_XM_TX_PARAM 0x000012d0
-#define FRF_AB_XM_TX_JUMBO_MODE_LBN 31
-#define FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3
-#define FRF_AB_XM_PAD_CHAR_LBN 0
-#define FRF_AB_XM_PAD_CHAR_WIDTH 8
-
-/* XM_RX_PARAM_REG: XGMAC receive parameter register */
-#define FR_AB_XM_RX_PARAM 0x000012e0
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3
-
-/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */
-#define FR_AB_XM_MGT_INT_MSK 0x000012f0
-#define FRF_AB_XM_STAT_CNTR_OF_LBN 9
-#define FRF_AB_XM_STAT_CNTR_OF_WIDTH 1
-#define FRF_AB_XM_STAT_CNTR_HF_LBN 8
-#define FRF_AB_XM_STAT_CNTR_HF_WIDTH 1
-#define FRF_AB_XM_PRMBLE_ERR_LBN 2
-#define FRF_AB_XM_PRMBLE_ERR_WIDTH 1
-#define FRF_AB_XM_RMTFLT_LBN 1
-#define FRF_AB_XM_RMTFLT_WIDTH 1
-#define FRF_AB_XM_LCLFLT_LBN 0
-#define FRF_AB_XM_LCLFLT_WIDTH 1
-
-/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */
-#define FR_AB_XX_PWR_RST 0x00001300
-#define FRF_AB_XX_PWRDND_SIG_LBN 31
-#define FRF_AB_XX_PWRDND_SIG_WIDTH 1
-#define FRF_AB_XX_PWRDNC_SIG_LBN 30
-#define FRF_AB_XX_PWRDNC_SIG_WIDTH 1
-#define FRF_AB_XX_PWRDNB_SIG_LBN 29
-#define FRF_AB_XX_PWRDNB_SIG_WIDTH 1
-#define FRF_AB_XX_PWRDNA_SIG_LBN 28
-#define FRF_AB_XX_PWRDNA_SIG_WIDTH 1
-#define FRF_AB_XX_SIM_MODE_LBN 27
-#define FRF_AB_XX_SIM_MODE_WIDTH 1
-#define FRF_AB_XX_RSTPLLCD_SIG_LBN 25
-#define FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1
-#define FRF_AB_XX_RSTPLLAB_SIG_LBN 24
-#define FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1
-#define FRF_AB_XX_RESETD_SIG_LBN 23
-#define FRF_AB_XX_RESETD_SIG_WIDTH 1
-#define FRF_AB_XX_RESETC_SIG_LBN 22
-#define FRF_AB_XX_RESETC_SIG_WIDTH 1
-#define FRF_AB_XX_RESETB_SIG_LBN 21
-#define FRF_AB_XX_RESETB_SIG_WIDTH 1
-#define FRF_AB_XX_RESETA_SIG_LBN 20
-#define FRF_AB_XX_RESETA_SIG_WIDTH 1
-#define FRF_AB_XX_RSTXGXSRX_SIG_LBN 18
-#define FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1
-#define FRF_AB_XX_RSTXGXSTX_SIG_LBN 17
-#define FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1
-#define FRF_AB_XX_SD_RST_ACT_LBN 16
-#define FRF_AB_XX_SD_RST_ACT_WIDTH 1
-#define FRF_AB_XX_PWRDND_EN_LBN 15
-#define FRF_AB_XX_PWRDND_EN_WIDTH 1
-#define FRF_AB_XX_PWRDNC_EN_LBN 14
-#define FRF_AB_XX_PWRDNC_EN_WIDTH 1
-#define FRF_AB_XX_PWRDNB_EN_LBN 13
-#define FRF_AB_XX_PWRDNB_EN_WIDTH 1
-#define FRF_AB_XX_PWRDNA_EN_LBN 12
-#define FRF_AB_XX_PWRDNA_EN_WIDTH 1
-#define FRF_AB_XX_RSTPLLCD_EN_LBN 9
-#define FRF_AB_XX_RSTPLLCD_EN_WIDTH 1
-#define FRF_AB_XX_RSTPLLAB_EN_LBN 8
-#define FRF_AB_XX_RSTPLLAB_EN_WIDTH 1
-#define FRF_AB_XX_RESETD_EN_LBN 7
-#define FRF_AB_XX_RESETD_EN_WIDTH 1
-#define FRF_AB_XX_RESETC_EN_LBN 6
-#define FRF_AB_XX_RESETC_EN_WIDTH 1
-#define FRF_AB_XX_RESETB_EN_LBN 5
-#define FRF_AB_XX_RESETB_EN_WIDTH 1
-#define FRF_AB_XX_RESETA_EN_LBN 4
-#define FRF_AB_XX_RESETA_EN_WIDTH 1
-#define FRF_AB_XX_RSTXGXSRX_EN_LBN 2
-#define FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1
-#define FRF_AB_XX_RSTXGXSTX_EN_LBN 1
-#define FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1
-#define FRF_AB_XX_RST_XX_EN_LBN 0
-#define FRF_AB_XX_RST_XX_EN_WIDTH 1
-
-/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */
-#define FR_AB_XX_SD_CTL 0x00001310
-#define FRF_AB_XX_TERMADJ1_LBN 17
-#define FRF_AB_XX_TERMADJ1_WIDTH 1
-#define FRF_AB_XX_TERMADJ0_LBN 16
-#define FRF_AB_XX_TERMADJ0_WIDTH 1
-#define FRF_AB_XX_HIDRVD_LBN 15
-#define FRF_AB_XX_HIDRVD_WIDTH 1
-#define FRF_AB_XX_LODRVD_LBN 14
-#define FRF_AB_XX_LODRVD_WIDTH 1
-#define FRF_AB_XX_HIDRVC_LBN 13
-#define FRF_AB_XX_HIDRVC_WIDTH 1
-#define FRF_AB_XX_LODRVC_LBN 12
-#define FRF_AB_XX_LODRVC_WIDTH 1
-#define FRF_AB_XX_HIDRVB_LBN 11
-#define FRF_AB_XX_HIDRVB_WIDTH 1
-#define FRF_AB_XX_LODRVB_LBN 10
-#define FRF_AB_XX_LODRVB_WIDTH 1
-#define FRF_AB_XX_HIDRVA_LBN 9
-#define FRF_AB_XX_HIDRVA_WIDTH 1
-#define FRF_AB_XX_LODRVA_LBN 8
-#define FRF_AB_XX_LODRVA_WIDTH 1
-#define FRF_AB_XX_LPBKD_LBN 3
-#define FRF_AB_XX_LPBKD_WIDTH 1
-#define FRF_AB_XX_LPBKC_LBN 2
-#define FRF_AB_XX_LPBKC_WIDTH 1
-#define FRF_AB_XX_LPBKB_LBN 1
-#define FRF_AB_XX_LPBKB_WIDTH 1
-#define FRF_AB_XX_LPBKA_LBN 0
-#define FRF_AB_XX_LPBKA_WIDTH 1
-
-/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
-#define FR_AB_XX_TXDRV_CTL 0x00001320
-#define FRF_AB_XX_DEQD_LBN 28
-#define FRF_AB_XX_DEQD_WIDTH 4
-#define FRF_AB_XX_DEQC_LBN 24
-#define FRF_AB_XX_DEQC_WIDTH 4
-#define FRF_AB_XX_DEQB_LBN 20
-#define FRF_AB_XX_DEQB_WIDTH 4
-#define FRF_AB_XX_DEQA_LBN 16
-#define FRF_AB_XX_DEQA_WIDTH 4
-#define FRF_AB_XX_DTXD_LBN 12
-#define FRF_AB_XX_DTXD_WIDTH 4
-#define FRF_AB_XX_DTXC_LBN 8
-#define FRF_AB_XX_DTXC_WIDTH 4
-#define FRF_AB_XX_DTXB_LBN 4
-#define FRF_AB_XX_DTXB_WIDTH 4
-#define FRF_AB_XX_DTXA_LBN 0
-#define FRF_AB_XX_DTXA_WIDTH 4
-
-/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */
-#define FR_AB_XX_PRBS_CTL 0x00001330
-#define FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30
-#define FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29
-#define FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28
-#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26
-#define FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25
-#define FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24
-#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22
-#define FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21
-#define FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20
-#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18
-#define FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17
-#define FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16
-#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14
-#define FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13
-#define FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12
-#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10
-#define FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9
-#define FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8
-#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6
-#define FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5
-#define FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4
-#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1
-#define FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2
-#define FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2
-#define FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1
-#define FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1
-#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0
-#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1
-
-/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */
-#define FR_AB_XX_PRBS_CHK 0x00001340
-#define FRF_AB_XX_REV_LB_EN_LBN 16
-#define FRF_AB_XX_REV_LB_EN_WIDTH 1
-#define FRF_AB_XX_CH3_DEG_DET_LBN 15
-#define FRF_AB_XX_CH3_DEG_DET_WIDTH 1
-#define FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14
-#define FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1
-#define FRF_AB_XX_CH3_PRBS_FRUN_LBN 13
-#define FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1
-#define FRF_AB_XX_CH3_ERR_CHK_LBN 12
-#define FRF_AB_XX_CH3_ERR_CHK_WIDTH 1
-#define FRF_AB_XX_CH2_DEG_DET_LBN 11
-#define FRF_AB_XX_CH2_DEG_DET_WIDTH 1
-#define FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10
-#define FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1
-#define FRF_AB_XX_CH2_PRBS_FRUN_LBN 9
-#define FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1
-#define FRF_AB_XX_CH2_ERR_CHK_LBN 8
-#define FRF_AB_XX_CH2_ERR_CHK_WIDTH 1
-#define FRF_AB_XX_CH1_DEG_DET_LBN 7
-#define FRF_AB_XX_CH1_DEG_DET_WIDTH 1
-#define FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6
-#define FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1
-#define FRF_AB_XX_CH1_PRBS_FRUN_LBN 5
-#define FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1
-#define FRF_AB_XX_CH1_ERR_CHK_LBN 4
-#define FRF_AB_XX_CH1_ERR_CHK_WIDTH 1
-#define FRF_AB_XX_CH0_DEG_DET_LBN 3
-#define FRF_AB_XX_CH0_DEG_DET_WIDTH 1
-#define FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2
-#define FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1
-#define FRF_AB_XX_CH0_PRBS_FRUN_LBN 1
-#define FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1
-#define FRF_AB_XX_CH0_ERR_CHK_LBN 0
-#define FRF_AB_XX_CH0_ERR_CHK_WIDTH 1
-
-/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */
-#define FR_AB_XX_PRBS_ERR 0x00001350
-#define FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24
-#define FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8
-#define FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16
-#define FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8
-#define FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8
-#define FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8
-#define FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0
-#define FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8
-
-/* XX_CORE_STAT_REG: XAUI XGXS core status register */
-#define FR_AB_XX_CORE_STAT 0x00001360
-#define FRF_AB_XX_FORCE_SIG3_LBN 31
-#define FRF_AB_XX_FORCE_SIG3_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG3_VAL_LBN 30
-#define FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG2_LBN 29
-#define FRF_AB_XX_FORCE_SIG2_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG2_VAL_LBN 28
-#define FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG1_LBN 27
-#define FRF_AB_XX_FORCE_SIG1_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG1_VAL_LBN 26
-#define FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG0_LBN 25
-#define FRF_AB_XX_FORCE_SIG0_WIDTH 1
-#define FRF_AB_XX_FORCE_SIG0_VAL_LBN 24
-#define FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1
-#define FRF_AB_XX_XGXS_LB_EN_LBN 23
-#define FRF_AB_XX_XGXS_LB_EN_WIDTH 1
-#define FRF_AB_XX_XGMII_LB_EN_LBN 22
-#define FRF_AB_XX_XGMII_LB_EN_WIDTH 1
-#define FRF_AB_XX_MATCH_FAULT_LBN 21
-#define FRF_AB_XX_MATCH_FAULT_WIDTH 1
-#define FRF_AB_XX_ALIGN_DONE_LBN 20
-#define FRF_AB_XX_ALIGN_DONE_WIDTH 1
-#define FRF_AB_XX_SYNC_STAT3_LBN 19
-#define FRF_AB_XX_SYNC_STAT3_WIDTH 1
-#define FRF_AB_XX_SYNC_STAT2_LBN 18
-#define FRF_AB_XX_SYNC_STAT2_WIDTH 1
-#define FRF_AB_XX_SYNC_STAT1_LBN 17
-#define FRF_AB_XX_SYNC_STAT1_WIDTH 1
-#define FRF_AB_XX_SYNC_STAT0_LBN 16
-#define FRF_AB_XX_SYNC_STAT0_WIDTH 1
-#define FRF_AB_XX_COMMA_DET_CH3_LBN 15
-#define FRF_AB_XX_COMMA_DET_CH3_WIDTH 1
-#define FRF_AB_XX_COMMA_DET_CH2_LBN 14
-#define FRF_AB_XX_COMMA_DET_CH2_WIDTH 1
-#define FRF_AB_XX_COMMA_DET_CH1_LBN 13
-#define FRF_AB_XX_COMMA_DET_CH1_WIDTH 1
-#define FRF_AB_XX_COMMA_DET_CH0_LBN 12
-#define FRF_AB_XX_COMMA_DET_CH0_WIDTH 1
-#define FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11
-#define FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1
-#define FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10
-#define FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1
-#define FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9
-#define FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1
-#define FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8
-#define FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1
-#define FRF_AB_XX_CHAR_ERR_CH3_LBN 7
-#define FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1
-#define FRF_AB_XX_CHAR_ERR_CH2_LBN 6
-#define FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1
-#define FRF_AB_XX_CHAR_ERR_CH1_LBN 5
-#define FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1
-#define FRF_AB_XX_CHAR_ERR_CH0_LBN 4
-#define FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1
-#define FRF_AB_XX_DISPERR_CH3_LBN 3
-#define FRF_AB_XX_DISPERR_CH3_WIDTH 1
-#define FRF_AB_XX_DISPERR_CH2_LBN 2
-#define FRF_AB_XX_DISPERR_CH2_WIDTH 1
-#define FRF_AB_XX_DISPERR_CH1_LBN 1
-#define FRF_AB_XX_DISPERR_CH1_WIDTH 1
-#define FRF_AB_XX_DISPERR_CH0_LBN 0
-#define FRF_AB_XX_DISPERR_CH0_WIDTH 1
-
-/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */
-#define FR_AA_RX_DESC_PTR_TBL_KER 0x00011800
-#define FR_AA_RX_DESC_PTR_TBL_KER_STEP 16
-#define FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4
-/* RX_DESC_PTR_TBL: Receive descriptor pointer table */
-#define FR_BZ_RX_DESC_PTR_TBL 0x00f40000
-#define FR_BZ_RX_DESC_PTR_TBL_STEP 16
-#define FR_BB_RX_DESC_PTR_TBL_ROWS 4096
-#define FR_CZ_RX_DESC_PTR_TBL_ROWS 1024
-#define FRF_CZ_RX_HDR_SPLIT_LBN 90
-#define FRF_CZ_RX_HDR_SPLIT_WIDTH 1
-#define FRF_AA_RX_RESET_LBN 89
-#define FRF_AA_RX_RESET_WIDTH 1
-#define FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88
-#define FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1
-#define FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87
-#define FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1
-#define FRF_AZ_RX_DESC_PREF_ACT_LBN 86
-#define FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1
-#define FRF_AZ_RX_DC_HW_RPTR_LBN 80
-#define FRF_AZ_RX_DC_HW_RPTR_WIDTH 6
-#define FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68
-#define FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12
-#define FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56
-#define FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12
-#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36
-#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24
-#define FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12
-#define FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10
-#define FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14
-#define FRF_AZ_RX_DESCQ_LABEL_LBN 5
-#define FRF_AZ_RX_DESCQ_LABEL_WIDTH 5
-#define FRF_AZ_RX_DESCQ_SIZE_LBN 3
-#define FRF_AZ_RX_DESCQ_SIZE_WIDTH 2
-#define FFE_AZ_RX_DESCQ_SIZE_4K 3
-#define FFE_AZ_RX_DESCQ_SIZE_2K 2
-#define FFE_AZ_RX_DESCQ_SIZE_1K 1
-#define FFE_AZ_RX_DESCQ_SIZE_512 0
-#define FRF_AZ_RX_DESCQ_TYPE_LBN 2
-#define FRF_AZ_RX_DESCQ_TYPE_WIDTH 1
-#define FRF_AZ_RX_DESCQ_JUMBO_LBN 1
-#define FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1
-#define FRF_AZ_RX_DESCQ_EN_LBN 0
-#define FRF_AZ_RX_DESCQ_EN_WIDTH 1
-
-/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */
-#define FR_AA_TX_DESC_PTR_TBL_KER 0x00011900
-#define FR_AA_TX_DESC_PTR_TBL_KER_STEP 16
-#define FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8
-/* TX_DESC_PTR_TBL: Transmit descriptor pointer */
-#define FR_BZ_TX_DESC_PTR_TBL 0x00f50000
-#define FR_BZ_TX_DESC_PTR_TBL_STEP 16
-#define FR_BB_TX_DESC_PTR_TBL_ROWS 4096
-#define FR_CZ_TX_DESC_PTR_TBL_ROWS 1024
-#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94
-#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2
-#define FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93
-#define FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1
-#define FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92
-#define FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1
-#define FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91
-#define FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1
-#define FRF_BZ_TX_IP_CHKSM_DIS_LBN 90
-#define FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1
-#define FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89
-#define FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1
-#define FRF_AZ_TX_DESCQ_EN_LBN 88
-#define FRF_AZ_TX_DESCQ_EN_WIDTH 1
-#define FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87
-#define FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1
-#define FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86
-#define FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1
-#define FRF_AZ_TX_DC_HW_RPTR_LBN 80
-#define FRF_AZ_TX_DC_HW_RPTR_WIDTH 6
-#define FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68
-#define FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12
-#define FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56
-#define FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12
-#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36
-#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24
-#define FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12
-#define FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10
-#define FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14
-#define FRF_AZ_TX_DESCQ_LABEL_LBN 5
-#define FRF_AZ_TX_DESCQ_LABEL_WIDTH 5
-#define FRF_AZ_TX_DESCQ_SIZE_LBN 3
-#define FRF_AZ_TX_DESCQ_SIZE_WIDTH 2
-#define FFE_AZ_TX_DESCQ_SIZE_4K 3
-#define FFE_AZ_TX_DESCQ_SIZE_2K 2
-#define FFE_AZ_TX_DESCQ_SIZE_1K 1
-#define FFE_AZ_TX_DESCQ_SIZE_512 0
-#define FRF_AZ_TX_DESCQ_TYPE_LBN 1
-#define FRF_AZ_TX_DESCQ_TYPE_WIDTH 2
-#define FRF_AZ_TX_DESCQ_FLUSH_LBN 0
-#define FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1
-
-/* EVQ_PTR_TBL_KER: Event queue pointer table */
-#define FR_AA_EVQ_PTR_TBL_KER 0x00011a00
-#define FR_AA_EVQ_PTR_TBL_KER_STEP 16
-#define FR_AA_EVQ_PTR_TBL_KER_ROWS 4
-/* EVQ_PTR_TBL: Event queue pointer table */
-#define FR_BZ_EVQ_PTR_TBL 0x00f60000
-#define FR_BZ_EVQ_PTR_TBL_STEP 16
-#define FR_CZ_EVQ_PTR_TBL_ROWS 1024
-#define FR_BB_EVQ_PTR_TBL_ROWS 4096
-#define FRF_BZ_EVQ_RPTR_IGN_LBN 40
-#define FRF_BZ_EVQ_RPTR_IGN_WIDTH 1
-#define FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39
-#define FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1
-#define FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39
-#define FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1
-#define FRF_AZ_EVQ_NXT_WPTR_LBN 24
-#define FRF_AZ_EVQ_NXT_WPTR_WIDTH 15
-#define FRF_AZ_EVQ_EN_LBN 23
-#define FRF_AZ_EVQ_EN_WIDTH 1
-#define FRF_AZ_EVQ_SIZE_LBN 20
-#define FRF_AZ_EVQ_SIZE_WIDTH 3
-#define FFE_AZ_EVQ_SIZE_32K 6
-#define FFE_AZ_EVQ_SIZE_16K 5
-#define FFE_AZ_EVQ_SIZE_8K 4
-#define FFE_AZ_EVQ_SIZE_4K 3
-#define FFE_AZ_EVQ_SIZE_2K 2
-#define FFE_AZ_EVQ_SIZE_1K 1
-#define FFE_AZ_EVQ_SIZE_512 0
-#define FRF_AZ_EVQ_BUF_BASE_ID_LBN 0
-#define FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20
-
-/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */
-#define FR_AA_BUF_HALF_TBL_KER 0x00018000
-#define FR_AA_BUF_HALF_TBL_KER_STEP 8
-#define FR_AA_BUF_HALF_TBL_KER_ROWS 4096
-/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */
-#define FR_BZ_BUF_HALF_TBL 0x00800000
-#define FR_BZ_BUF_HALF_TBL_STEP 8
-#define FR_CZ_BUF_HALF_TBL_ROWS 147456
-#define FR_BB_BUF_HALF_TBL_ROWS 524288
-#define FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44
-#define FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20
-#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32
-#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12
-#define FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12
-#define FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20
-#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0
-#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
-
-/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */
-#define FR_AA_BUF_FULL_TBL_KER 0x00018000
-#define FR_AA_BUF_FULL_TBL_KER_STEP 8
-#define FR_AA_BUF_FULL_TBL_KER_ROWS 4096
-/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */
-#define FR_BZ_BUF_FULL_TBL 0x00800000
-#define FR_BZ_BUF_FULL_TBL_STEP 8
-#define FR_CZ_BUF_FULL_TBL_ROWS 147456
-#define FR_BB_BUF_FULL_TBL_ROWS 917504
-#define FRF_AZ_BUF_FULL_UNUSED_LBN 51
-#define FRF_AZ_BUF_FULL_UNUSED_WIDTH 13
-#define FRF_AZ_IP_DAT_BUF_SIZE_LBN 50
-#define FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1
-#define FRF_AZ_BUF_ADR_REGION_LBN 48
-#define FRF_AZ_BUF_ADR_REGION_WIDTH 2
-#define FFE_AZ_BUF_ADR_REGN3 3
-#define FFE_AZ_BUF_ADR_REGN2 2
-#define FFE_AZ_BUF_ADR_REGN1 1
-#define FFE_AZ_BUF_ADR_REGN0 0
-#define FRF_AZ_BUF_ADR_FBUF_LBN 14
-#define FRF_AZ_BUF_ADR_FBUF_WIDTH 34
-#define FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0
-#define FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14
-
-/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */
-#define FR_BZ_RX_FILTER_TBL0 0x00f00000
-#define FR_BZ_RX_FILTER_TBL0_STEP 32
-#define FR_BZ_RX_FILTER_TBL0_ROWS 8192
-/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */
-#define FR_BB_RX_FILTER_TBL1 0x00f00010
-#define FR_BB_RX_FILTER_TBL1_STEP 32
-#define FR_BB_RX_FILTER_TBL1_ROWS 8192
-#define FRF_BZ_RSS_EN_LBN 110
-#define FRF_BZ_RSS_EN_WIDTH 1
-#define FRF_BZ_SCATTER_EN_LBN 109
-#define FRF_BZ_SCATTER_EN_WIDTH 1
-#define FRF_BZ_TCP_UDP_LBN 108
-#define FRF_BZ_TCP_UDP_WIDTH 1
-#define FRF_BZ_RXQ_ID_LBN 96
-#define FRF_BZ_RXQ_ID_WIDTH 12
-#define FRF_BZ_DEST_IP_LBN 64
-#define FRF_BZ_DEST_IP_WIDTH 32
-#define FRF_BZ_DEST_PORT_TCP_LBN 48
-#define FRF_BZ_DEST_PORT_TCP_WIDTH 16
-#define FRF_BZ_SRC_IP_LBN 16
-#define FRF_BZ_SRC_IP_WIDTH 32
-#define FRF_BZ_SRC_TCP_DEST_UDP_LBN 0
-#define FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16
-
-/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */
-#define FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010
-#define FR_CZ_RX_MAC_FILTER_TBL0_STEP 32
-#define FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512
-#define FRF_CZ_RMFT_RSS_EN_LBN 75
-#define FRF_CZ_RMFT_RSS_EN_WIDTH 1
-#define FRF_CZ_RMFT_SCATTER_EN_LBN 74
-#define FRF_CZ_RMFT_SCATTER_EN_WIDTH 1
-#define FRF_CZ_RMFT_IP_OVERRIDE_LBN 73
-#define FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1
-#define FRF_CZ_RMFT_RXQ_ID_LBN 61
-#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12
-#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
-#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
-#define FRF_CZ_RMFT_DEST_MAC_LBN 12
-#define FRF_CZ_RMFT_DEST_MAC_WIDTH 48
-#define FRF_CZ_RMFT_VLAN_ID_LBN 0
-#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12
-
-/* TIMER_TBL: Timer table */
-#define FR_BZ_TIMER_TBL 0x00f70000
-#define FR_BZ_TIMER_TBL_STEP 16
-#define FR_CZ_TIMER_TBL_ROWS 1024
-#define FR_BB_TIMER_TBL_ROWS 4096
-#define FRF_CZ_TIMER_Q_EN_LBN 33
-#define FRF_CZ_TIMER_Q_EN_WIDTH 1
-#define FRF_CZ_INT_ARMD_LBN 32
-#define FRF_CZ_INT_ARMD_WIDTH 1
-#define FRF_CZ_INT_PEND_LBN 31
-#define FRF_CZ_INT_PEND_WIDTH 1
-#define FRF_CZ_HOST_NOTIFY_MODE_LBN 30
-#define FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1
-#define FRF_CZ_RELOAD_TIMER_VAL_LBN 16
-#define FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14
-#define FRF_CZ_TIMER_MODE_LBN 14
-#define FRF_CZ_TIMER_MODE_WIDTH 2
-#define FFE_CZ_TIMER_MODE_INT_HLDOFF 3
-#define FFE_CZ_TIMER_MODE_TRIG_START 2
-#define FFE_CZ_TIMER_MODE_IMMED_START 1
-#define FFE_CZ_TIMER_MODE_DIS 0
-#define FRF_BB_TIMER_MODE_LBN 12
-#define FRF_BB_TIMER_MODE_WIDTH 2
-#define FFE_BB_TIMER_MODE_INT_HLDOFF 2
-#define FFE_BB_TIMER_MODE_TRIG_START 2
-#define FFE_BB_TIMER_MODE_IMMED_START 1
-#define FFE_BB_TIMER_MODE_DIS 0
-#define FRF_CZ_TIMER_VAL_LBN 0
-#define FRF_CZ_TIMER_VAL_WIDTH 14
-#define FRF_BB_TIMER_VAL_LBN 0
-#define FRF_BB_TIMER_VAL_WIDTH 12
-
-/* TX_PACE_TBL: Transmit pacing table */
-#define FR_BZ_TX_PACE_TBL 0x00f80000
-#define FR_BZ_TX_PACE_TBL_STEP 16
-#define FR_CZ_TX_PACE_TBL_ROWS 1024
-#define FR_BB_TX_PACE_TBL_ROWS 4096
-#define FRF_BZ_TX_PACE_LBN 0
-#define FRF_BZ_TX_PACE_WIDTH 5
-
-/* RX_INDIRECTION_TBL: RX Indirection Table */
-#define FR_BZ_RX_INDIRECTION_TBL 0x00fb0000
-#define FR_BZ_RX_INDIRECTION_TBL_STEP 16
-#define FR_BZ_RX_INDIRECTION_TBL_ROWS 128
-#define FRF_BZ_IT_QUEUE_LBN 0
-#define FRF_BZ_IT_QUEUE_WIDTH 6
-
-/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */
-#define FR_CZ_TX_FILTER_TBL0 0x00fc0000
-#define FR_CZ_TX_FILTER_TBL0_STEP 16
-#define FR_CZ_TX_FILTER_TBL0_ROWS 8192
-#define FRF_CZ_TIFT_TCP_UDP_LBN 108
-#define FRF_CZ_TIFT_TCP_UDP_WIDTH 1
-#define FRF_CZ_TIFT_TXQ_ID_LBN 96
-#define FRF_CZ_TIFT_TXQ_ID_WIDTH 12
-#define FRF_CZ_TIFT_DEST_IP_LBN 64
-#define FRF_CZ_TIFT_DEST_IP_WIDTH 32
-#define FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48
-#define FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16
-#define FRF_CZ_TIFT_SRC_IP_LBN 16
-#define FRF_CZ_TIFT_SRC_IP_WIDTH 32
-#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0
-#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16
-
-/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */
-#define FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000
-#define FR_CZ_TX_MAC_FILTER_TBL0_STEP 16
-#define FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512
-#define FRF_CZ_TMFT_TXQ_ID_LBN 61
-#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12
-#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
-#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
-#define FRF_CZ_TMFT_SRC_MAC_LBN 12
-#define FRF_CZ_TMFT_SRC_MAC_WIDTH 48
-#define FRF_CZ_TMFT_VLAN_ID_LBN 0
-#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12
-
-/* MC_TREG_SMEM: MC Shared Memory */
-#define FR_CZ_MC_TREG_SMEM 0x00ff0000
-#define FR_CZ_MC_TREG_SMEM_STEP 4
-#define FR_CZ_MC_TREG_SMEM_ROWS 512
-#define FRF_CZ_MC_TREG_SMEM_ROW_LBN 0
-#define FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32
-
-/* MSIX_VECTOR_TABLE: MSIX Vector Table */
-#define FR_BB_MSIX_VECTOR_TABLE 0x00ff0000
-#define FR_BZ_MSIX_VECTOR_TABLE_STEP 16
-#define FR_BB_MSIX_VECTOR_TABLE_ROWS 64
-/* MSIX_VECTOR_TABLE: MSIX Vector Table */
-#define FR_CZ_MSIX_VECTOR_TABLE 0x00000000
-/* FR_BZ_MSIX_VECTOR_TABLE_STEP 16 */
-#define FR_CZ_MSIX_VECTOR_TABLE_ROWS 1024
-#define FRF_BZ_MSIX_VECTOR_RESERVED_LBN 97
-#define FRF_BZ_MSIX_VECTOR_RESERVED_WIDTH 31
-#define FRF_BZ_MSIX_VECTOR_MASK_LBN 96
-#define FRF_BZ_MSIX_VECTOR_MASK_WIDTH 1
-#define FRF_BZ_MSIX_MESSAGE_DATA_LBN 64
-#define FRF_BZ_MSIX_MESSAGE_DATA_WIDTH 32
-#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_LBN 32
-#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_WIDTH 32
-#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_LBN 0
-#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_WIDTH 32
-
-/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
-#define FR_BB_MSIX_PBA_TABLE 0x00ff2000
-#define FR_BZ_MSIX_PBA_TABLE_STEP 4
-#define FR_BB_MSIX_PBA_TABLE_ROWS 2
-/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
-#define FR_CZ_MSIX_PBA_TABLE 0x00008000
-/* FR_BZ_MSIX_PBA_TABLE_STEP 4 */
-#define FR_CZ_MSIX_PBA_TABLE_ROWS 32
-#define FRF_BZ_MSIX_PBA_PEND_DWORD_LBN 0
-#define FRF_BZ_MSIX_PBA_PEND_DWORD_WIDTH 32
-
-/* SRM_DBG_REG: SRAM debug access */
-#define FR_BZ_SRM_DBG 0x03000000
-#define FR_BZ_SRM_DBG_STEP 8
-#define FR_CZ_SRM_DBG_ROWS 262144
-#define FR_BB_SRM_DBG_ROWS 2097152
-#define FRF_BZ_SRM_DBG_LBN 0
-#define FRF_BZ_SRM_DBG_WIDTH 64
-
-/* TB_MSIX_PBA_TABLE: MSIX Pending Bit Array */
-#define FR_CZ_TB_MSIX_PBA_TABLE 0x00008000
-#define FR_CZ_TB_MSIX_PBA_TABLE_STEP 4
-#define FR_CZ_TB_MSIX_PBA_TABLE_ROWS 1024
-#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_LBN 0
-#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_WIDTH 32
-
-/* DRIVER_EV */
-#define FSF_AZ_DRIVER_EV_SUBCODE_LBN 56
-#define FSF_AZ_DRIVER_EV_SUBCODE_WIDTH 4
-#define FSE_BZ_TX_DSC_ERROR_EV 15
-#define FSE_BZ_RX_DSC_ERROR_EV 14
-#define FSE_AA_RX_RECOVER_EV 11
-#define FSE_AZ_TIMER_EV 10
-#define FSE_AZ_TX_PKT_NON_TCP_UDP 9
-#define FSE_AZ_WAKE_UP_EV 6
-#define FSE_AZ_SRM_UPD_DONE_EV 5
-#define FSE_AB_EVQ_NOT_EN_EV 3
-#define FSE_AZ_EVQ_INIT_DONE_EV 2
-#define FSE_AZ_RX_DESCQ_FLS_DONE_EV 1
-#define FSE_AZ_TX_DESCQ_FLS_DONE_EV 0
-#define FSF_AZ_DRIVER_EV_SUBDATA_LBN 0
-#define FSF_AZ_DRIVER_EV_SUBDATA_WIDTH 14
-
-/* EVENT_ENTRY */
-#define FSF_AZ_EV_CODE_LBN 60
-#define FSF_AZ_EV_CODE_WIDTH 4
-#define FSE_CZ_EV_CODE_MCDI_EV 12
-#define FSE_CZ_EV_CODE_USER_EV 8
-#define FSE_AZ_EV_CODE_DRV_GEN_EV 7
-#define FSE_AZ_EV_CODE_GLOBAL_EV 6
-#define FSE_AZ_EV_CODE_DRIVER_EV 5
-#define FSE_AZ_EV_CODE_TX_EV 2
-#define FSE_AZ_EV_CODE_RX_EV 0
-#define FSF_AZ_EV_DATA_LBN 0
-#define FSF_AZ_EV_DATA_WIDTH 60
-
-/* GLOBAL_EV */
-#define FSF_BB_GLB_EV_RX_RECOVERY_LBN 12
-#define FSF_BB_GLB_EV_RX_RECOVERY_WIDTH 1
-#define FSF_AA_GLB_EV_RX_RECOVERY_LBN 11
-#define FSF_AA_GLB_EV_RX_RECOVERY_WIDTH 1
-#define FSF_BB_GLB_EV_XG_MGT_INTR_LBN 11
-#define FSF_BB_GLB_EV_XG_MGT_INTR_WIDTH 1
-#define FSF_AB_GLB_EV_XFP_PHY0_INTR_LBN 10
-#define FSF_AB_GLB_EV_XFP_PHY0_INTR_WIDTH 1
-#define FSF_AB_GLB_EV_XG_PHY0_INTR_LBN 9
-#define FSF_AB_GLB_EV_XG_PHY0_INTR_WIDTH 1
-#define FSF_AB_GLB_EV_G_PHY0_INTR_LBN 7
-#define FSF_AB_GLB_EV_G_PHY0_INTR_WIDTH 1
-
-/* LEGACY_INT_VEC */
-#define FSF_AZ_NET_IVEC_FATAL_INT_LBN 64
-#define FSF_AZ_NET_IVEC_FATAL_INT_WIDTH 1
-#define FSF_AZ_NET_IVEC_INT_Q_LBN 40
-#define FSF_AZ_NET_IVEC_INT_Q_WIDTH 4
-#define FSF_AZ_NET_IVEC_INT_FLAG_LBN 32
-#define FSF_AZ_NET_IVEC_INT_FLAG_WIDTH 1
-#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_LBN 1
-#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_WIDTH 1
-#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_LBN 0
-#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_WIDTH 1
-
-/* MC_XGMAC_FLTR_RULE_DEF */
-#define FSF_CZ_MC_XFRC_MODE_LBN 416
-#define FSF_CZ_MC_XFRC_MODE_WIDTH 1
-#define FSE_CZ_MC_XFRC_MODE_LAYERED 1
-#define FSE_CZ_MC_XFRC_MODE_SIMPLE 0
-#define FSF_CZ_MC_XFRC_HASH_LBN 384
-#define FSF_CZ_MC_XFRC_HASH_WIDTH 32
-#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_LBN 256
-#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_WIDTH 128
-#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_LBN 128
-#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_WIDTH 128
-#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_LBN 0
-#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_WIDTH 128
-
-/* RX_EV */
-#define FSF_CZ_RX_EV_PKT_NOT_PARSED_LBN 58
-#define FSF_CZ_RX_EV_PKT_NOT_PARSED_WIDTH 1
-#define FSF_CZ_RX_EV_IPV6_PKT_LBN 57
-#define FSF_CZ_RX_EV_IPV6_PKT_WIDTH 1
-#define FSF_AZ_RX_EV_PKT_OK_LBN 56
-#define FSF_AZ_RX_EV_PKT_OK_WIDTH 1
-#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_LBN 55
-#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_LBN 54
-#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_IP_FRAG_ERR_LBN 53
-#define FSF_AZ_RX_EV_IP_FRAG_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
-#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
-#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_ETH_CRC_ERR_LBN 50
-#define FSF_AZ_RX_EV_ETH_CRC_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_FRM_TRUNC_LBN 49
-#define FSF_AZ_RX_EV_FRM_TRUNC_WIDTH 1
-#define FSF_AA_RX_EV_DRIB_NIB_LBN 49
-#define FSF_AA_RX_EV_DRIB_NIB_WIDTH 1
-#define FSF_AZ_RX_EV_TOBE_DISC_LBN 47
-#define FSF_AZ_RX_EV_TOBE_DISC_WIDTH 1
-#define FSF_AZ_RX_EV_PKT_TYPE_LBN 44
-#define FSF_AZ_RX_EV_PKT_TYPE_WIDTH 3
-#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_JUMBO 5
-#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_LLC 4
-#define FSE_AZ_RX_EV_PKT_TYPE_VLAN 3
-#define FSE_AZ_RX_EV_PKT_TYPE_JUMBO 2
-#define FSE_AZ_RX_EV_PKT_TYPE_LLC 1
-#define FSE_AZ_RX_EV_PKT_TYPE_ETH 0
-#define FSF_AZ_RX_EV_HDR_TYPE_LBN 42
-#define FSF_AZ_RX_EV_HDR_TYPE_WIDTH 2
-#define FSE_AZ_RX_EV_HDR_TYPE_OTHER 3
-#define FSE_AB_RX_EV_HDR_TYPE_IPV4_OTHER 2
-#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER 2
-#define FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP 1
-#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP 1
-#define FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP 0
-#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP 0
-#define FSF_AZ_RX_EV_DESC_Q_EMPTY_LBN 41
-#define FSF_AZ_RX_EV_DESC_Q_EMPTY_WIDTH 1
-#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_LBN 40
-#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_WIDTH 1
-#define FSF_AZ_RX_EV_MCAST_PKT_LBN 39
-#define FSF_AZ_RX_EV_MCAST_PKT_WIDTH 1
-#define FSF_AA_RX_EV_RECOVERY_FLAG_LBN 37
-#define FSF_AA_RX_EV_RECOVERY_FLAG_WIDTH 1
-#define FSF_AZ_RX_EV_Q_LABEL_LBN 32
-#define FSF_AZ_RX_EV_Q_LABEL_WIDTH 5
-#define FSF_AZ_RX_EV_JUMBO_CONT_LBN 31
-#define FSF_AZ_RX_EV_JUMBO_CONT_WIDTH 1
-#define FSF_AZ_RX_EV_PORT_LBN 30
-#define FSF_AZ_RX_EV_PORT_WIDTH 1
-#define FSF_AZ_RX_EV_BYTE_CNT_LBN 16
-#define FSF_AZ_RX_EV_BYTE_CNT_WIDTH 14
-#define FSF_AZ_RX_EV_SOP_LBN 15
-#define FSF_AZ_RX_EV_SOP_WIDTH 1
-#define FSF_AZ_RX_EV_ISCSI_PKT_OK_LBN 14
-#define FSF_AZ_RX_EV_ISCSI_PKT_OK_WIDTH 1
-#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_LBN 13
-#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_LBN 12
-#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_WIDTH 1
-#define FSF_AZ_RX_EV_DESC_PTR_LBN 0
-#define FSF_AZ_RX_EV_DESC_PTR_WIDTH 12
-
-/* RX_KER_DESC */
-#define FSF_AZ_RX_KER_BUF_SIZE_LBN 48
-#define FSF_AZ_RX_KER_BUF_SIZE_WIDTH 14
-#define FSF_AZ_RX_KER_BUF_REGION_LBN 46
-#define FSF_AZ_RX_KER_BUF_REGION_WIDTH 2
-#define FSF_AZ_RX_KER_BUF_ADDR_LBN 0
-#define FSF_AZ_RX_KER_BUF_ADDR_WIDTH 46
-
-/* RX_USER_DESC */
-#define FSF_AZ_RX_USER_2BYTE_OFFSET_LBN 20
-#define FSF_AZ_RX_USER_2BYTE_OFFSET_WIDTH 12
-#define FSF_AZ_RX_USER_BUF_ID_LBN 0
-#define FSF_AZ_RX_USER_BUF_ID_WIDTH 20
-
-/* TX_EV */
-#define FSF_AZ_TX_EV_PKT_ERR_LBN 38
-#define FSF_AZ_TX_EV_PKT_ERR_WIDTH 1
-#define FSF_AZ_TX_EV_PKT_TOO_BIG_LBN 37
-#define FSF_AZ_TX_EV_PKT_TOO_BIG_WIDTH 1
-#define FSF_AZ_TX_EV_Q_LABEL_LBN 32
-#define FSF_AZ_TX_EV_Q_LABEL_WIDTH 5
-#define FSF_AZ_TX_EV_PORT_LBN 16
-#define FSF_AZ_TX_EV_PORT_WIDTH 1
-#define FSF_AZ_TX_EV_WQ_FF_FULL_LBN 15
-#define FSF_AZ_TX_EV_WQ_FF_FULL_WIDTH 1
-#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_LBN 14
-#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
-#define FSF_AZ_TX_EV_COMP_LBN 12
-#define FSF_AZ_TX_EV_COMP_WIDTH 1
-#define FSF_AZ_TX_EV_DESC_PTR_LBN 0
-#define FSF_AZ_TX_EV_DESC_PTR_WIDTH 12
-
-/* TX_KER_DESC */
-#define FSF_AZ_TX_KER_CONT_LBN 62
-#define FSF_AZ_TX_KER_CONT_WIDTH 1
-#define FSF_AZ_TX_KER_BYTE_COUNT_LBN 48
-#define FSF_AZ_TX_KER_BYTE_COUNT_WIDTH 14
-#define FSF_AZ_TX_KER_BUF_REGION_LBN 46
-#define FSF_AZ_TX_KER_BUF_REGION_WIDTH 2
-#define FSF_AZ_TX_KER_BUF_ADDR_LBN 0
-#define FSF_AZ_TX_KER_BUF_ADDR_WIDTH 46
-
-/* TX_USER_DESC */
-#define FSF_AZ_TX_USER_SW_EV_EN_LBN 48
-#define FSF_AZ_TX_USER_SW_EV_EN_WIDTH 1
-#define FSF_AZ_TX_USER_CONT_LBN 46
-#define FSF_AZ_TX_USER_CONT_WIDTH 1
-#define FSF_AZ_TX_USER_BYTE_CNT_LBN 33
-#define FSF_AZ_TX_USER_BYTE_CNT_WIDTH 13
-#define FSF_AZ_TX_USER_BUF_ID_LBN 13
-#define FSF_AZ_TX_USER_BUF_ID_WIDTH 20
-#define FSF_AZ_TX_USER_BYTE_OFS_LBN 0
-#define FSF_AZ_TX_USER_BYTE_OFS_WIDTH 13
-
-/* USER_EV */
-#define FSF_CZ_USER_QID_LBN 32
-#define FSF_CZ_USER_QID_WIDTH 10
-#define FSF_CZ_USER_EV_REG_VALUE_LBN 0
-#define FSF_CZ_USER_EV_REG_VALUE_WIDTH 32
-
-/**************************************************************************
- *
- * Falcon B0 PCIe core indirect registers
- *
- **************************************************************************
- */
-
-#define FPCR_BB_PCIE_DEVICE_CTRL_STAT 0x68
-
-#define FPCR_BB_PCIE_LINK_CTRL_STAT 0x70
-
-#define FPCR_BB_ACK_RPL_TIMER 0x700
-#define FPCRF_BB_ACK_TL_LBN 0
-#define FPCRF_BB_ACK_TL_WIDTH 16
-#define FPCRF_BB_RPL_TL_LBN 16
-#define FPCRF_BB_RPL_TL_WIDTH 16
-
-#define FPCR_BB_ACK_FREQ 0x70C
-#define FPCRF_BB_ACK_FREQ_LBN 0
-#define FPCRF_BB_ACK_FREQ_WIDTH 7
-
-/**************************************************************************
- *
- * Pseudo-registers and fields
- *
- **************************************************************************
- */
-
-/* Interrupt acknowledge work-around register (A0/A1 only) */
-#define FR_AA_WORK_AROUND_BROKEN_PCI_READS 0x0070
-
-/* EE_SPI_HCMD_REG: SPI host command register */
-/* Values for the EE_SPI_HCMD_SF_SEL register field */
-#define FFE_AB_SPI_DEVICE_EEPROM 0
-#define FFE_AB_SPI_DEVICE_FLASH 1
-
-/* NIC_STAT_REG: NIC status register */
-#define FRF_AB_STRAP_10G_LBN 2
-#define FRF_AB_STRAP_10G_WIDTH 1
-#define FRF_AA_STRAP_PCIE_LBN 0
-#define FRF_AA_STRAP_PCIE_WIDTH 1
-
-/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
-#define FRF_AZ_FATAL_INTR_LBN 0
-#define FRF_AZ_FATAL_INTR_WIDTH 12
-
-/* SRM_CFG_REG: SRAM configuration register */
-/* We treat the number of SRAM banks and bank size as a single field */
-#define FRF_AZ_SRM_NB_SZ_LBN FRF_AZ_SRM_BANK_SIZE_LBN
-#define FRF_AZ_SRM_NB_SZ_WIDTH \
- (FRF_AZ_SRM_BANK_SIZE_WIDTH + FRF_AZ_SRM_NUM_BANK_WIDTH)
-#define FFE_AB_SRM_NB1_SZ2M 0
-#define FFE_AB_SRM_NB1_SZ4M 1
-#define FFE_AB_SRM_NB1_SZ8M 2
-#define FFE_AB_SRM_NB_SZ_DEF 3
-#define FFE_AB_SRM_NB2_SZ4M 4
-#define FFE_AB_SRM_NB2_SZ8M 5
-#define FFE_AB_SRM_NB2_SZ16M 6
-#define FFE_AB_SRM_NB_SZ_RES 7
-
-/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
-/* We write just the last dword of these registers */
-#define FR_AZ_RX_DESC_UPD_DWORD_P0 \
- (BUILD_BUG_ON_ZERO(FR_AA_RX_DESC_UPD_KER != FR_BZ_RX_DESC_UPD_P0) + \
- FR_BZ_RX_DESC_UPD_P0 + 3 * 4)
-#define FRF_AZ_RX_DESC_WPTR_DWORD_LBN (FRF_AZ_RX_DESC_WPTR_LBN - 3 * 32)
-#define FRF_AZ_RX_DESC_WPTR_DWORD_WIDTH FRF_AZ_RX_DESC_WPTR_WIDTH
-
-/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
-#define FR_AZ_TX_DESC_UPD_DWORD_P0 \
- (BUILD_BUG_ON_ZERO(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0) + \
- FR_BZ_TX_DESC_UPD_P0 + 3 * 4)
-#define FRF_AZ_TX_DESC_WPTR_DWORD_LBN (FRF_AZ_TX_DESC_WPTR_LBN - 3 * 32)
-#define FRF_AZ_TX_DESC_WPTR_DWORD_WIDTH FRF_AZ_TX_DESC_WPTR_WIDTH
-
-/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
-#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_WIDTH 1
-
-/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
-#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_LBN FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN
-#define FRF_AB_XM_MAX_TX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH + \
- FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH)
-
-/* XM_RX_PARAM_REG: XGMAC receive parameter register */
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_LBN FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN
-#define FRF_AB_XM_MAX_RX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH + \
- FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH)
-
-/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
-/* Default values */
-#define FFE_AB_XX_TXDRV_DEQ_DEF 0xe /* deq=.6 */
-#define FFE_AB_XX_TXDRV_DTX_DEF 0x5 /* 1.25 */
-#define FFE_AB_XX_SD_CTL_DRV_DEF 0 /* 20mA */
-
-/* XX_CORE_STAT_REG: XAUI XGXS core status register */
-/* XGXS all-lanes status fields */
-#define FRF_AB_XX_SYNC_STAT_LBN FRF_AB_XX_SYNC_STAT0_LBN
-#define FRF_AB_XX_SYNC_STAT_WIDTH 4
-#define FRF_AB_XX_COMMA_DET_LBN FRF_AB_XX_COMMA_DET_CH0_LBN
-#define FRF_AB_XX_COMMA_DET_WIDTH 4
-#define FRF_AB_XX_CHAR_ERR_LBN FRF_AB_XX_CHAR_ERR_CH0_LBN
-#define FRF_AB_XX_CHAR_ERR_WIDTH 4
-#define FRF_AB_XX_DISPERR_LBN FRF_AB_XX_DISPERR_CH0_LBN
-#define FRF_AB_XX_DISPERR_WIDTH 4
-#define FFE_AB_XX_STAT_ALL_LANES 0xf
-#define FRF_AB_XX_FORCE_SIG_LBN FRF_AB_XX_FORCE_SIG0_VAL_LBN
-#define FRF_AB_XX_FORCE_SIG_WIDTH 8
-#define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff
-
-/* RX_MAC_FILTER_TBL0 */
-/* RMFT_DEST_MAC is wider than 32 bits */
-#define FRF_CZ_RMFT_DEST_MAC_LO_LBN FRF_CZ_RMFT_DEST_MAC_LBN
-#define FRF_CZ_RMFT_DEST_MAC_LO_WIDTH 32
-#define FRF_CZ_RMFT_DEST_MAC_HI_LBN (FRF_CZ_RMFT_DEST_MAC_LBN + 32)
-#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH (FRF_CZ_RMFT_DEST_MAC_WIDTH - 32)
-
-/* TX_MAC_FILTER_TBL0 */
-/* TMFT_SRC_MAC is wider than 32 bits */
-#define FRF_CZ_TMFT_SRC_MAC_LO_LBN FRF_CZ_TMFT_SRC_MAC_LBN
-#define FRF_CZ_TMFT_SRC_MAC_LO_WIDTH 32
-#define FRF_CZ_TMFT_SRC_MAC_HI_LBN (FRF_CZ_TMFT_SRC_MAC_LBN + 32)
-#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH (FRF_CZ_TMFT_SRC_MAC_WIDTH - 32)
-
-/* TX_PACE_TBL */
-/* Values >20 are documented as reserved, but will result in a queue going
- * into the fast bin with a pace value of zero. */
-#define FFE_BZ_TX_PACE_OFF 0
-#define FFE_BZ_TX_PACE_RESERVED 21
-
-/* DRIVER_EV */
-/* Sub-fields of an RX flush completion event */
-#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12
-#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
-#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_LBN 0
-#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_WIDTH 12
-
-/* EVENT_ENTRY */
-/* Magic number field for event test */
-#define FSF_AZ_DRV_GEN_EV_MAGIC_LBN 0
-#define FSF_AZ_DRV_GEN_EV_MAGIC_WIDTH 32
-
-/* RX packet prefix */
-#define FS_BZ_RX_PREFIX_HASH_OFST 12
-#define FS_BZ_RX_PREFIX_SIZE 16
-
-#endif /* EFX_FARCH_REGS_H */
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 5f201a547e5b..0d45900afa76 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -30,13 +30,6 @@
*
* Only some combinations are supported, depending on NIC type:
*
- * - Falcon supports RX filters matching by {TCP,UDP}/IPv4 4-tuple or
- * local 2-tuple (only implemented for Falcon B0)
- *
- * - Siena supports RX and TX filters matching by {TCP,UDP}/IPv4 4-tuple
- * or local 2-tuple, or local MAC with or without outer VID, and RX
- * default filters
- *
* - Huntington supports filter matching controlled by firmware, potentially
* using {TCP,UDP}/IPv{4,6} 4-tuple or local 2-tuple, local MAC or I/G bit,
* with or without outer and inner VID
diff --git a/drivers/net/ethernet/sfc/io.h b/drivers/net/ethernet/sfc/io.h
index 30439cc83a89..4cc7b501135f 100644
--- a/drivers/net/ethernet/sfc/io.h
+++ b/drivers/net/ethernet/sfc/io.h
@@ -17,46 +17,22 @@
*
**************************************************************************
*
- * Notes on locking strategy for the Falcon architecture:
- *
- * Many CSRs are very wide and cannot be read or written atomically.
- * Writes from the host are buffered by the Bus Interface Unit (BIU)
- * up to 128 bits. Whenever the host writes part of such a register,
- * the BIU collects the written value and does not write to the
- * underlying register until all 4 dwords have been written. A
- * similar buffering scheme applies to host access to the NIC's 64-bit
- * SRAM.
- *
- * Writes to different CSRs and 64-bit SRAM words must be serialised,
- * since interleaved access can result in lost writes. We use
- * efx_nic::biu_lock for this.
- *
- * We also serialise reads from 128-bit CSRs and SRAM with the same
- * spinlock. This may not be necessary, but it doesn't really matter
- * as there are no such reads on the fast path.
+ * The EF10 architecture exposes very few registers to the host and
+ * most of them are only 32 bits wide. The only exceptions are the MC
+ * doorbell register pair, which has its own latching, and
+ * TX_DESC_UPD.
*
- * The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are
- * 128-bit but are special-cased in the BIU to avoid the need for
- * locking in the host:
+ * The TX_DESC_UPD DMA descriptor pointer is 128-bits but is a special
+ * case in the BIU to avoid the need for locking in the host:
*
- * - They are write-only.
- * - The semantics of writing to these registers are such that
+ * - It is write-only.
+ * - The semantics of writing to this register is such that
* replacing the low 96 bits with zero does not affect functionality.
- * - If the host writes to the last dword address of such a register
+ * - If the host writes to the last dword address of the register
* (i.e. the high 32 bits) the underlying register will always be
* written. If the collector and the current write together do not
* provide values for all 128 bits of the register, the low 96 bits
* will be written as zero.
- * - If the host writes to the address of any other part of such a
- * register while the collector already holds values for some other
- * register, the write is discarded and the collector maintains its
- * current state.
- *
- * The EF10 architecture exposes very few registers to the host and
- * most of them are only 32 bits wide. The only exceptions are the MC
- * doorbell register pair, which has its own latching, and
- * TX_DESC_UPD, which works in a similar way to the Falcon
- * architecture.
*/
#if BITS_PER_LONG == 64
@@ -70,7 +46,7 @@
*/
#ifdef CONFIG_X86_64
/* PIO is a win only if write-combining is possible */
-#ifdef ARCH_HAS_IOREMAP_WC
+#ifdef ioremap_wc
#define EFX_USE_PIO 1
#endif
#endif
@@ -125,27 +101,6 @@ static inline void efx_writeo(struct efx_nic *efx, const efx_oword_t *value,
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
-/* Write 64-bit SRAM through the supplied mapping, locking as appropriate. */
-static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
- const efx_qword_t *value, unsigned int index)
-{
- unsigned int addr = index * sizeof(*value);
- unsigned long flags __attribute__ ((unused));
-
- netif_vdbg(efx, hw, efx->net_dev,
- "writing SRAM address %x with " EFX_QWORD_FMT "\n",
- addr, EFX_QWORD_VAL(*value));
-
- spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef EFX_USE_QWORD_IO
- __raw_writeq((__force u64)value->u64[0], membase + addr);
-#else
- __raw_writel((__force u32)value->u32[0], membase + addr);
- __raw_writel((__force u32)value->u32[1], membase + addr + 4);
-#endif
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
/* Write a 32-bit CSR or the last dword of a special 128-bit CSR */
static inline void efx_writed(struct efx_nic *efx, const efx_dword_t *value,
unsigned int reg)
@@ -176,27 +131,6 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
EFX_OWORD_VAL(*value));
}
-/* Read 64-bit SRAM through the supplied mapping, locking as appropriate. */
-static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
- efx_qword_t *value, unsigned int index)
-{
- unsigned int addr = index * sizeof(*value);
- unsigned long flags __attribute__ ((unused));
-
- spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef EFX_USE_QWORD_IO
- value->u64[0] = (__force __le64)__raw_readq(membase + addr);
-#else
- value->u32[0] = (__force __le32)__raw_readl(membase + addr);
- value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
-#endif
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-
- netif_vdbg(efx, hw, efx->net_dev,
- "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
- addr, EFX_QWORD_VAL(*value));
-}
-
/* Read a 32-bit CSR or SRAM */
static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 0cab508f2f9d..c3e2b4a21d10 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -16,6 +16,7 @@
#include "mcdi_pcol.h"
#include "mcdi_pcol_mae.h"
#include "tc_encap_actions.h"
+#include "tc_conntrack.h"
int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
{
@@ -227,6 +228,256 @@ void efx_mae_counters_grant_credits(struct work_struct *work)
rx_queue->granted_count += credits;
}
+static int efx_mae_table_get_desc(struct efx_nic *efx,
+ struct efx_tc_table_desc *desc,
+ u32 table_id)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(16));
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_DESCRIPTOR_IN_LEN);
+ unsigned int offset = 0, i;
+ size_t outlen;
+ int rc;
+
+ memset(desc, 0, sizeof(*desc));
+
+ MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_TABLE_ID, table_id);
+more:
+ MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX, offset);
+ rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DESCRIPTOR, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ goto fail;
+ if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(1)) {
+ rc = -EIO;
+ goto fail;
+ }
+ if (!offset) { /* first iteration: get metadata */
+ desc->type = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_TYPE);
+ desc->key_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_KEY_WIDTH);
+ desc->resp_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_RESP_WIDTH);
+ desc->n_keys = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS);
+ desc->n_resps = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS);
+ desc->n_prios = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_PRIORITIES);
+ desc->flags = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_FLAGS);
+ rc = -EOPNOTSUPP;
+ if (desc->flags)
+ goto fail;
+ desc->scheme = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_SCHEME);
+ if (desc->scheme)
+ goto fail;
+ rc = -ENOMEM;
+ desc->keys = kcalloc(desc->n_keys,
+ sizeof(struct efx_tc_table_field_fmt),
+ GFP_KERNEL);
+ if (!desc->keys)
+ goto fail;
+ desc->resps = kcalloc(desc->n_resps,
+ sizeof(struct efx_tc_table_field_fmt),
+ GFP_KERNEL);
+ if (!desc->resps)
+ goto fail;
+ }
+ /* FW could have returned more than the 16 field_descrs we
+ * made room for in our outbuf
+ */
+ outlen = min(outlen, sizeof(outbuf));
+ for (i = 0; i + offset < desc->n_keys + desc->n_resps; i++) {
+ struct efx_tc_table_field_fmt *field;
+ MCDI_DECLARE_STRUCT_PTR(fdesc);
+
+ if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(i + 1)) {
+ offset += i;
+ goto more;
+ }
+ if (i + offset < desc->n_keys)
+ field = desc->keys + i + offset;
+ else
+ field = desc->resps + (i + offset - desc->n_keys);
+ fdesc = MCDI_ARRAY_STRUCT_PTR(outbuf,
+ TABLE_DESCRIPTOR_OUT_FIELDS, i);
+ field->field_id = MCDI_STRUCT_WORD(fdesc,
+ TABLE_FIELD_DESCR_FIELD_ID);
+ field->lbn = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_LBN);
+ field->width = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_WIDTH);
+ field->masking = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_MASK_TYPE);
+ field->scheme = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_SCHEME);
+ }
+ return 0;
+
+fail:
+ kfree(desc->keys);
+ kfree(desc->resps);
+ return rc;
+}
+
+static int efx_mae_table_hook_find(u16 n_fields,
+ struct efx_tc_table_field_fmt *fields,
+ u16 field_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < n_fields; i++) {
+ if (fields[i].field_id == field_id)
+ return i;
+ }
+ return -EPROTO;
+}
+
+#define TABLE_FIND_KEY(_desc, _id) \
+ efx_mae_table_hook_find((_desc)->n_keys, (_desc)->keys, _id)
+#define TABLE_FIND_RESP(_desc, _id) \
+ efx_mae_table_hook_find((_desc)->n_resps, (_desc)->resps, _id)
+
+#define TABLE_HOOK_KEY(_meta, _name, _mcdi_name) ({ \
+ int _rc = TABLE_FIND_KEY(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \
+ \
+ if (_rc > U8_MAX) \
+ _rc = -EOPNOTSUPP; \
+ if (_rc >= 0) { \
+ _meta->keys._name##_idx = _rc; \
+ _rc = 0; \
+ } \
+ _rc; \
+})
+#define TABLE_HOOK_RESP(_meta, _name, _mcdi_name) ({ \
+ int _rc = TABLE_FIND_RESP(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \
+ \
+ if (_rc > U8_MAX) \
+ _rc = -EOPNOTSUPP; \
+ if (_rc >= 0) { \
+ _meta->resps._name##_idx = _rc; \
+ _rc = 0; \
+ } \
+ _rc; \
+})
+
+static int efx_mae_table_hook_ct(struct efx_nic *efx,
+ struct efx_tc_table_ct *meta_ct)
+{
+ int rc;
+
+ rc = TABLE_HOOK_KEY(meta_ct, eth_proto, ETHER_TYPE);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, ip_proto, IP_PROTO);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, src_ip, SRC_IP);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, dst_ip, DST_IP);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, l4_sport, SRC_PORT);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, l4_dport, DST_PORT);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_KEY(meta_ct, zone, DOMAIN);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_RESP(meta_ct, dnat, NAT_DIR);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_RESP(meta_ct, nat_ip, NAT_IP);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_RESP(meta_ct, l4_natport, NAT_PORT);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_RESP(meta_ct, mark, CT_MARK);
+ if (rc)
+ return rc;
+ rc = TABLE_HOOK_RESP(meta_ct, counter_id, COUNTER_ID);
+ if (rc)
+ return rc;
+ meta_ct->hooked = true;
+ return 0;
+}
+
+static void efx_mae_table_free_desc(struct efx_tc_table_desc *desc)
+{
+ kfree(desc->keys);
+ kfree(desc->resps);
+ memset(desc, 0, sizeof(*desc));
+}
+
+static bool efx_mae_check_table_exists(struct efx_nic *efx, u32 tbl_req)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_LIST_OUT_LEN(16));
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_LIST_IN_LEN);
+ u32 tbl_id, tbl_total, tbl_cnt, pos = 0;
+ size_t outlen, msg_max;
+ bool ct_tbl = false;
+ int rc, idx;
+
+ msg_max = sizeof(outbuf);
+ efx->tc->meta_ct.hooked = false;
+more:
+ memset(outbuf, 0, sizeof(*outbuf));
+ MCDI_SET_DWORD(inbuf, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX, pos);
+ rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_LIST, inbuf, sizeof(inbuf), outbuf,
+ msg_max, &outlen);
+ if (rc)
+ return false;
+
+ if (outlen < MC_CMD_TABLE_LIST_OUT_LEN(1))
+ return false;
+
+ tbl_total = MCDI_DWORD(outbuf, TABLE_LIST_OUT_N_TABLES);
+ tbl_cnt = MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(min(outlen, msg_max));
+
+ for (idx = 0; idx < tbl_cnt; idx++) {
+ tbl_id = MCDI_ARRAY_DWORD(outbuf, TABLE_LIST_OUT_TABLE_ID, idx);
+ if (tbl_id == tbl_req) {
+ ct_tbl = true;
+ break;
+ }
+ }
+
+ pos += tbl_cnt;
+ if (!ct_tbl && pos < tbl_total)
+ goto more;
+
+ return ct_tbl;
+}
+
+int efx_mae_get_tables(struct efx_nic *efx)
+{
+ int rc;
+
+ efx->tc->meta_ct.hooked = false;
+ if (efx_mae_check_table_exists(efx, TABLE_ID_CONNTRACK_TABLE)) {
+ rc = efx_mae_table_get_desc(efx, &efx->tc->meta_ct.desc,
+ TABLE_ID_CONNTRACK_TABLE);
+ if (rc) {
+ pci_info(efx->pci_dev,
+ "FW does not support conntrack desc rc %d\n",
+ rc);
+ return 0;
+ }
+
+ rc = efx_mae_table_hook_ct(efx, &efx->tc->meta_ct);
+ if (rc) {
+ pci_info(efx->pci_dev,
+ "FW does not support conntrack hook rc %d\n",
+ rc);
+ return 0;
+ }
+ } else {
+ pci_info(efx->pci_dev,
+ "FW does not support conntrack table\n");
+ }
+ return 0;
+}
+
+void efx_mae_free_tables(struct efx_nic *efx)
+{
+ efx_mae_table_free_desc(&efx->tc->meta_ct.desc);
+ efx->tc->meta_ct.hooked = false;
+}
+
static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
@@ -444,8 +695,13 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
CHECK(L4_SPORT, l4_sport) ||
CHECK(L4_DPORT, l4_dport) ||
CHECK(TCP_FLAGS, tcp_flags) ||
+ CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst) ||
CHECK_BIT(IS_IP_FRAG, ip_frag) ||
CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) ||
+ CHECK_BIT(DO_CT, ct_state_trk) ||
+ CHECK_BIT(CT_HIT, ct_state_est) ||
+ CHECK(CT_MARK, ct_mark) ||
+ CHECK(CT_DOMAIN, ct_zone) ||
CHECK(RECIRC_ID, recirc_id))
return rc;
/* Matches on outer fields are done in a separate hardware table,
@@ -471,6 +727,90 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
}
return 0;
}
+
+/* Checks for match fields not supported in LHS Outer Rules */
+#define UNSUPPORTED(_field) ({ \
+ enum mask_type typ = classify_mask((const u8 *)&mask->_field, \
+ sizeof(mask->_field)); \
+ \
+ if (typ != MASK_ZEROES) { \
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
+ rc = -EOPNOTSUPP; \
+ } \
+ rc; \
+})
+#define UNSUPPORTED_BIT(_field) ({ \
+ if (mask->_field) { \
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
+ rc = -EOPNOTSUPP; \
+ } \
+ rc; \
+})
+
+/* LHS rules are (normally) inserted in the Outer Rule table, which means
+ * they use ENC_ fields in hardware to match regular (not enc_) fields from
+ * &struct efx_tc_match_fields.
+ */
+int efx_mae_match_check_caps_lhs(struct efx_nic *efx,
+ const struct efx_tc_match_fields *mask,
+ struct netlink_ext_ack *extack)
+{
+ const u8 *supported_fields = efx->tc->caps->outer_rule_fields;
+ __be32 ingress_port = cpu_to_be32(mask->ingress_port);
+ enum mask_type ingress_port_mask_type;
+ int rc;
+
+ /* Check for _PREFIX assumes big-endian, so we need to convert */
+ ingress_port_mask_type = classify_mask((const u8 *)&ingress_port,
+ sizeof(ingress_port));
+ rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT],
+ ingress_port_mask_type);
+ if (rc) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s\n",
+ mask_type_name(ingress_port_mask_type),
+ "ingress_port");
+ return rc;
+ }
+ if (CHECK(ENC_ETHER_TYPE, eth_proto) ||
+ CHECK(ENC_VLAN0_TCI, vlan_tci[0]) ||
+ CHECK(ENC_VLAN0_PROTO, vlan_proto[0]) ||
+ CHECK(ENC_VLAN1_TCI, vlan_tci[1]) ||
+ CHECK(ENC_VLAN1_PROTO, vlan_proto[1]) ||
+ CHECK(ENC_ETH_SADDR, eth_saddr) ||
+ CHECK(ENC_ETH_DADDR, eth_daddr) ||
+ CHECK(ENC_IP_PROTO, ip_proto) ||
+ CHECK(ENC_IP_TOS, ip_tos) ||
+ CHECK(ENC_IP_TTL, ip_ttl) ||
+ CHECK_BIT(ENC_IP_FRAG, ip_frag) ||
+ UNSUPPORTED_BIT(ip_firstfrag) ||
+ CHECK(ENC_SRC_IP4, src_ip) ||
+ CHECK(ENC_DST_IP4, dst_ip) ||
+#ifdef CONFIG_IPV6
+ CHECK(ENC_SRC_IP6, src_ip6) ||
+ CHECK(ENC_DST_IP6, dst_ip6) ||
+#endif
+ CHECK(ENC_L4_SPORT, l4_sport) ||
+ CHECK(ENC_L4_DPORT, l4_dport) ||
+ UNSUPPORTED(tcp_flags) ||
+ CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst))
+ return rc;
+ if (efx_tc_match_is_encap(mask)) {
+ /* can't happen; disallowed for local rules, translated
+ * for foreign rules.
+ */
+ NL_SET_ERR_MSG_MOD(extack, "Unexpected encap match in LHS rule");
+ return -EOPNOTSUPP;
+ }
+ if (UNSUPPORTED(enc_keyid) ||
+ /* Can't filter on conntrack in LHS rules */
+ UNSUPPORTED_BIT(ct_state_trk) ||
+ UNSUPPORTED_BIT(ct_state_est) ||
+ UNSUPPORTED(ct_mark) ||
+ UNSUPPORTED(recirc_id))
+ return rc;
+ return 0;
+}
+#undef UNSUPPORTED
#undef CHECK_BIT
#undef CHECK
@@ -879,6 +1219,71 @@ fail:
return rc;
}
+/**
+ * efx_mae_allocate_pedit_mac() - allocate pedit MAC address in HW.
+ * @efx: NIC we're installing a pedit MAC address on
+ * @ped: pedit MAC action to be installed
+ *
+ * Attempts to install @ped in HW and populates its id with an index of this
+ * entry in the firmware MAC address table on success.
+ *
+ * Return: negative value on error, 0 in success.
+ */
+int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
+ struct efx_tc_mac_pedit_action *ped)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN);
+ size_t outlen;
+ int rc;
+
+ BUILD_BUG_ON(MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_LEN !=
+ sizeof(ped->h_addr));
+ memcpy(MCDI_PTR(inbuf, MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR), ped->h_addr,
+ sizeof(ped->h_addr));
+ rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_ALLOC, inbuf, sizeof(inbuf),
+ outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < sizeof(outbuf))
+ return -EIO;
+ ped->fw_id = MCDI_DWORD(outbuf, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
+ return 0;
+}
+
+/**
+ * efx_mae_free_pedit_mac() - free pedit MAC address in HW.
+ * @efx: NIC we're installing a pedit MAC address on
+ * @ped: pedit MAC action that needs to be freed
+ *
+ * Frees @ped in HW, check that firmware did not free a different one and clears
+ * the id (which denotes the index of the entry in the MAC address table).
+ */
+void efx_mae_free_pedit_mac(struct efx_nic *efx,
+ struct efx_tc_mac_pedit_action *ped)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1));
+ size_t outlen;
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, MAE_MAC_ADDR_FREE_IN_MAC_ID, ped->fw_id);
+ rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_FREE, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+ if (rc || outlen < sizeof(outbuf))
+ return;
+ /* FW freed a different ID than we asked for, should also never happen.
+ * Warn because it means we've now got a different idea to the FW of
+ * what MAC addresses exist, which could cause mayhem later.
+ */
+ if (WARN_ON(MCDI_DWORD(outbuf, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != ped->fw_id))
+ return;
+ /* We're probably about to free @ped, but let's just make sure its
+ * fw_id is blatted so that it won't look valid if it leaks out.
+ */
+ ped->fw_id = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL;
+}
+
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
@@ -886,15 +1291,27 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
size_t outlen;
int rc;
- MCDI_POPULATE_DWORD_3(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS,
+ MCDI_POPULATE_DWORD_4(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS,
MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push,
MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop,
- MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap);
+ MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap,
+ MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL,
+ act->do_ttl_dec);
+
+ if (act->src_mac)
+ MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
+ act->src_mac->fw_id);
+ else
+ MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
+ MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
+
+ if (act->dst_mac)
+ MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
+ act->dst_mac->fw_id);
+ else
+ MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
+ MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
- MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
- MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
- MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
- MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
if (act->count && !WARN_ON(!act->count->cnt))
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
act->count->cnt->fw_id);
@@ -1153,6 +1570,465 @@ int efx_mae_unregister_encap_match(struct efx_nic *efx,
return 0;
}
+static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
+ const struct efx_tc_match *match)
+{
+ if (match->mask.ingress_port) {
+ if (~match->mask.ingress_port)
+ return -EOPNOTSUPP;
+ MCDI_STRUCT_SET_DWORD(match_crit,
+ MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR,
+ match->value.ingress_port);
+ }
+ MCDI_STRUCT_SET_DWORD(match_crit, MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR_MASK,
+ match->mask.ingress_port);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE,
+ match->value.eth_proto);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK,
+ match->mask.eth_proto);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE,
+ match->value.vlan_tci[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE_MASK,
+ match->mask.vlan_tci[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE,
+ match->value.vlan_proto[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE_MASK,
+ match->mask.vlan_proto[0]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE,
+ match->value.vlan_tci[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE_MASK,
+ match->mask.vlan_tci[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE,
+ match->value.vlan_proto[1]);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE_MASK,
+ match->mask.vlan_proto[1]);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE),
+ match->value.eth_saddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE_MASK),
+ match->mask.eth_saddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE),
+ match->value.eth_daddr, ETH_ALEN);
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE_MASK),
+ match->mask.eth_daddr, ETH_ALEN);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO,
+ match->value.ip_proto);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK,
+ match->mask.ip_proto);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS,
+ match->value.ip_tos);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK,
+ match->mask.ip_tos);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL,
+ match->value.ip_ttl);
+ MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL_MASK,
+ match->mask.ip_ttl);
+ MCDI_STRUCT_POPULATE_BYTE_1(match_crit,
+ MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS,
+ MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG,
+ match->value.ip_frag);
+ MCDI_STRUCT_POPULATE_BYTE_1(match_crit,
+ MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS_MASK,
+ MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG_MASK,
+ match->mask.ip_frag);
+ MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE,
+ match->value.src_ip);
+ MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK,
+ match->mask.src_ip);
+ MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE,
+ match->value.dst_ip);
+ MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK,
+ match->mask.dst_ip);
+#ifdef CONFIG_IPV6
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE),
+ &match->value.src_ip6, sizeof(struct in6_addr));
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK),
+ &match->mask.src_ip6, sizeof(struct in6_addr));
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE),
+ &match->value.dst_ip6, sizeof(struct in6_addr));
+ memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK),
+ &match->mask.dst_ip6, sizeof(struct in6_addr));
+#endif
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE,
+ match->value.l4_sport);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE_MASK,
+ match->mask.l4_sport);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
+ match->value.l4_dport);
+ MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK,
+ match->mask.l4_dport);
+ /* No enc-keys in LHS rules. Caps check should have caught this; any
+ * enc-keys from an fLHS should have been translated to regular keys
+ * and any EM should be a pseudo (we're an OR so can't have a direct
+ * EM with another OR).
+ */
+ if (WARN_ON_ONCE(match->encap && !match->encap->type))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_src_ip))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_dst_ip))
+ return -EOPNOTSUPP;
+#ifdef CONFIG_IPV6
+ if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)))
+ return -EOPNOTSUPP;
+#endif
+ if (WARN_ON_ONCE(match->mask.enc_ip_tos))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_ip_ttl))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_sport))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_dport))
+ return -EOPNOTSUPP;
+ if (WARN_ON_ONCE(match->mask.enc_keyid))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static int efx_mae_insert_lhs_outer_rule(struct efx_nic *efx,
+ struct efx_tc_lhs_rule *rule, u32 prio)
+{
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN));
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
+ MCDI_DECLARE_STRUCT_PTR(match_crit);
+ const struct efx_tc_lhs_action *act;
+ size_t outlen;
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_PRIO, prio);
+ /* match */
+ match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA);
+ rc = efx_mae_populate_lhs_match_criteria(match_crit, &rule->match);
+ if (rc)
+ return rc;
+
+ /* action */
+ act = &rule->lhs_act;
+ MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE,
+ MAE_MCDI_ENCAP_TYPE_NONE);
+ /* We always inhibit CT lookup on TCP_INTERESTING_FLAGS, since the
+ * SW path needs to process the packet to update the conntrack tables
+ * on connection establishment (SYN) or termination (FIN, RST).
+ */
+ MCDI_POPULATE_DWORD_6(inbuf, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL,
+ MAE_OUTER_RULE_INSERT_IN_DO_CT, !!act->zone,
+ MAE_OUTER_RULE_INSERT_IN_CT_TCP_FLAGS_INHIBIT, 1,
+ MAE_OUTER_RULE_INSERT_IN_CT_DOMAIN,
+ act->zone ? act->zone->zone : 0,
+ MAE_OUTER_RULE_INSERT_IN_CT_VNI_MODE,
+ MAE_CT_VNI_MODE_ZERO,
+ MAE_OUTER_RULE_INSERT_IN_DO_COUNT, !!act->count,
+ MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
+ act->rid ? act->rid->fw_id : 0);
+ if (act->count)
+ MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_COUNTER_ID,
+ act->count->cnt->fw_id);
+ rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < sizeof(outbuf))
+ return -EIO;
+ rule->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
+ return 0;
+}
+
+int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule,
+ u32 prio)
+{
+ return efx_mae_insert_lhs_outer_rule(efx, rule, prio);
+}
+
+static int efx_mae_remove_lhs_outer_rule(struct efx_nic *efx,
+ struct efx_tc_lhs_rule *rule)
+{
+ MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
+ MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1));
+ size_t outlen;
+ int rc;
+
+ MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, rule->fw_id);
+ rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf,
+ sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+ if (rc)
+ return rc;
+ if (outlen < sizeof(outbuf))
+ return -EIO;
+ /* FW freed a different ID than we asked for, should also never happen.
+ * Warn because it means we've now got a different idea to the FW of
+ * what encap_mds exist, which could cause mayhem later.
+ */
+ if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != rule->fw_id))
+ return -EIO;
+ /* We're probably about to free @rule, but let's just make sure its
+ * fw_id is blatted so that it won't look valid if it leaks out.
+ */
+ rule->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL;
+ return 0;
+}
+
+int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule)
+{
+ return efx_mae_remove_lhs_outer_rule(efx, rule);
+}
+
+/* Populating is done by taking each byte of @value in turn and storing
+ * it in the appropriate bits of @row. @value must be big-endian; we
+ * convert it to little-endianness as we go.
+ */
+static int efx_mae_table_populate(struct efx_tc_table_field_fmt field,
+ __le32 *row, size_t row_bits,
+ void *value, size_t value_size)
+{
+ unsigned int i;
+
+ /* For now only scheme 0 is supported for any field, so we check here
+ * (rather than, say, in calling code, which knows the semantics and
+ * could in principle encode for other schemes).
+ */
+ if (field.scheme)
+ return -EOPNOTSUPP;
+ if (DIV_ROUND_UP(field.width, 8) != value_size)
+ return -EINVAL;
+ if (field.lbn + field.width > row_bits)
+ return -EINVAL;
+ for (i = 0; i < value_size; i++) {
+ unsigned int bn = field.lbn + i * 8;
+ unsigned int wn = bn / 32;
+ u64 v;
+
+ v = ((u8 *)value)[value_size - i - 1];
+ v <<= (bn % 32);
+ row[wn] |= cpu_to_le32(v & 0xffffffff);
+ if (wn * 32 < row_bits)
+ row[wn + 1] |= cpu_to_le32(v >> 32);
+ }
+ return 0;
+}
+
+static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field,
+ __le32 *row, size_t row_bits, bool value)
+{
+ u8 v = value ? 1 : 0;
+
+ if (field.width != 1)
+ return -EINVAL;
+ return efx_mae_table_populate(field, row, row_bits, &v, 1);
+}
+
+static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field,
+ __le32 *row, size_t row_bits, __be32 value)
+{
+ /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */
+ struct in6_addr v = {};
+
+ if (field.width != 128)
+ return -EINVAL;
+ v.s6_addr32[0] = value;
+ return efx_mae_table_populate(field, row, row_bits, &v, sizeof(v));
+}
+
+static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field,
+ __le32 *row, size_t row_bits, u32 value)
+{
+ __be32 v = cpu_to_be32(value);
+
+ /* We adjust value_size here since just 3 bytes will be copied, and
+ * the pointer to the value is set discarding the first byte which is
+ * the most significant byte for a big-endian 4-bytes value.
+ */
+ return efx_mae_table_populate(field, row, row_bits, ((void *)&v) + 1,
+ sizeof(v) - 1);
+}
+
+#define _TABLE_POPULATE(dst, dw, _field, _value) ({ \
+ typeof(_value) _v = _value; \
+ \
+ (_field.width == sizeof(_value) * 8) ? \
+ efx_mae_table_populate(_field, dst, dw, &_v, \
+ sizeof(_v)) : -EINVAL; \
+})
+#define TABLE_POPULATE_KEY_IPV4(dst, _table, _field, _value) \
+ efx_mae_table_populate_ipv4(efx->tc->meta_##_table.desc.keys \
+ [efx->tc->meta_##_table.keys._field##_idx],\
+ dst, efx->tc->meta_##_table.desc.key_width,\
+ _value)
+#define TABLE_POPULATE_KEY(dst, _table, _field, _value) \
+ _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.key_width, \
+ efx->tc->meta_##_table.desc.keys \
+ [efx->tc->meta_##_table.keys._field##_idx], \
+ _value)
+
+#define TABLE_POPULATE_RESP_BOOL(dst, _table, _field, _value) \
+ efx_mae_table_populate_bool(efx->tc->meta_##_table.desc.resps \
+ [efx->tc->meta_##_table.resps._field##_idx],\
+ dst, efx->tc->meta_##_table.desc.resp_width,\
+ _value)
+#define TABLE_POPULATE_RESP(dst, _table, _field, _value) \
+ _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.resp_width, \
+ efx->tc->meta_##_table.desc.resps \
+ [efx->tc->meta_##_table.resps._field##_idx], \
+ _value)
+
+#define TABLE_POPULATE_RESP_U24(dst, _table, _field, _value) \
+ efx_mae_table_populate_u24(efx->tc->meta_##_table.desc.resps \
+ [efx->tc->meta_##_table.resps._field##_idx],\
+ dst, efx->tc->meta_##_table.desc.resp_width,\
+ _value)
+
+static int efx_mae_populate_ct_key(struct efx_nic *efx, __le32 *key, size_t kw,
+ struct efx_tc_ct_entry *conn)
+{
+ bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
+ int rc;
+
+ rc = TABLE_POPULATE_KEY(key, ct, eth_proto, conn->eth_proto);
+ if (rc)
+ return rc;
+ rc = TABLE_POPULATE_KEY(key, ct, ip_proto, conn->ip_proto);
+ if (rc)
+ return rc;
+ if (ipv6)
+ rc = TABLE_POPULATE_KEY(key, ct, src_ip, conn->src_ip6);
+ else
+ rc = TABLE_POPULATE_KEY_IPV4(key, ct, src_ip, conn->src_ip);
+ if (rc)
+ return rc;
+ if (ipv6)
+ rc = TABLE_POPULATE_KEY(key, ct, dst_ip, conn->dst_ip6);
+ else
+ rc = TABLE_POPULATE_KEY_IPV4(key, ct, dst_ip, conn->dst_ip);
+ if (rc)
+ return rc;
+ rc = TABLE_POPULATE_KEY(key, ct, l4_sport, conn->l4_sport);
+ if (rc)
+ return rc;
+ rc = TABLE_POPULATE_KEY(key, ct, l4_dport, conn->l4_dport);
+ if (rc)
+ return rc;
+ return TABLE_POPULATE_KEY(key, ct, zone, cpu_to_be16(conn->zone->zone));
+}
+
+int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
+{
+ bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
+ __le32 *key = NULL, *resp = NULL;
+ size_t inlen, kw, rw;
+ efx_dword_t *inbuf;
+ int rc = -ENOMEM;
+
+ /* Check table access is supported */
+ if (!efx->tc->meta_ct.hooked)
+ return -EOPNOTSUPP;
+
+ /* key/resp widths are in bits; convert to dwords for IN_LEN */
+ kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32);
+ rw = DIV_ROUND_UP(efx->tc->meta_ct.desc.resp_width, 32);
+ BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_INSERT_IN_DATA_LEN);
+ inlen = MC_CMD_TABLE_INSERT_IN_LEN(kw + rw);
+ if (inlen > MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2)
+ return -E2BIG;
+ inbuf = kzalloc(inlen, GFP_KERNEL);
+ if (!inbuf)
+ return -ENOMEM;
+
+ key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
+ if (!key)
+ goto out_free;
+ resp = kcalloc(rw, sizeof(__le32), GFP_KERNEL);
+ if (!resp)
+ goto out_free;
+
+ rc = efx_mae_populate_ct_key(efx, key, kw, conn);
+ if (rc)
+ goto out_free;
+
+ rc = TABLE_POPULATE_RESP_BOOL(resp, ct, dnat, conn->dnat);
+ if (rc)
+ goto out_free;
+ /* No support in hw for IPv6 NAT; field is only 32 bits */
+ if (!ipv6)
+ rc = TABLE_POPULATE_RESP(resp, ct, nat_ip, conn->nat_ip);
+ if (rc)
+ goto out_free;
+ rc = TABLE_POPULATE_RESP(resp, ct, l4_natport, conn->l4_natport);
+ if (rc)
+ goto out_free;
+ rc = TABLE_POPULATE_RESP(resp, ct, mark, cpu_to_be32(conn->mark));
+ if (rc)
+ goto out_free;
+ rc = TABLE_POPULATE_RESP_U24(resp, ct, counter_id, conn->cnt->fw_id);
+ if (rc)
+ goto out_free;
+
+ MCDI_SET_DWORD(inbuf, TABLE_INSERT_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE);
+ MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_KEY_WIDTH,
+ efx->tc->meta_ct.desc.key_width);
+ /* MASK_WIDTH is zero as CT is a BCAM */
+ MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_RESP_WIDTH,
+ efx->tc->meta_ct.desc.resp_width);
+ memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA), key, kw * sizeof(__le32));
+ memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA) + kw * sizeof(__le32),
+ resp, rw * sizeof(__le32));
+
+ BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_INSERT, inbuf, inlen, NULL, 0, NULL);
+
+out_free:
+ kfree(resp);
+ kfree(key);
+ kfree(inbuf);
+ return rc;
+}
+
+int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
+{
+ __le32 *key = NULL;
+ efx_dword_t *inbuf;
+ size_t inlen, kw;
+ int rc = -ENOMEM;
+
+ /* Check table access is supported */
+ if (!efx->tc->meta_ct.hooked)
+ return -EOPNOTSUPP;
+
+ /* key width is in bits; convert to dwords for IN_LEN */
+ kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32);
+ BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_DELETE_IN_DATA_LEN);
+ inlen = MC_CMD_TABLE_DELETE_IN_LEN(kw);
+ if (inlen > MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2)
+ return -E2BIG;
+ inbuf = kzalloc(inlen, GFP_KERNEL);
+ if (!inbuf)
+ return -ENOMEM;
+
+ key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
+ if (!key)
+ goto out_free;
+
+ rc = efx_mae_populate_ct_key(efx, key, kw, conn);
+ if (rc)
+ goto out_free;
+
+ MCDI_SET_DWORD(inbuf, TABLE_DELETE_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE);
+ MCDI_SET_WORD(inbuf, TABLE_DELETE_IN_KEY_WIDTH,
+ efx->tc->meta_ct.desc.key_width);
+ /* MASK_WIDTH is zero as CT is a BCAM */
+ /* RESP_WIDTH is zero for DELETE */
+ memcpy(MCDI_PTR(inbuf, TABLE_DELETE_IN_DATA), key, kw * sizeof(__le32));
+
+ BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN);
+
+ rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DELETE, inbuf, inlen, NULL, 0, NULL);
+
+out_free:
+ kfree(key);
+ kfree(inbuf);
+ return rc;
+}
+
static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
const struct efx_tc_match *match)
{
@@ -1165,20 +2041,40 @@ static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
}
MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
match->mask.ingress_port);
- EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS),
+ EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS),
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT,
+ match->value.ct_state_trk,
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT,
+ match->value.ct_state_est,
MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
match->value.ip_frag,
MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
- match->value.ip_firstfrag);
- EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK),
+ match->value.ip_firstfrag,
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST,
+ match->value.tcp_syn_fin_rst);
+ EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK),
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT,
+ match->mask.ct_state_trk,
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT,
+ match->mask.ct_state_est,
MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
match->mask.ip_frag,
MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
- match->mask.ip_firstfrag);
+ match->mask.ip_firstfrag,
+ MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST,
+ match->mask.tcp_syn_fin_rst);
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID,
match->value.recirc_id);
MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
match->mask.recirc_id);
+ MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK,
+ match->value.ct_mark);
+ MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK_MASK,
+ match->mask.ct_mark);
+ MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN,
+ match->value.ct_zone);
+ MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN_MASK,
+ match->mask.ct_zone);
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE,
match->value.eth_proto);
MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK,
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index 24abfe509690..8df30bc4f3ba 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -66,6 +66,9 @@ int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
void efx_mae_counters_grant_credits(struct work_struct *work);
+int efx_mae_get_tables(struct efx_nic *efx);
+void efx_mae_free_tables(struct efx_nic *efx);
+
#define MAE_NUM_FIELDS (MAE_FIELD_ENC_VNET_ID + 1)
struct mae_caps {
@@ -81,6 +84,9 @@ int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps);
int efx_mae_match_check_caps(struct efx_nic *efx,
const struct efx_tc_match_fields *mask,
struct netlink_ext_ack *extack);
+int efx_mae_match_check_caps_lhs(struct efx_nic *efx,
+ const struct efx_tc_match_fields *mask,
+ struct netlink_ext_ack *extack);
int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6,
u8 ip_tos_mask, __be16 udp_sport_mask,
struct netlink_ext_ack *extack);
@@ -97,6 +103,10 @@ int efx_mae_update_encap_md(struct efx_nic *efx,
int efx_mae_free_encap_md(struct efx_nic *efx,
struct efx_tc_encap_action *encap);
+int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
+ struct efx_tc_mac_pedit_action *ped);
+void efx_mae_free_pedit_mac(struct efx_nic *efx,
+ struct efx_tc_mac_pedit_action *ped);
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act);
int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
@@ -109,6 +119,12 @@ int efx_mae_register_encap_match(struct efx_nic *efx,
struct efx_tc_encap_match *encap);
int efx_mae_unregister_encap_match(struct efx_nic *efx,
struct efx_tc_encap_match *encap);
+int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule,
+ u32 prio);
+int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule);
+struct efx_tc_ct_entry; /* see tc_conntrack.h */
+int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn);
+int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn);
int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
u32 prio, u32 acts_id, u32 *id);
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index a7f2c31071e8..d23da9627338 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -10,7 +10,6 @@
#include "net_driver.h"
#include "nic.h"
#include "io.h"
-#include "farch_regs.h"
#include "mcdi_pcol.h"
/**************************************************************************
@@ -1353,12 +1352,6 @@ void efx_mcdi_process_event(struct efx_channel *channel,
case MCDI_EVENT_CODE_MAC_STATS_DMA:
/* MAC stats are gather lazily. We can ignore this. */
break;
- case MCDI_EVENT_CODE_FLR:
- if (efx->type->sriov_flr)
- efx->type->sriov_flr(efx,
- MCDI_EVENT_FIELD(*event, FLR_VF));
- break;
- case MCDI_EVENT_CODE_PTP_RX:
case MCDI_EVENT_CODE_PTP_FAULT:
case MCDI_EVENT_CODE_PTP_PPS:
efx_ptp_event(efx, event);
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 454e9d51a4c2..ea612c619874 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -218,14 +218,28 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
BUILD_BUG_ON(_field ## _LEN != 1); \
*(u8 *)MCDI_STRUCT_PTR(_buf, _field) = _value; \
} while (0)
+#define MCDI_STRUCT_POPULATE_BYTE_1(_buf, _field, _name, _value) do { \
+ efx_dword_t _temp; \
+ EFX_POPULATE_DWORD_1(_temp, _name, _value); \
+ MCDI_STRUCT_SET_BYTE(_buf, _field, \
+ EFX_DWORD_FIELD(_temp, EFX_BYTE_0)); \
+ } while (0)
#define MCDI_BYTE(_buf, _field) \
((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \
*MCDI_PTR(_buf, _field))
+#define MCDI_STRUCT_BYTE(_buf, _field) \
+ ((void)BUILD_BUG_ON_ZERO(_field ## _LEN != 1), \
+ *MCDI_STRUCT_PTR(_buf, _field))
#define MCDI_SET_WORD(_buf, _field, _value) do { \
BUILD_BUG_ON(MC_CMD_ ## _field ## _LEN != 2); \
BUILD_BUG_ON(MC_CMD_ ## _field ## _OFST & 1); \
*(__force __le16 *)MCDI_PTR(_buf, _field) = cpu_to_le16(_value);\
} while (0)
+#define MCDI_STRUCT_SET_WORD(_buf, _field, _value) do { \
+ BUILD_BUG_ON(_field ## _LEN != 2); \
+ BUILD_BUG_ON(_field ## _OFST & 1); \
+ *(__force __le16 *)MCDI_STRUCT_PTR(_buf, _field) = cpu_to_le16(_value);\
+ } while (0)
#define MCDI_WORD(_buf, _field) \
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
diff --git a/drivers/net/ethernet/sfc/mcdi_functions.c b/drivers/net/ethernet/sfc/mcdi_functions.c
index d3e6d8239f5c..ff8424167384 100644
--- a/drivers/net/ethernet/sfc/mcdi_functions.c
+++ b/drivers/net/ethernet/sfc/mcdi_functions.c
@@ -62,7 +62,7 @@ int efx_mcdi_alloc_vis(struct efx_nic *efx, unsigned int min_vis,
int efx_mcdi_ev_probe(struct efx_channel *channel)
{
- return efx_nic_alloc_buffer(channel->efx, &channel->eventq.buf,
+ return efx_nic_alloc_buffer(channel->efx, &channel->eventq,
(channel->eventq_mask + 1) *
sizeof(efx_qword_t),
GFP_KERNEL);
@@ -74,14 +74,14 @@ int efx_mcdi_ev_init(struct efx_channel *channel, bool v1_cut_thru, bool v2)
MC_CMD_INIT_EVQ_V2_IN_LEN(EFX_MAX_EVQ_SIZE * 8 /
EFX_BUF_SIZE));
MCDI_DECLARE_BUF(outbuf, MC_CMD_INIT_EVQ_V2_OUT_LEN);
- size_t entries = channel->eventq.buf.len / EFX_BUF_SIZE;
+ size_t entries = channel->eventq.len / EFX_BUF_SIZE;
struct efx_nic *efx = channel->efx;
size_t inlen, outlen;
dma_addr_t dma_addr;
int rc, i;
/* Fill event queue with all ones (i.e. empty events) */
- memset(channel->eventq.buf.addr, 0xff, channel->eventq.buf.len);
+ memset(channel->eventq.addr, 0xff, channel->eventq.len);
MCDI_SET_DWORD(inbuf, INIT_EVQ_IN_SIZE, channel->eventq_mask + 1);
MCDI_SET_DWORD(inbuf, INIT_EVQ_IN_INSTANCE, channel->channel);
@@ -112,7 +112,7 @@ int efx_mcdi_ev_init(struct efx_channel *channel, bool v1_cut_thru, bool v2)
INIT_EVQ_IN_FLAG_CUT_THRU, v1_cut_thru);
}
- dma_addr = channel->eventq.buf.dma_addr;
+ dma_addr = channel->eventq.dma_addr;
for (i = 0; i < entries; ++i) {
MCDI_SET_ARRAY_QWORD(inbuf, INIT_EVQ_IN_DMA_ADDR, i, dma_addr);
dma_addr += EFX_BUF_SIZE;
@@ -134,7 +134,7 @@ int efx_mcdi_ev_init(struct efx_channel *channel, bool v1_cut_thru, bool v2)
void efx_mcdi_ev_remove(struct efx_channel *channel)
{
- efx_nic_free_buffer(channel->efx, &channel->eventq.buf);
+ efx_nic_free_buffer(channel->efx, &channel->eventq);
}
void efx_mcdi_ev_fini(struct efx_channel *channel)
@@ -166,7 +166,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue)
EFX_BUF_SIZE));
bool csum_offload = tx_queue->type & EFX_TXQ_TYPE_OUTER_CSUM;
bool inner_csum = tx_queue->type & EFX_TXQ_TYPE_INNER_CSUM;
- size_t entries = tx_queue->txd.buf.len / EFX_BUF_SIZE;
+ size_t entries = tx_queue->txd.len / EFX_BUF_SIZE;
struct efx_channel *channel = tx_queue->channel;
struct efx_nic *efx = tx_queue->efx;
dma_addr_t dma_addr;
@@ -182,7 +182,7 @@ int efx_mcdi_tx_init(struct efx_tx_queue *tx_queue)
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_OWNER_ID, 0);
MCDI_SET_DWORD(inbuf, INIT_TXQ_IN_PORT_ID, efx->vport_id);
- dma_addr = tx_queue->txd.buf.dma_addr;
+ dma_addr = tx_queue->txd.dma_addr;
netif_dbg(efx, hw, efx->net_dev, "pushing TXQ %d. %zu entries (%llx)\n",
tx_queue->queue, entries, (u64)dma_addr);
@@ -240,7 +240,7 @@ fail:
void efx_mcdi_tx_remove(struct efx_tx_queue *tx_queue)
{
- efx_nic_free_buffer(tx_queue->efx, &tx_queue->txd.buf);
+ efx_nic_free_buffer(tx_queue->efx, &tx_queue->txd);
}
void efx_mcdi_tx_fini(struct efx_tx_queue *tx_queue)
@@ -269,7 +269,7 @@ fail:
int efx_mcdi_rx_probe(struct efx_rx_queue *rx_queue)
{
- return efx_nic_alloc_buffer(rx_queue->efx, &rx_queue->rxd.buf,
+ return efx_nic_alloc_buffer(rx_queue->efx, &rx_queue->rxd,
(rx_queue->ptr_mask + 1) *
sizeof(efx_qword_t),
GFP_KERNEL);
@@ -278,7 +278,7 @@ int efx_mcdi_rx_probe(struct efx_rx_queue *rx_queue)
void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
{
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
- size_t entries = rx_queue->rxd.buf.len / EFX_BUF_SIZE;
+ size_t entries = rx_queue->rxd.len / EFX_BUF_SIZE;
MCDI_DECLARE_BUF(inbuf, MC_CMD_INIT_RXQ_V4_IN_LEN);
struct efx_nic *efx = rx_queue->efx;
unsigned int buffer_size;
@@ -306,7 +306,7 @@ void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
MCDI_SET_DWORD(inbuf, INIT_RXQ_IN_PORT_ID, efx->vport_id);
MCDI_SET_DWORD(inbuf, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES, buffer_size);
- dma_addr = rx_queue->rxd.buf.dma_addr;
+ dma_addr = rx_queue->rxd.dma_addr;
netif_dbg(efx, hw, efx->net_dev, "pushing RXQ %d. %zu entries (%llx)\n",
efx_rx_queue_index(rx_queue), entries, (u64)dma_addr);
@@ -325,7 +325,7 @@ void efx_mcdi_rx_init(struct efx_rx_queue *rx_queue)
void efx_mcdi_rx_remove(struct efx_rx_queue *rx_queue)
{
- efx_nic_free_buffer(rx_queue->efx, &rx_queue->rxd.buf);
+ efx_nic_free_buffer(rx_queue->efx, &rx_queue->rxd);
}
void efx_mcdi_rx_fini(struct efx_rx_queue *rx_queue)
diff --git a/drivers/net/ethernet/sfc/mcdi_port_common.c b/drivers/net/ethernet/sfc/mcdi_port_common.c
index 0ab14f3d01d4..76ea26722ca4 100644
--- a/drivers/net/ethernet/sfc/mcdi_port_common.c
+++ b/drivers/net/ethernet/sfc/mcdi_port_common.c
@@ -1106,11 +1106,6 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, efx_calc_mac_mtu(efx));
MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0);
-
- /* Set simple MAC filter for Siena */
- MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_REJECT,
- SET_MAC_IN_REJECT_UNCST, efx->unicast_filter);
-
MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_FLAGS,
SET_MAC_IN_FLAG_INCLUDE_FCS,
!!(efx->net_dev->features & NETIF_F_RXFCS));
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index a7a22b019794..27d86e90a3bb 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -67,9 +67,7 @@
#define EFX_MAX_CORE_TX_QUEUES (EFX_MAX_TX_TC * EFX_MAX_CHANNELS)
#define EFX_TXQ_TYPE_OUTER_CSUM 1 /* Outer checksum offload */
#define EFX_TXQ_TYPE_INNER_CSUM 2 /* Inner checksum offload */
-#define EFX_TXQ_TYPE_HIGHPRI 4 /* High-priority (for TC) */
-#define EFX_TXQ_TYPES 8
-/* HIGHPRI is Siena-only, and INNER_CSUM is EF10, so no need for both */
+#define EFX_TXQ_TYPES 4
#define EFX_MAX_TXQ_PER_CHANNEL 4
#define EFX_MAX_TX_QUEUES (EFX_MAX_TXQ_PER_CHANNEL * EFX_MAX_CHANNELS)
@@ -125,26 +123,6 @@ struct efx_buffer {
};
/**
- * struct efx_special_buffer - DMA buffer entered into buffer table
- * @buf: Standard &struct efx_buffer
- * @index: Buffer index within controller;s buffer table
- * @entries: Number of buffer table entries
- *
- * The NIC has a buffer table that maps buffers of size %EFX_BUF_SIZE.
- * Event and descriptor rings are addressed via one or more buffer
- * table entries (and so can be physically non-contiguous, although we
- * currently do not take advantage of that). On Falcon and Siena we
- * have to take care of allocating and initialising the entries
- * ourselves. On later hardware this is managed by the firmware and
- * @index and @entries are left as 0.
- */
-struct efx_special_buffer {
- struct efx_buffer buf;
- unsigned int index;
- unsigned int entries;
-};
-
-/**
* struct efx_tx_buffer - buffer state for a TX descriptor
* @skb: When @flags & %EFX_TX_BUF_SKB, the associated socket buffer to be
* freed when descriptor completes
@@ -237,7 +215,7 @@ struct efx_tx_buffer {
* Normally this will equal @write_count, but as option descriptors
* don't produce completion events, they won't update this.
* Filled in iff @efx->type->option_descriptors; only used for PIO.
- * Thus, this is written and used on EF10, and neither on farch.
+ * Thus, this is only written and used on EF10.
* @old_read_count: The value of read_count when last checked.
* This is here for performance reasons. The xmit path will
* only get the up-to-date value of read_count if this
@@ -270,7 +248,7 @@ struct efx_tx_queue {
struct netdev_queue *core_txq;
struct efx_tx_buffer *buffer;
struct efx_buffer *cb_page;
- struct efx_special_buffer txd;
+ struct efx_buffer txd;
unsigned int ptr_mask;
void __iomem *piobuf;
unsigned int piobuf_offset;
@@ -399,7 +377,7 @@ struct efx_rx_queue {
struct efx_nic *efx;
int core_index;
struct efx_rx_buffer *buffer;
- struct efx_special_buffer rxd;
+ struct efx_buffer rxd;
unsigned int ptr_mask;
bool refill_enabled;
bool flush_pending;
@@ -515,7 +493,7 @@ struct efx_channel {
#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned long busy_poll_state;
#endif
- struct efx_special_buffer eventq;
+ struct efx_buffer eventq;
unsigned int eventq_mask;
unsigned int eventq_read_ptr;
int event_test_cpu;
@@ -754,18 +732,6 @@ struct efx_hw_stat_desc {
u16 offset;
};
-/* Number of bits used in a multicast filter hash address */
-#define EFX_MCAST_HASH_BITS 8
-
-/* Number of (single-bit) entries in a multicast filter hash */
-#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
-
-/* An Efx multicast filter hash */
-union efx_multicast_hash {
- u8 byte[EFX_MCAST_HASH_ENTRIES / 8];
- efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
-};
-
struct vfdi_status;
/* The reserved RSS context value */
@@ -895,7 +861,6 @@ struct efx_mae;
* @tx_dc_base: Base qword address in SRAM of TX queue descriptor caches
* @rx_dc_base: Base qword address in SRAM of RX queue descriptor caches
* @sram_lim_qw: Qword address limit of SRAM
- * @next_buffer_table: First available buffer table id
* @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
* @n_tx_channels: Number of channels used for TX
@@ -957,10 +922,6 @@ struct efx_mae;
* see &enum ethtool_fec_config_bits.
* @link_state: Current state of the link
* @n_link_state_changes: Number of times the link has changed state
- * @unicast_filter: Flag for Falcon-arch simple unicast filter.
- * Protected by @mac_lock.
- * @multicast_hash: Multicast hash table for Falcon-arch.
- * Protected by @mac_lock.
* @wanted_fc: Wanted flow control flags
* @fc_disable: When non-zero flow control is disabled. Typically used to
* ensure that network back pressure doesn't delay dma queue flushes.
@@ -1064,7 +1025,6 @@ struct efx_nic {
unsigned tx_dc_base;
unsigned rx_dc_base;
unsigned sram_lim_qw;
- unsigned next_buffer_table;
unsigned int max_channels;
unsigned int max_vis;
@@ -1139,8 +1099,6 @@ struct efx_nic {
struct efx_link_state link_state;
unsigned int n_link_state_changes;
- bool unicast_filter;
- union efx_multicast_hash multicast_hash;
u8 wanted_fc;
unsigned fc_disable;
@@ -1263,10 +1221,6 @@ struct efx_udp_tunnel {
* @remove_port: Free resources allocated by probe_port()
* @handle_global_event: Handle a "global" event (may be %NULL)
* @fini_dmaq: Flush and finalise DMA queues (RX and TX queues)
- * @prepare_flush: Prepare the hardware for flushing the DMA queues
- * (for Falcon architecture)
- * @finish_flush: Clean up after flushing the DMA queues (for Falcon
- * architecture)
* @prepare_flr: Prepare for an FLR
* @finish_flr: Clean up after an FLR
* @describe_stats: Describe statistics for ethtool
@@ -1288,8 +1242,7 @@ struct efx_udp_tunnel {
* @set_wol: Push WoL configuration to the NIC
* @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
* @get_fec_stats: Get standard FEC statistics.
- * @test_chip: Test registers. May use efx_farch_test_registers(), and is
- * expected to reset the NIC.
+ * @test_chip: Test registers. This is expected to reset the NIC.
* @test_nvram: Test validity of NVRAM contents
* @mcdi_request: Send an MCDI request with the given header and SDU.
* The SDU length may be any value from 0 up to the protocol-
@@ -1414,8 +1367,6 @@ struct efx_nic_type {
void (*remove_port)(struct efx_nic *efx);
bool (*handle_global_event)(struct efx_channel *channel, efx_qword_t *);
int (*fini_dmaq)(struct efx_nic *efx);
- void (*prepare_flush)(struct efx_nic *efx);
- 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);
@@ -1531,8 +1482,6 @@ struct efx_nic_type {
int (*sriov_init)(struct efx_nic *efx);
void (*sriov_fini)(struct efx_nic *efx);
bool (*sriov_wanted)(struct efx_nic *efx);
- void (*sriov_reset)(struct efx_nic *efx);
- void (*sriov_flr)(struct efx_nic *efx, unsigned vf_i);
int (*sriov_set_vf_mac)(struct efx_nic *efx, int vf_i, const u8 *mac);
int (*sriov_set_vf_vlan)(struct efx_nic *efx, int vf_i, u16 vlan,
u8 qos);
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index 63e2394382bb..a33ed473cc8a 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -17,7 +17,6 @@
#include "efx.h"
#include "nic.h"
#include "ef10_regs.h"
-#include "farch_regs.h"
#include "io.h"
#include "workarounds.h"
#include "mcdi_pcol.h"
@@ -172,10 +171,6 @@ void efx_nic_fini_interrupt(struct efx_nic *efx)
/* Register dump */
-#define REGISTER_REVISION_FA 1
-#define REGISTER_REVISION_FB 2
-#define REGISTER_REVISION_FC 3
-#define REGISTER_REVISION_FZ 3 /* last Falcon arch revision */
#define REGISTER_REVISION_ED 4
#define REGISTER_REVISION_EZ 4 /* latest EF10 revision */
@@ -189,117 +184,9 @@ struct efx_nic_reg {
REGISTER_REVISION_ ## arch ## min_rev, \
REGISTER_REVISION_ ## arch ## max_rev \
}
-#define REGISTER_AA(name) REGISTER(name, F, A, A)
-#define REGISTER_AB(name) REGISTER(name, F, A, B)
-#define REGISTER_AZ(name) REGISTER(name, F, A, Z)
-#define REGISTER_BB(name) REGISTER(name, F, B, B)
-#define REGISTER_BZ(name) REGISTER(name, F, B, Z)
-#define REGISTER_CZ(name) REGISTER(name, F, C, Z)
#define REGISTER_DZ(name) REGISTER(name, E, D, Z)
static const struct efx_nic_reg efx_nic_regs[] = {
- REGISTER_AZ(ADR_REGION),
- REGISTER_AZ(INT_EN_KER),
- REGISTER_BZ(INT_EN_CHAR),
- REGISTER_AZ(INT_ADR_KER),
- REGISTER_BZ(INT_ADR_CHAR),
- /* INT_ACK_KER is WO */
- /* INT_ISR0 is RC */
- REGISTER_AZ(HW_INIT),
- REGISTER_CZ(USR_EV_CFG),
- REGISTER_AB(EE_SPI_HCMD),
- REGISTER_AB(EE_SPI_HADR),
- REGISTER_AB(EE_SPI_HDATA),
- REGISTER_AB(EE_BASE_PAGE),
- REGISTER_AB(EE_VPD_CFG0),
- /* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */
- /* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */
- /* PCIE_CORE_INDIRECT is indirect */
- REGISTER_AB(NIC_STAT),
- REGISTER_AB(GPIO_CTL),
- REGISTER_AB(GLB_CTL),
- /* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */
- REGISTER_BZ(DP_CTRL),
- REGISTER_AZ(MEM_STAT),
- REGISTER_AZ(CS_DEBUG),
- REGISTER_AZ(ALTERA_BUILD),
- REGISTER_AZ(CSR_SPARE),
- REGISTER_AB(PCIE_SD_CTL0123),
- REGISTER_AB(PCIE_SD_CTL45),
- REGISTER_AB(PCIE_PCS_CTL_STAT),
- /* DEBUG_DATA_OUT is not used */
- /* DRV_EV is WO */
- REGISTER_AZ(EVQ_CTL),
- REGISTER_AZ(EVQ_CNT1),
- REGISTER_AZ(EVQ_CNT2),
- REGISTER_AZ(BUF_TBL_CFG),
- REGISTER_AZ(SRM_RX_DC_CFG),
- REGISTER_AZ(SRM_TX_DC_CFG),
- REGISTER_AZ(SRM_CFG),
- /* BUF_TBL_UPD is WO */
- REGISTER_AZ(SRM_UPD_EVQ),
- REGISTER_AZ(SRAM_PARITY),
- REGISTER_AZ(RX_CFG),
- REGISTER_BZ(RX_FILTER_CTL),
- /* RX_FLUSH_DESCQ is WO */
- REGISTER_AZ(RX_DC_CFG),
- REGISTER_AZ(RX_DC_PF_WM),
- REGISTER_BZ(RX_RSS_TKEY),
- /* RX_NODESC_DROP is RC */
- REGISTER_AA(RX_SELF_RST),
- /* RX_DEBUG, RX_PUSH_DROP are not used */
- REGISTER_CZ(RX_RSS_IPV6_REG1),
- REGISTER_CZ(RX_RSS_IPV6_REG2),
- REGISTER_CZ(RX_RSS_IPV6_REG3),
- /* TX_FLUSH_DESCQ is WO */
- REGISTER_AZ(TX_DC_CFG),
- REGISTER_AA(TX_CHKSM_CFG),
- REGISTER_AZ(TX_CFG),
- /* TX_PUSH_DROP is not used */
- REGISTER_AZ(TX_RESERVED),
- REGISTER_BZ(TX_PACE),
- /* TX_PACE_DROP_QID is RC */
- REGISTER_BB(TX_VLAN),
- REGISTER_BZ(TX_IPFIL_PORTEN),
- REGISTER_AB(MD_TXD),
- REGISTER_AB(MD_RXD),
- REGISTER_AB(MD_CS),
- REGISTER_AB(MD_PHY_ADR),
- REGISTER_AB(MD_ID),
- /* MD_STAT is RC */
- REGISTER_AB(MAC_STAT_DMA),
- REGISTER_AB(MAC_CTRL),
- REGISTER_BB(GEN_MODE),
- REGISTER_AB(MAC_MC_HASH_REG0),
- REGISTER_AB(MAC_MC_HASH_REG1),
- REGISTER_AB(GM_CFG1),
- REGISTER_AB(GM_CFG2),
- /* GM_IPG and GM_HD are not used */
- REGISTER_AB(GM_MAX_FLEN),
- /* GM_TEST is not used */
- REGISTER_AB(GM_ADR1),
- REGISTER_AB(GM_ADR2),
- REGISTER_AB(GMF_CFG0),
- REGISTER_AB(GMF_CFG1),
- REGISTER_AB(GMF_CFG2),
- REGISTER_AB(GMF_CFG3),
- REGISTER_AB(GMF_CFG4),
- REGISTER_AB(GMF_CFG5),
- REGISTER_BB(TX_SRC_MAC_CTL),
- REGISTER_AB(XM_ADR_LO),
- REGISTER_AB(XM_ADR_HI),
- REGISTER_AB(XM_GLB_CFG),
- REGISTER_AB(XM_TX_CFG),
- REGISTER_AB(XM_RX_CFG),
- REGISTER_AB(XM_MGT_INT_MASK),
- REGISTER_AB(XM_FC),
- REGISTER_AB(XM_PAUSE_TIME),
- REGISTER_AB(XM_TX_PARAM),
- REGISTER_AB(XM_RX_PARAM),
- /* XM_MGT_INT_MSK (note no 'A') is RC */
- REGISTER_AB(XX_PWR_RST),
- REGISTER_AB(XX_SD_CTL),
- REGISTER_AB(XX_TXDRV_CTL),
/* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */
/* XX_CORE_STAT is partly RC */
REGISTER_DZ(BIU_HW_REV_ID),
@@ -325,49 +212,9 @@ struct efx_nic_reg_table {
arch, min_rev, max_rev, \
arch ## R_ ## min_rev ## max_rev ## _ ## name ## _STEP, \
arch ## R_ ## min_rev ## max_rev ## _ ## name ## _ROWS)
-#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, F, A, A)
-#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, F, A, Z)
-#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, F, B, B)
-#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, F, B, Z)
-#define REGISTER_TABLE_BB_CZ(name) \
- REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, B, B, \
- FR_BZ_ ## name ## _STEP, \
- FR_BB_ ## name ## _ROWS), \
- REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, C, Z, \
- FR_BZ_ ## name ## _STEP, \
- FR_CZ_ ## name ## _ROWS)
-#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, F, C, Z)
#define REGISTER_TABLE_DZ(name) REGISTER_TABLE(name, E, D, Z)
static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
- /* DRIVER is not used */
- /* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */
- REGISTER_TABLE_BB(TX_IPFIL_TBL),
- REGISTER_TABLE_BB(TX_SRC_MAC_TBL),
- REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER),
- REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL),
- REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER),
- REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL),
- REGISTER_TABLE_AA(EVQ_PTR_TBL_KER),
- REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL),
- /* We can't reasonably read all of the buffer table (up to 8MB!).
- * However this driver will only use a few entries. Reading
- * 1K entries allows for some expansion of queue count and
- * size before we need to change the version. */
- REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER,
- F, A, A, 8, 1024),
- REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL,
- F, B, Z, 8, 1024),
- REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0),
- REGISTER_TABLE_BB_CZ(TIMER_TBL),
- REGISTER_TABLE_BB_CZ(TX_PACE_TBL),
- REGISTER_TABLE_BZ(RX_INDIRECTION_TBL),
- /* TX_FILTER_TBL0 is huge and not used by this driver */
- REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0),
- REGISTER_TABLE_CZ(MC_TREG_SMEM),
- /* MSIX_PBA_TABLE is not mapped */
- /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */
- REGISTER_TABLE_BZ(RX_FILTER_TBL0),
REGISTER_TABLE_DZ(BIU_MC_SFT_STATUS),
};
@@ -425,11 +272,6 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
case 4: /* 32-bit SRAM */
efx_readd(efx, buf, table->offset + 4 * i);
break;
- case 8: /* 64-bit SRAM */
- efx_sram_readq(efx,
- efx->membase + table->offset,
- buf, i);
- break;
case 16: /* 128-bit-readable register */
efx_reado_table(efx, buf, table->offset, i);
break;
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 251868235ae4..1db64fc6e909 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -11,8 +11,6 @@
#include "nic_common.h"
#include "efx.h"
-u32 efx_farch_fpga_ver(struct efx_nic *efx);
-
enum {
PHY_TYPE_NONE = 0,
PHY_TYPE_TXC43128 = 1,
@@ -26,97 +24,6 @@ enum {
};
enum {
- SIENA_STAT_tx_bytes = GENERIC_STAT_COUNT,
- SIENA_STAT_tx_good_bytes,
- SIENA_STAT_tx_bad_bytes,
- SIENA_STAT_tx_packets,
- SIENA_STAT_tx_bad,
- SIENA_STAT_tx_pause,
- SIENA_STAT_tx_control,
- SIENA_STAT_tx_unicast,
- SIENA_STAT_tx_multicast,
- SIENA_STAT_tx_broadcast,
- SIENA_STAT_tx_lt64,
- SIENA_STAT_tx_64,
- SIENA_STAT_tx_65_to_127,
- SIENA_STAT_tx_128_to_255,
- SIENA_STAT_tx_256_to_511,
- SIENA_STAT_tx_512_to_1023,
- SIENA_STAT_tx_1024_to_15xx,
- SIENA_STAT_tx_15xx_to_jumbo,
- SIENA_STAT_tx_gtjumbo,
- SIENA_STAT_tx_collision,
- SIENA_STAT_tx_single_collision,
- SIENA_STAT_tx_multiple_collision,
- SIENA_STAT_tx_excessive_collision,
- SIENA_STAT_tx_deferred,
- SIENA_STAT_tx_late_collision,
- SIENA_STAT_tx_excessive_deferred,
- SIENA_STAT_tx_non_tcpudp,
- SIENA_STAT_tx_mac_src_error,
- SIENA_STAT_tx_ip_src_error,
- SIENA_STAT_rx_bytes,
- SIENA_STAT_rx_good_bytes,
- SIENA_STAT_rx_bad_bytes,
- SIENA_STAT_rx_packets,
- SIENA_STAT_rx_good,
- SIENA_STAT_rx_bad,
- SIENA_STAT_rx_pause,
- SIENA_STAT_rx_control,
- SIENA_STAT_rx_unicast,
- SIENA_STAT_rx_multicast,
- SIENA_STAT_rx_broadcast,
- SIENA_STAT_rx_lt64,
- SIENA_STAT_rx_64,
- SIENA_STAT_rx_65_to_127,
- SIENA_STAT_rx_128_to_255,
- SIENA_STAT_rx_256_to_511,
- SIENA_STAT_rx_512_to_1023,
- SIENA_STAT_rx_1024_to_15xx,
- SIENA_STAT_rx_15xx_to_jumbo,
- SIENA_STAT_rx_gtjumbo,
- SIENA_STAT_rx_bad_gtjumbo,
- SIENA_STAT_rx_overflow,
- SIENA_STAT_rx_false_carrier,
- SIENA_STAT_rx_symbol_error,
- SIENA_STAT_rx_align_error,
- SIENA_STAT_rx_length_error,
- SIENA_STAT_rx_internal_error,
- SIENA_STAT_rx_nodesc_drop_cnt,
- SIENA_STAT_COUNT
-};
-
-/**
- * struct siena_nic_data - Siena NIC state
- * @efx: Pointer back to main interface structure
- * @wol_filter_id: Wake-on-LAN packet filter id
- * @stats: Hardware statistics
- * @vf: Array of &struct siena_vf objects
- * @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
- * @vfdi_status: Common VFDI status page to be dmad to VF address space.
- * @local_addr_list: List of local addresses. Protected by %local_lock.
- * @local_page_list: List of DMA addressable pages used to broadcast
- * %local_addr_list. Protected by %local_lock.
- * @local_lock: Mutex protecting %local_addr_list and %local_page_list.
- * @peer_work: Work item to broadcast peer addresses to VMs.
- */
-struct siena_nic_data {
- struct efx_nic *efx;
- int wol_filter_id;
- u64 stats[SIENA_STAT_COUNT];
-#ifdef CONFIG_SFC_SRIOV
- struct siena_vf *vf;
- struct efx_channel *vfdi_channel;
- unsigned vf_buftbl_base;
- struct efx_buffer vfdi_status;
- struct list_head local_addr_list;
- struct list_head local_page_list;
- struct mutex local_lock;
- struct work_struct peer_work;
-#endif
-};
-
-enum {
EF10_STAT_port_tx_bytes = GENERIC_STAT_COUNT,
EF10_STAT_port_tx_packets,
EF10_STAT_port_tx_pause,
@@ -304,89 +211,4 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
extern const struct efx_nic_type efx_hunt_a0_nic_type;
extern const struct efx_nic_type efx_hunt_a0_vf_nic_type;
-int falcon_probe_board(struct efx_nic *efx, u16 revision_info);
-
-/* Falcon/Siena queue operations */
-int efx_farch_tx_probe(struct efx_tx_queue *tx_queue);
-void efx_farch_tx_init(struct efx_tx_queue *tx_queue);
-void efx_farch_tx_fini(struct efx_tx_queue *tx_queue);
-void efx_farch_tx_remove(struct efx_tx_queue *tx_queue);
-void efx_farch_tx_write(struct efx_tx_queue *tx_queue);
-unsigned int efx_farch_tx_limit_len(struct efx_tx_queue *tx_queue,
- dma_addr_t dma_addr, unsigned int len);
-int efx_farch_rx_probe(struct efx_rx_queue *rx_queue);
-void efx_farch_rx_init(struct efx_rx_queue *rx_queue);
-void efx_farch_rx_fini(struct efx_rx_queue *rx_queue);
-void efx_farch_rx_remove(struct efx_rx_queue *rx_queue);
-void efx_farch_rx_write(struct efx_rx_queue *rx_queue);
-void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue);
-int efx_farch_ev_probe(struct efx_channel *channel);
-int efx_farch_ev_init(struct efx_channel *channel);
-void efx_farch_ev_fini(struct efx_channel *channel);
-void efx_farch_ev_remove(struct efx_channel *channel);
-int efx_farch_ev_process(struct efx_channel *channel, int quota);
-void efx_farch_ev_read_ack(struct efx_channel *channel);
-void efx_farch_ev_test_generate(struct efx_channel *channel);
-
-/* Falcon/Siena filter operations */
-int efx_farch_filter_table_probe(struct efx_nic *efx);
-void efx_farch_filter_table_restore(struct efx_nic *efx);
-void efx_farch_filter_table_remove(struct efx_nic *efx);
-void efx_farch_filter_update_rx_scatter(struct efx_nic *efx);
-s32 efx_farch_filter_insert(struct efx_nic *efx, struct efx_filter_spec *spec,
- bool replace);
-int efx_farch_filter_remove_safe(struct efx_nic *efx,
- enum efx_filter_priority priority,
- u32 filter_id);
-int efx_farch_filter_get_safe(struct efx_nic *efx,
- enum efx_filter_priority priority, u32 filter_id,
- struct efx_filter_spec *);
-int efx_farch_filter_clear_rx(struct efx_nic *efx,
- enum efx_filter_priority priority);
-u32 efx_farch_filter_count_rx_used(struct efx_nic *efx,
- enum efx_filter_priority priority);
-u32 efx_farch_filter_get_rx_id_limit(struct efx_nic *efx);
-s32 efx_farch_filter_get_rx_ids(struct efx_nic *efx,
- enum efx_filter_priority priority, u32 *buf,
- u32 size);
-#ifdef CONFIG_RFS_ACCEL
-bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
- unsigned int index);
-#endif
-void efx_farch_filter_sync_rx_mode(struct efx_nic *efx);
-
-/* Falcon/Siena interrupts */
-void efx_farch_irq_enable_master(struct efx_nic *efx);
-int efx_farch_irq_test_generate(struct efx_nic *efx);
-void efx_farch_irq_disable_master(struct efx_nic *efx);
-irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id);
-irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id);
-irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx);
-
-/* Global Resources */
-void siena_prepare_flush(struct efx_nic *efx);
-int efx_farch_fini_dmaq(struct efx_nic *efx);
-void efx_farch_finish_flr(struct efx_nic *efx);
-void siena_finish_flush(struct efx_nic *efx);
-void falcon_start_nic_stats(struct efx_nic *efx);
-void falcon_stop_nic_stats(struct efx_nic *efx);
-int falcon_reset_xaui(struct efx_nic *efx);
-void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw);
-void efx_farch_init_common(struct efx_nic *efx);
-void efx_farch_rx_push_indir_table(struct efx_nic *efx);
-void efx_farch_rx_pull_indir_table(struct efx_nic *efx);
-
-/* Tests */
-struct efx_farch_register_test {
- unsigned address;
- efx_oword_t mask;
-};
-
-int efx_farch_test_registers(struct efx_nic *efx,
- const struct efx_farch_register_test *regs,
- size_t n_regs);
-
-void efx_farch_generate_event(struct efx_nic *efx, unsigned int evq,
- efx_qword_t *event);
-
#endif /* EFX_NIC_H */
diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h
index 0cef35c0c559..466df5348b29 100644
--- a/drivers/net/ethernet/sfc/nic_common.h
+++ b/drivers/net/ethernet/sfc/nic_common.h
@@ -15,11 +15,10 @@
#include "ptp.h"
enum {
- /* Revisions 0-2 were Falcon A0, A1 and B0 respectively.
+ /* Revisions 0-3 were Falcon A0, A1, B0 and Siena respectively.
* They are not supported by this driver but these revision numbers
* form part of the ethtool API for register dumping.
*/
- EFX_REV_SIENA_A0 = 3,
EFX_REV_HUNT_A0 = 4,
EFX_REV_EF100 = 5,
};
@@ -33,7 +32,7 @@ static inline int efx_nic_rev(struct efx_nic *efx)
static inline efx_qword_t *efx_event(struct efx_channel *channel,
unsigned int index)
{
- return ((efx_qword_t *) (channel->eventq.buf.addr)) +
+ return ((efx_qword_t *)(channel->eventq.addr)) +
(index & channel->eventq_mask);
}
@@ -59,7 +58,7 @@ static inline int efx_event_present(efx_qword_t *event)
static inline efx_qword_t *
efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
{
- return ((efx_qword_t *) (tx_queue->txd.buf.addr)) + index;
+ return ((efx_qword_t *)(tx_queue->txd.addr)) + index;
}
/* Report whether this TX queue would be empty for the given write_count.
@@ -80,9 +79,7 @@ int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
/* Decide whether to push a TX descriptor to the NIC vs merely writing
* the doorbell. This can reduce latency when we are adding a single
- * descriptor to an empty queue, but is otherwise pointless. Further,
- * Falcon and Siena have hardware bugs (SF bug 33851) that may be
- * triggered if we don't check this.
+ * descriptor to an empty queue, but is otherwise pointless.
* We use the write_count used for the last doorbell push, to get the
* NIC's view of the tx queue.
*/
@@ -99,7 +96,7 @@ static inline bool efx_nic_may_push_tx_desc(struct efx_tx_queue *tx_queue,
static inline efx_qword_t *
efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
{
- return ((efx_qword_t *) (rx_queue->rxd.buf.addr)) + index;
+ return ((efx_qword_t *)(rx_queue->rxd.addr)) + index;
}
/* Alignment of PCIe DMA boundaries (4KB) */
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 0c40571133cb..f54200f03e15 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -43,7 +43,6 @@
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "io.h"
-#include "farch_regs.h"
#include "tx.h"
#include "nic.h" /* indirectly includes ptp.h */
#include "efx_channels.h"
@@ -87,9 +86,6 @@
#define PTP_V1_VERSION_LENGTH 2
#define PTP_V1_VERSION_OFFSET 28
-#define PTP_V1_UUID_LENGTH 6
-#define PTP_V1_UUID_OFFSET 50
-
#define PTP_V1_SEQUENCE_LENGTH 2
#define PTP_V1_SEQUENCE_OFFSET 58
@@ -101,17 +97,6 @@
#define PTP_V2_VERSION_LENGTH 1
#define PTP_V2_VERSION_OFFSET 29
-#define PTP_V2_UUID_LENGTH 8
-#define PTP_V2_UUID_OFFSET 48
-
-/* Although PTP V2 UUIDs are comprised a ClockIdentity (8) and PortNumber (2),
- * the MC only captures the last six bytes of the clock identity. These values
- * reflect those, not the ones used in the standard. The standard permits
- * mapping of V1 UUIDs to V2 UUIDs with these same values.
- */
-#define PTP_V2_MC_UUID_LENGTH 6
-#define PTP_V2_MC_UUID_OFFSET 50
-
#define PTP_V2_SEQUENCE_LENGTH 2
#define PTP_V2_SEQUENCE_OFFSET 58
@@ -167,14 +152,12 @@ enum ptp_packet_state {
/**
* struct efx_ptp_match - Matching structure, stored in sk_buff's cb area.
- * @words: UUID and (partial) sequence number
* @expiry: Time after which the packet should be delivered irrespective of
* event arrival.
* @state: The state of the packet - whether it is ready for processing or
* whether that is of no interest.
*/
struct efx_ptp_match {
- u32 words[DIV_ROUND_UP(PTP_V1_UUID_LENGTH, 4)];
unsigned long expiry;
enum ptp_packet_state state;
};
@@ -236,15 +219,9 @@ struct efx_ptp_rxfilter {
/**
* struct efx_ptp_data - Precision Time Protocol (PTP) state
* @efx: The NIC context
- * @channel: The PTP channel (Siena only)
- * @rx_ts_inline: Flag for whether RX timestamps are inline (else they are
- * separate events)
+ * @channel: The PTP channel (for Medford and Medford2)
* @rxq: Receive SKB queue (awaiting timestamps)
* @txq: Transmit SKB queue
- * @evt_list: List of MC receive events awaiting packets
- * @evt_free_list: List of free events
- * @evt_lock: Lock for manipulating evt_list and evt_free_list
- * @rx_evts: Instantiated events (on evt_list and evt_free_list)
* @workwq: Work queue for processing pending PTP operations
* @work: Work task
* @cleanup_work: Work task for periodic cleanup
@@ -310,13 +287,8 @@ struct efx_ptp_rxfilter {
struct efx_ptp_data {
struct efx_nic *efx;
struct efx_channel *channel;
- bool rx_ts_inline;
struct sk_buff_head rxq;
struct sk_buff_head txq;
- struct list_head evt_list;
- struct list_head evt_free_list;
- spinlock_t evt_lock;
- struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS];
struct workqueue_struct *workwq;
struct work_struct work;
struct delayed_work cleanup_work;
@@ -465,25 +437,6 @@ size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats)
return PTP_STAT_COUNT;
}
-/* For Siena platforms NIC time is s and ns */
-static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor)
-{
- struct timespec64 ts = ns_to_timespec64(ns);
- *nic_major = (u32)ts.tv_sec;
- *nic_minor = ts.tv_nsec;
-}
-
-static ktime_t efx_ptp_s_ns_to_ktime_correction(u32 nic_major, u32 nic_minor,
- s32 correction)
-{
- ktime_t kt = ktime_set(nic_major, nic_minor);
- if (correction >= 0)
- kt = ktime_add_ns(kt, (u64)correction);
- else
- kt = ktime_sub_ns(kt, (u64)-correction);
- return kt;
-}
-
/* To convert from s27 format to ns we multiply then divide by a power of 2.
* For the conversion from ns to s27, the operation is also converted to a
* multiply and shift.
@@ -697,12 +650,6 @@ static int efx_ptp_get_attributes(struct efx_nic *efx)
ptp->nic_time.minor_max = 1 << 27;
ptp->nic_time.sync_event_minor_shift = 19;
break;
- case MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS:
- ptp->ns_to_nic_time = efx_ptp_ns_to_s_ns;
- ptp->nic_to_kernel_time = efx_ptp_s_ns_to_ktime_correction;
- ptp->nic_time.minor_max = 1000000000;
- ptp->nic_time.sync_event_minor_shift = 22;
- break;
case MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_QTR_NANOSECONDS:
ptp->ns_to_nic_time = efx_ptp_ns_to_s_qns;
ptp->nic_to_kernel_time = efx_ptp_s_qns_to_ktime_correction;
@@ -1217,76 +1164,6 @@ fail:
return;
}
-static void efx_ptp_drop_time_expired_events(struct efx_nic *efx)
-{
- struct efx_ptp_data *ptp = efx->ptp_data;
- struct list_head *cursor;
- struct list_head *next;
-
- if (ptp->rx_ts_inline)
- return;
-
- /* Drop time-expired events */
- spin_lock_bh(&ptp->evt_lock);
- list_for_each_safe(cursor, next, &ptp->evt_list) {
- struct efx_ptp_event_rx *evt;
-
- evt = list_entry(cursor, struct efx_ptp_event_rx,
- link);
- if (time_after(jiffies, evt->expiry)) {
- list_move(&evt->link, &ptp->evt_free_list);
- netif_warn(efx, hw, efx->net_dev,
- "PTP rx event dropped\n");
- }
- }
- spin_unlock_bh(&ptp->evt_lock);
-}
-
-static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx,
- struct sk_buff *skb)
-{
- struct efx_ptp_data *ptp = efx->ptp_data;
- bool evts_waiting;
- struct list_head *cursor;
- struct list_head *next;
- struct efx_ptp_match *match;
- enum ptp_packet_state rc = PTP_PACKET_STATE_UNMATCHED;
-
- WARN_ON_ONCE(ptp->rx_ts_inline);
-
- spin_lock_bh(&ptp->evt_lock);
- evts_waiting = !list_empty(&ptp->evt_list);
- spin_unlock_bh(&ptp->evt_lock);
-
- if (!evts_waiting)
- return PTP_PACKET_STATE_UNMATCHED;
-
- match = (struct efx_ptp_match *)skb->cb;
- /* Look for a matching timestamp in the event queue */
- spin_lock_bh(&ptp->evt_lock);
- list_for_each_safe(cursor, next, &ptp->evt_list) {
- struct efx_ptp_event_rx *evt;
-
- evt = list_entry(cursor, struct efx_ptp_event_rx, link);
- if ((evt->seq0 == match->words[0]) &&
- (evt->seq1 == match->words[1])) {
- struct skb_shared_hwtstamps *timestamps;
-
- /* Match - add in hardware timestamp */
- timestamps = skb_hwtstamps(skb);
- timestamps->hwtstamp = evt->hwtimestamp;
-
- match->state = PTP_PACKET_STATE_MATCHED;
- rc = PTP_PACKET_STATE_MATCHED;
- list_move(&evt->link, &ptp->evt_free_list);
- break;
- }
- }
- spin_unlock_bh(&ptp->evt_lock);
-
- return rc;
-}
-
/* Process any queued receive events and corresponding packets
*
* q is returned with all the packets that are ready for delivery.
@@ -1302,9 +1179,6 @@ static void efx_ptp_process_events(struct efx_nic *efx, struct sk_buff_head *q)
match = (struct efx_ptp_match *)skb->cb;
if (match->state == PTP_PACKET_STATE_MATCH_UNWANTED) {
__skb_queue_tail(q, skb);
- } else if (efx_ptp_match_rx(efx, skb) ==
- PTP_PACKET_STATE_MATCHED) {
- __skb_queue_tail(q, skb);
} else if (time_after(jiffies, match->expiry)) {
match->state = PTP_PACKET_STATE_TIMED_OUT;
++ptp->rx_no_timestamp;
@@ -1485,7 +1359,9 @@ static int efx_ptp_insert_multicast_filters(struct efx_nic *efx)
goto fail;
rc = efx_ptp_insert_eth_multicast_filter(efx);
- if (rc < 0)
+
+ /* Not all firmware variants support this filter */
+ if (rc < 0 && rc != -EPROTONOSUPPORT)
goto fail;
}
@@ -1581,8 +1457,6 @@ fail:
static int efx_ptp_stop(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
- struct list_head *cursor;
- struct list_head *next;
int rc;
if (ptp == NULL)
@@ -1597,13 +1471,6 @@ static int efx_ptp_stop(struct efx_nic *efx)
efx_ptp_deliver_rx_queue(&efx->ptp_data->rxq);
skb_queue_purge(&efx->ptp_data->txq);
- /* Drop any pending receive events */
- spin_lock_bh(&efx->ptp_data->evt_lock);
- list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) {
- list_move(cursor, &efx->ptp_data->evt_free_list);
- }
- spin_unlock_bh(&efx->ptp_data->evt_lock);
-
return rc;
}
@@ -1643,8 +1510,6 @@ static void efx_ptp_worker(struct work_struct *work)
return;
}
- efx_ptp_drop_time_expired_events(efx);
-
__skb_queue_head_init(&tempq);
efx_ptp_process_events(efx, &tempq);
@@ -1693,7 +1558,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
{
struct efx_ptp_data *ptp;
int rc = 0;
- unsigned int pos;
if (efx->ptp_data) {
efx->ptp_data->channel = channel;
@@ -1707,7 +1571,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
ptp->efx = efx;
ptp->channel = channel;
- ptp->rx_ts_inline = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int), GFP_KERNEL);
if (rc != 0)
@@ -1734,12 +1597,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
ptp->config.flags = 0;
ptp->config.tx_type = HWTSTAMP_TX_OFF;
ptp->config.rx_filter = HWTSTAMP_FILTER_NONE;
- INIT_LIST_HEAD(&ptp->evt_list);
- INIT_LIST_HEAD(&ptp->evt_free_list);
- spin_lock_init(&ptp->evt_lock);
- for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++)
- list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list);
-
INIT_LIST_HEAD(&ptp->rxfilters_mcast);
INIT_LIST_HEAD(&ptp->rxfilters_ucast);
@@ -1879,7 +1736,6 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
struct efx_nic *efx = channel->efx;
struct efx_ptp_data *ptp = efx->ptp_data;
struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb;
- u8 *match_data_012, *match_data_345;
unsigned int version;
u8 *data;
@@ -1895,12 +1751,6 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
if (version != PTP_VERSION_V1) {
return false;
}
-
- /* PTP V1 uses all six bytes of the UUID to match the packet
- * to the timestamp
- */
- match_data_012 = data + PTP_V1_UUID_OFFSET;
- match_data_345 = data + PTP_V1_UUID_OFFSET + 3;
} else {
if (!pskb_may_pull(skb, PTP_V2_MIN_LENGTH)) {
return false;
@@ -1910,21 +1760,6 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) {
return false;
}
-
- /* The original V2 implementation uses bytes 2-7 of
- * the UUID to match the packet to the timestamp. This
- * discards two of the bytes of the MAC address used
- * to create the UUID (SF bug 33070). The PTP V2
- * enhanced mode fixes this issue and uses bytes 0-2
- * and byte 5-7 of the UUID.
- */
- match_data_345 = data + PTP_V2_UUID_OFFSET + 5;
- if (ptp->mode == MC_CMD_PTP_MODE_V2) {
- match_data_012 = data + PTP_V2_UUID_OFFSET + 2;
- } else {
- match_data_012 = data + PTP_V2_UUID_OFFSET + 0;
- BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED);
- }
}
/* Does this packet require timestamping? */
@@ -1936,17 +1771,6 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
*/
BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET);
BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH);
-
- /* Extract UUID/Sequence information */
- match->words[0] = (match_data_012[0] |
- (match_data_012[1] << 8) |
- (match_data_012[2] << 16) |
- (match_data_345[0] << 24));
- match->words[1] = (match_data_345[1] |
- (match_data_345[2] << 8) |
- (data[PTP_V1_SEQUENCE_OFFSET +
- PTP_V1_SEQUENCE_LENGTH - 1] <<
- 16));
} else {
match->state = PTP_PACKET_STATE_MATCH_UNWANTED;
}
@@ -2110,50 +1934,6 @@ static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len)
queue_work(ptp->workwq, &ptp->work);
}
-/* Process a completed receive event. Put it on the event queue and
- * start worker thread. This is required because event and their
- * correspoding packets may come in either order.
- */
-static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp)
-{
- struct efx_ptp_event_rx *evt = NULL;
-
- if (WARN_ON_ONCE(ptp->rx_ts_inline))
- return;
-
- if (ptp->evt_frag_idx != 3) {
- ptp_event_failure(efx, 3);
- return;
- }
-
- spin_lock_bh(&ptp->evt_lock);
- if (!list_empty(&ptp->evt_free_list)) {
- evt = list_first_entry(&ptp->evt_free_list,
- struct efx_ptp_event_rx, link);
- list_del(&evt->link);
-
- evt->seq0 = EFX_QWORD_FIELD(ptp->evt_frags[2], MCDI_EVENT_DATA);
- evt->seq1 = (EFX_QWORD_FIELD(ptp->evt_frags[2],
- MCDI_EVENT_SRC) |
- (EFX_QWORD_FIELD(ptp->evt_frags[1],
- MCDI_EVENT_SRC) << 8) |
- (EFX_QWORD_FIELD(ptp->evt_frags[0],
- MCDI_EVENT_SRC) << 16));
- evt->hwtimestamp = efx->ptp_data->nic_to_kernel_time(
- EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA),
- EFX_QWORD_FIELD(ptp->evt_frags[1], MCDI_EVENT_DATA),
- ptp->ts_corrections.ptp_rx);
- evt->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS);
- list_add_tail(&evt->link, &ptp->evt_list);
-
- queue_work(ptp->workwq, &ptp->work);
- } else if (net_ratelimit()) {
- /* Log a rate-limited warning message. */
- netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n");
- }
- spin_unlock_bh(&ptp->evt_lock);
-}
-
static void ptp_event_fault(struct efx_nic *efx, struct efx_ptp_data *ptp)
{
int code = EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA);
@@ -2200,9 +1980,6 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
if (!MCDI_EVENT_FIELD(*ev, CONT)) {
/* Process resulting event */
switch (code) {
- case MCDI_EVENT_CODE_PTP_RX:
- ptp_event_rx(efx, ptp);
- break;
case MCDI_EVENT_CODE_PTP_FAULT:
ptp_event_fault(efx, ptp);
break;
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c
index 19a0b8584afb..894fad0bb5ea 100644
--- a/drivers/net/ethernet/sfc/selftest.c
+++ b/drivers/net/ethernet/sfc/selftest.c
@@ -38,8 +38,7 @@
/*
* Loopback test packet structure
*
- * The self-test should stress every RSS vector, and unfortunately
- * Falcon only performs RSS on TCP/UDP packets.
+ * The self-test should stress every RSS vector.
*/
struct efx_loopback_payload {
char pad[2]; /* Ensures ip is 4-byte aligned */
@@ -426,7 +425,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
for (i = 0; i < state->packet_count; i++) {
/* Allocate an skb, holding an extra reference for
* transmit completion counting */
- skb = alloc_skb(EFX_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL);
+ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
if (!skb)
return -ENOMEM;
state->skbs[i] = skb;
@@ -584,10 +583,6 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
return 0;
}
-/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but
- * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it
- * to delay and retry. Therefore, it's safer to just poll directly. Wait
- * for link up and any faults to dissipate. */
static int efx_wait_for_link(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
diff --git a/drivers/net/ethernet/sfc/siena/io.h b/drivers/net/ethernet/sfc/siena/io.h
index 30439cc83a89..07f99ad14bf3 100644
--- a/drivers/net/ethernet/sfc/siena/io.h
+++ b/drivers/net/ethernet/sfc/siena/io.h
@@ -70,7 +70,7 @@
*/
#ifdef CONFIG_X86_64
/* PIO is a win only if write-combining is possible */
-#ifdef ARCH_HAS_IOREMAP_WC
+#ifdef ioremap_wc
#define EFX_USE_PIO 1
#endif
#endif
diff --git a/drivers/net/ethernet/sfc/siena/selftest.c b/drivers/net/ethernet/sfc/siena/selftest.c
index b55fd3346972..526da43d4b61 100644
--- a/drivers/net/ethernet/sfc/siena/selftest.c
+++ b/drivers/net/ethernet/sfc/siena/selftest.c
@@ -426,7 +426,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
for (i = 0; i < state->packet_count; i++) {
/* Allocate an skb, holding an extra reference for
* transmit completion counting */
- skb = alloc_skb(EFX_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL);
+ skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
if (!skb)
return -ENOMEM;
state->skbs[i] = skb;
diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c
index fe268b6c1cac..047322b04d4f 100644
--- a/drivers/net/ethernet/sfc/tc.c
+++ b/drivers/net/ethernet/sfc/tc.c
@@ -12,9 +12,11 @@
#include <net/pkt_cls.h>
#include <net/vxlan.h>
#include <net/geneve.h>
+#include <net/tc_act/tc_ct.h>
#include "tc.h"
#include "tc_bindings.h"
#include "tc_encap_actions.h"
+#include "tc_conntrack.h"
#include "mae.h"
#include "ef100_rep.h"
#include "efx.h"
@@ -29,6 +31,9 @@ enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev)
return EFX_ENCAP_TYPE_NONE;
}
+#define EFX_TC_HDR_TYPE_TTL_MASK ((u32)0xff)
+/* Hoplimit is stored in the most significant byte in the pedit ipv6 header action */
+#define EFX_TC_HDR_TYPE_HLIMIT_MASK ~((u32)0xff000000)
#define EFX_EFV_PF NULL
/* Look up the representor information (efv) for a device.
* May return NULL for the PF (us), or an error pointer for a device that
@@ -84,6 +89,12 @@ s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv)
return mport;
}
+static const struct rhashtable_params efx_tc_mac_ht_params = {
+ .key_len = offsetofend(struct efx_tc_mac_pedit_action, h_addr),
+ .key_offset = 0,
+ .head_offset = offsetof(struct efx_tc_mac_pedit_action, linkage),
+};
+
static const struct rhashtable_params efx_tc_encap_match_ht_params = {
.key_len = offsetof(struct efx_tc_encap_match, linkage),
.key_offset = 0,
@@ -96,6 +107,68 @@ static const struct rhashtable_params efx_tc_match_action_ht_params = {
.head_offset = offsetof(struct efx_tc_flow_rule, linkage),
};
+static const struct rhashtable_params efx_tc_lhs_rule_ht_params = {
+ .key_len = sizeof(unsigned long),
+ .key_offset = offsetof(struct efx_tc_lhs_rule, cookie),
+ .head_offset = offsetof(struct efx_tc_lhs_rule, linkage),
+};
+
+static const struct rhashtable_params efx_tc_recirc_ht_params = {
+ .key_len = offsetof(struct efx_tc_recirc_id, linkage),
+ .key_offset = 0,
+ .head_offset = offsetof(struct efx_tc_recirc_id, linkage),
+};
+
+static struct efx_tc_mac_pedit_action *efx_tc_flower_get_mac(struct efx_nic *efx,
+ unsigned char h_addr[ETH_ALEN],
+ struct netlink_ext_ack *extack)
+{
+ struct efx_tc_mac_pedit_action *ped, *old;
+ int rc;
+
+ ped = kzalloc(sizeof(*ped), GFP_USER);
+ if (!ped)
+ return ERR_PTR(-ENOMEM);
+ memcpy(ped->h_addr, h_addr, ETH_ALEN);
+ old = rhashtable_lookup_get_insert_fast(&efx->tc->mac_ht,
+ &ped->linkage,
+ efx_tc_mac_ht_params);
+ if (old) {
+ /* don't need our new entry */
+ kfree(ped);
+ if (!refcount_inc_not_zero(&old->ref))
+ return ERR_PTR(-EAGAIN);
+ /* existing entry found, ref taken */
+ return old;
+ }
+
+ rc = efx_mae_allocate_pedit_mac(efx, ped);
+ if (rc < 0) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to store pedit MAC address in hw");
+ goto out_remove;
+ }
+
+ /* ref and return */
+ refcount_set(&ped->ref, 1);
+ return ped;
+out_remove:
+ rhashtable_remove_fast(&efx->tc->mac_ht, &ped->linkage,
+ efx_tc_mac_ht_params);
+ kfree(ped);
+ return ERR_PTR(rc);
+}
+
+static void efx_tc_flower_put_mac(struct efx_nic *efx,
+ struct efx_tc_mac_pedit_action *ped)
+{
+ if (!refcount_dec_and_test(&ped->ref))
+ return; /* still in use */
+ rhashtable_remove_fast(&efx->tc->mac_ht, &ped->linkage,
+ efx_tc_mac_ht_params);
+ efx_mae_free_pedit_mac(efx, ped);
+ kfree(ped);
+}
+
static void efx_tc_free_action_set(struct efx_nic *efx,
struct efx_tc_action_set *act, bool in_hw)
{
@@ -121,6 +194,10 @@ static void efx_tc_free_action_set(struct efx_nic *efx,
list_del(&act->encap_user);
efx_tc_flower_release_encap_md(efx, act->encap_md);
}
+ if (act->src_mac)
+ efx_tc_flower_put_mac(efx, act->src_mac);
+ if (act->dst_mac)
+ efx_tc_flower_put_mac(efx, act->dst_mac);
kfree(act);
}
@@ -201,23 +278,24 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
}
}
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_VLAN) |
- BIT(FLOW_DISSECTOR_KEY_CVLAN) |
- BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_TCP) |
- BIT(FLOW_DISSECTOR_KEY_IP))) {
- NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#x",
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CT) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP))) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported flower keys %#llx",
dissector->used_keys);
return -EOPNOTSUPP;
}
@@ -228,12 +306,13 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
!(match->value.eth_proto == htons(ETH_P_IP) ||
match->value.eth_proto == htons(ETH_P_IPV6)))
if (dissector->used_keys &
- (BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_IP) |
- BIT(FLOW_DISSECTOR_KEY_TCP))) {
- NL_SET_ERR_MSG_FMT_MOD(extack, "L3/L4 flower keys %#x require protocol ipv[46]",
+ (BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP))) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "L3/L4 flower keys %#llx require protocol ipv[46]",
dissector->used_keys);
return -EINVAL;
}
@@ -281,9 +360,10 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
if ((match->value.ip_proto != IPPROTO_UDP &&
match->value.ip_proto != IPPROTO_TCP) || !IS_ALL_ONES(match->mask.ip_proto))
if (dissector->used_keys &
- (BIT(FLOW_DISSECTOR_KEY_PORTS) |
- BIT(FLOW_DISSECTOR_KEY_TCP))) {
- NL_SET_ERR_MSG_FMT_MOD(extack, "L4 flower keys %#x require ipproto udp or tcp",
+ (BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP))) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "L4 flower keys %#llx require ipproto udp or tcp",
dissector->used_keys);
return -EINVAL;
}
@@ -344,15 +424,41 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx,
MAP_ENC_KEY_AND_MASK(PORTS, ports, enc_ports, dst, enc_dport);
MAP_ENC_KEY_AND_MASK(KEYID, enc_keyid, enc_keyid, keyid, enc_keyid);
} else if (dissector->used_keys &
- (BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
- BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
- BIT(FLOW_DISSECTOR_KEY_ENC_PORTS))) {
- NL_SET_ERR_MSG_FMT_MOD(extack, "Flower enc keys require enc_control (keys: %#x)",
+ (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_PORTS))) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Flower enc keys require enc_control (keys: %#llx)",
dissector->used_keys);
return -EOPNOTSUPP;
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CT)) {
+ struct flow_match_ct fm;
+
+ flow_rule_match_ct(rule, &fm);
+ match->value.ct_state_trk = !!(fm.key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED);
+ match->mask.ct_state_trk = !!(fm.mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED);
+ match->value.ct_state_est = !!(fm.key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED);
+ match->mask.ct_state_est = !!(fm.mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED);
+ if (fm.mask->ct_state & ~(TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
+ TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported ct_state match %#x",
+ fm.mask->ct_state);
+ return -EOPNOTSUPP;
+ }
+ match->value.ct_mark = fm.key->ct_mark;
+ match->mask.ct_mark = fm.mask->ct_mark;
+ match->value.ct_zone = fm.key->ct_zone;
+ match->mask.ct_zone = fm.mask->ct_zone;
+
+ if (memchr_inv(fm.mask->ct_labels, 0, sizeof(fm.mask->ct_labels))) {
+ NL_SET_ERR_MSG_MOD(extack, "Matching on ct_label not supported");
+ return -EOPNOTSUPP;
+ }
+ }
return 0;
}
@@ -572,12 +678,65 @@ fail_pseudo:
return rc;
}
+static struct efx_tc_recirc_id *efx_tc_get_recirc_id(struct efx_nic *efx,
+ u32 chain_index,
+ struct net_device *net_dev)
+{
+ struct efx_tc_recirc_id *rid, *old;
+ int rc;
+
+ rid = kzalloc(sizeof(*rid), GFP_USER);
+ if (!rid)
+ return ERR_PTR(-ENOMEM);
+ rid->chain_index = chain_index;
+ /* We don't take a reference here, because it's implied - if there's
+ * a rule on the net_dev that's been offloaded to us, then the net_dev
+ * can't go away until the rule has been deoffloaded.
+ */
+ rid->net_dev = net_dev;
+ old = rhashtable_lookup_get_insert_fast(&efx->tc->recirc_ht,
+ &rid->linkage,
+ efx_tc_recirc_ht_params);
+ if (old) {
+ /* don't need our new entry */
+ kfree(rid);
+ if (!refcount_inc_not_zero(&old->ref))
+ return ERR_PTR(-EAGAIN);
+ /* existing entry found */
+ rid = old;
+ } else {
+ rc = ida_alloc_range(&efx->tc->recirc_ida, 1, U8_MAX, GFP_USER);
+ if (rc < 0) {
+ rhashtable_remove_fast(&efx->tc->recirc_ht,
+ &rid->linkage,
+ efx_tc_recirc_ht_params);
+ kfree(rid);
+ return ERR_PTR(rc);
+ }
+ rid->fw_id = rc;
+ refcount_set(&rid->ref, 1);
+ }
+ return rid;
+}
+
+static void efx_tc_put_recirc_id(struct efx_nic *efx, struct efx_tc_recirc_id *rid)
+{
+ if (!refcount_dec_and_test(&rid->ref))
+ return; /* still in use */
+ rhashtable_remove_fast(&efx->tc->recirc_ht, &rid->linkage,
+ efx_tc_recirc_ht_params);
+ ida_free(&efx->tc->recirc_ida, rid->fw_id);
+ kfree(rid);
+}
+
static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule)
{
efx_mae_delete_rule(efx, rule->fw_id);
/* Release entries in subsidiary tables */
efx_tc_free_action_set_list(efx, &rule->acts, true);
+ if (rule->match.rid)
+ efx_tc_put_recirc_id(efx, rule->match.rid);
if (rule->match.encap)
efx_tc_flower_release_encap_match(efx, rule->match.encap);
rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
@@ -601,6 +760,8 @@ static const char *efx_tc_encap_type_name(enum efx_encap_type typ)
/* For details of action order constraints refer to SF-123102-TC-1§12.6.1 */
enum efx_tc_action_order {
EFX_TC_AO_DECAP,
+ EFX_TC_AO_DEC_TTL,
+ EFX_TC_AO_PEDIT_MAC_ADDRS,
EFX_TC_AO_VLAN_POP,
EFX_TC_AO_VLAN_PUSH,
EFX_TC_AO_COUNT,
@@ -615,6 +776,15 @@ static bool efx_tc_flower_action_order_ok(const struct efx_tc_action_set *act,
case EFX_TC_AO_DECAP:
if (act->decap)
return false;
+ /* PEDIT_MAC_ADDRS must not happen before DECAP, though it
+ * can wait until much later
+ */
+ if (act->dst_mac || act->src_mac)
+ return false;
+
+ /* Decrementing ttl must not happen before DECAP */
+ if (act->do_ttl_dec)
+ return false;
fallthrough;
case EFX_TC_AO_VLAN_POP:
if (act->vlan_pop >= 2)
@@ -634,12 +804,17 @@ static bool efx_tc_flower_action_order_ok(const struct efx_tc_action_set *act,
if (act->count)
return false;
fallthrough;
+ case EFX_TC_AO_PEDIT_MAC_ADDRS:
case EFX_TC_AO_ENCAP:
if (act->encap_md)
return false;
fallthrough;
case EFX_TC_AO_DELIVER:
return !act->deliver;
+ case EFX_TC_AO_DEC_TTL:
+ if (act->encap_md)
+ return false;
+ return !act->do_ttl_dec;
default:
/* Bad caller. Whatever they wanted to do, say they can't. */
WARN_ON_ONCE(1);
@@ -647,6 +822,532 @@ static bool efx_tc_flower_action_order_ok(const struct efx_tc_action_set *act,
}
}
+/**
+ * DOC: TC conntrack sequences
+ *
+ * The MAE hardware can handle at most two rounds of action rule matching,
+ * consequently we support conntrack through the notion of a "left-hand side
+ * rule". This is a rule which typically contains only the actions "ct" and
+ * "goto chain N", and corresponds to one or more "right-hand side rules" in
+ * chain N, which typically match on +trk+est, and may perform ct(nat) actions.
+ * RHS rules go in the Action Rule table as normal but with a nonzero recirc_id
+ * (the hardware equivalent of chain_index), while LHS rules may go in either
+ * the Action Rule or the Outer Rule table, the latter being preferred for
+ * performance reasons, and set both DO_CT and a recirc_id in their response.
+ *
+ * Besides the RHS rules, there are often also similar rules matching on
+ * +trk+new which perform the ct(commit) action. These are not offloaded.
+ */
+
+static bool efx_tc_rule_is_lhs_rule(struct flow_rule *fr,
+ struct efx_tc_match *match)
+{
+ const struct flow_action_entry *fa;
+ int i;
+
+ flow_action_for_each(i, fa, &fr->action) {
+ switch (fa->id) {
+ case FLOW_ACTION_GOTO:
+ return true;
+ case FLOW_ACTION_CT:
+ /* If rule is -trk, or doesn't mention trk at all, then
+ * a CT action implies a conntrack lookup (hence it's an
+ * LHS rule). If rule is +trk, then a CT action could
+ * just be ct(nat) or even ct(commit) (though the latter
+ * can't be offloaded).
+ */
+ if (!match->mask.ct_state_trk || !match->value.ct_state_trk)
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+static int efx_tc_flower_handle_lhs_actions(struct efx_nic *efx,
+ struct flow_cls_offload *tc,
+ struct flow_rule *fr,
+ struct net_device *net_dev,
+ struct efx_tc_lhs_rule *rule)
+
+{
+ struct netlink_ext_ack *extack = tc->common.extack;
+ struct efx_tc_lhs_action *act = &rule->lhs_act;
+ const struct flow_action_entry *fa;
+ bool pipe = true;
+ int i;
+
+ flow_action_for_each(i, fa, &fr->action) {
+ struct efx_tc_ct_zone *ct_zone;
+ struct efx_tc_recirc_id *rid;
+
+ if (!pipe) {
+ /* more actions after a non-pipe action */
+ NL_SET_ERR_MSG_MOD(extack, "Action follows non-pipe action");
+ return -EINVAL;
+ }
+ switch (fa->id) {
+ case FLOW_ACTION_GOTO:
+ if (!fa->chain_index) {
+ NL_SET_ERR_MSG_MOD(extack, "Can't goto chain 0, no looping in hw");
+ return -EOPNOTSUPP;
+ }
+ rid = efx_tc_get_recirc_id(efx, fa->chain_index,
+ net_dev);
+ if (IS_ERR(rid)) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to allocate a hardware recirculation ID for this chain_index");
+ return PTR_ERR(rid);
+ }
+ act->rid = rid;
+ if (fa->hw_stats) {
+ struct efx_tc_counter_index *cnt;
+
+ if (!(fa->hw_stats & FLOW_ACTION_HW_STATS_DELAYED)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "hw_stats_type %u not supported (only 'delayed')",
+ fa->hw_stats);
+ return -EOPNOTSUPP;
+ }
+ cnt = efx_tc_flower_get_counter_index(efx, tc->cookie,
+ EFX_TC_COUNTER_TYPE_OR);
+ if (IS_ERR(cnt)) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to obtain a counter");
+ return PTR_ERR(cnt);
+ }
+ WARN_ON(act->count); /* can't happen */
+ act->count = cnt;
+ }
+ pipe = false;
+ break;
+ case FLOW_ACTION_CT:
+ if (act->zone) {
+ NL_SET_ERR_MSG_MOD(extack, "Can't offload multiple ct actions");
+ return -EOPNOTSUPP;
+ }
+ if (fa->ct.action & (TCA_CT_ACT_COMMIT |
+ TCA_CT_ACT_FORCE)) {
+ NL_SET_ERR_MSG_MOD(extack, "Can't offload ct commit/force");
+ return -EOPNOTSUPP;
+ }
+ if (fa->ct.action & TCA_CT_ACT_CLEAR) {
+ NL_SET_ERR_MSG_MOD(extack, "Can't clear ct in LHS rule");
+ return -EOPNOTSUPP;
+ }
+ if (fa->ct.action & (TCA_CT_ACT_NAT |
+ TCA_CT_ACT_NAT_SRC |
+ TCA_CT_ACT_NAT_DST)) {
+ NL_SET_ERR_MSG_MOD(extack, "Can't perform NAT in LHS rule - packet isn't conntracked yet");
+ return -EOPNOTSUPP;
+ }
+ if (fa->ct.action) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled ct.action %u for LHS rule\n",
+ fa->ct.action);
+ return -EOPNOTSUPP;
+ }
+ ct_zone = efx_tc_ct_register_zone(efx, fa->ct.zone,
+ fa->ct.flow_table);
+ if (IS_ERR(ct_zone)) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to register for CT updates");
+ return PTR_ERR(ct_zone);
+ }
+ act->zone = ct_zone;
+ break;
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled action %u for LHS rule\n",
+ fa->id);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (pipe) {
+ NL_SET_ERR_MSG_MOD(extack, "Missing goto chain in LHS rule");
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static void efx_tc_flower_release_lhs_actions(struct efx_nic *efx,
+ struct efx_tc_lhs_action *act)
+{
+ if (act->rid)
+ efx_tc_put_recirc_id(efx, act->rid);
+ if (act->zone)
+ efx_tc_ct_unregister_zone(efx, act->zone);
+ if (act->count)
+ efx_tc_flower_put_counter_index(efx, act->count);
+}
+
+/**
+ * struct efx_tc_mangler_state - accumulates 32-bit pedits into fields
+ *
+ * @dst_mac_32: dst_mac[0:3] has been populated
+ * @dst_mac_16: dst_mac[4:5] has been populated
+ * @src_mac_16: src_mac[0:1] has been populated
+ * @src_mac_32: src_mac[2:5] has been populated
+ * @dst_mac: h_dest field of ethhdr
+ * @src_mac: h_source field of ethhdr
+ *
+ * Since FLOW_ACTION_MANGLE comes in 32-bit chunks that do not
+ * necessarily equate to whole fields of the packet header, this
+ * structure is used to hold the cumulative effect of the partial
+ * field pedits that have been processed so far.
+ */
+struct efx_tc_mangler_state {
+ u8 dst_mac_32:1; /* eth->h_dest[0:3] */
+ u8 dst_mac_16:1; /* eth->h_dest[4:5] */
+ u8 src_mac_16:1; /* eth->h_source[0:1] */
+ u8 src_mac_32:1; /* eth->h_source[2:5] */
+ unsigned char dst_mac[ETH_ALEN];
+ unsigned char src_mac[ETH_ALEN];
+};
+
+/** efx_tc_complete_mac_mangle() - pull complete field pedits out of @mung
+ * @efx: NIC we're installing a flow rule on
+ * @act: action set (cursor) to update
+ * @mung: accumulated partial mangles
+ * @extack: netlink extended ack for reporting errors
+ *
+ * Check @mung to find any combinations of partial mangles that can be
+ * combined into a complete packet field edit, add that edit to @act,
+ * and consume the partial mangles from @mung.
+ */
+
+static int efx_tc_complete_mac_mangle(struct efx_nic *efx,
+ struct efx_tc_action_set *act,
+ struct efx_tc_mangler_state *mung,
+ struct netlink_ext_ack *extack)
+{
+ struct efx_tc_mac_pedit_action *ped;
+
+ if (mung->dst_mac_32 && mung->dst_mac_16) {
+ ped = efx_tc_flower_get_mac(efx, mung->dst_mac, extack);
+ if (IS_ERR(ped))
+ return PTR_ERR(ped);
+
+ /* Check that we have not already populated dst_mac */
+ if (act->dst_mac)
+ efx_tc_flower_put_mac(efx, act->dst_mac);
+
+ act->dst_mac = ped;
+
+ /* consume the incomplete state */
+ mung->dst_mac_32 = 0;
+ mung->dst_mac_16 = 0;
+ }
+ if (mung->src_mac_16 && mung->src_mac_32) {
+ ped = efx_tc_flower_get_mac(efx, mung->src_mac, extack);
+ if (IS_ERR(ped))
+ return PTR_ERR(ped);
+
+ /* Check that we have not already populated src_mac */
+ if (act->src_mac)
+ efx_tc_flower_put_mac(efx, act->src_mac);
+
+ act->src_mac = ped;
+
+ /* consume the incomplete state */
+ mung->src_mac_32 = 0;
+ mung->src_mac_16 = 0;
+ }
+ return 0;
+}
+
+static int efx_tc_pedit_add(struct efx_nic *efx, struct efx_tc_action_set *act,
+ const struct flow_action_entry *fa,
+ struct netlink_ext_ack *extack)
+{
+ switch (fa->mangle.htype) {
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
+ switch (fa->mangle.offset) {
+ case offsetof(struct iphdr, ttl):
+ /* check that pedit applies to ttl only */
+ if (fa->mangle.mask != ~EFX_TC_HDR_TYPE_TTL_MASK)
+ break;
+
+ /* Adding 0xff is equivalent to decrementing the ttl.
+ * Other added values are not supported.
+ */
+ if ((fa->mangle.val & EFX_TC_HDR_TYPE_TTL_MASK) != U8_MAX)
+ break;
+
+ /* check that we do not decrement ttl twice */
+ if (!efx_tc_flower_action_order_ok(act,
+ EFX_TC_AO_DEC_TTL)) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported: multiple dec ttl");
+ return -EOPNOTSUPP;
+ }
+ act->do_ttl_dec = 1;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
+ switch (fa->mangle.offset) {
+ case round_down(offsetof(struct ipv6hdr, hop_limit), 4):
+ /* check that pedit applies to hoplimit only */
+ if (fa->mangle.mask != EFX_TC_HDR_TYPE_HLIMIT_MASK)
+ break;
+
+ /* Adding 0xff is equivalent to decrementing the hoplimit.
+ * Other added values are not supported.
+ */
+ if ((fa->mangle.val >> 24) != U8_MAX)
+ break;
+
+ /* check that we do not decrement hoplimit twice */
+ if (!efx_tc_flower_action_order_ok(act,
+ EFX_TC_AO_DEC_TTL)) {
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported: multiple dec ttl");
+ return -EOPNOTSUPP;
+ }
+ act->do_ttl_dec = 1;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: ttl add action type %x %x %x/%x",
+ fa->mangle.htype, fa->mangle.offset,
+ fa->mangle.val, fa->mangle.mask);
+ return -EOPNOTSUPP;
+}
+
+/**
+ * efx_tc_mangle() - handle a single 32-bit (or less) pedit
+ * @efx: NIC we're installing a flow rule on
+ * @act: action set (cursor) to update
+ * @fa: FLOW_ACTION_MANGLE action metadata
+ * @mung: accumulator for partial mangles
+ * @extack: netlink extended ack for reporting errors
+ * @match: original match used along with the mangle action
+ *
+ * Identify the fields written by a FLOW_ACTION_MANGLE, and record
+ * the partial mangle state in @mung. If this mangle completes an
+ * earlier partial mangle, consume and apply to @act by calling
+ * efx_tc_complete_mac_mangle().
+ */
+
+static int efx_tc_mangle(struct efx_nic *efx, struct efx_tc_action_set *act,
+ const struct flow_action_entry *fa,
+ struct efx_tc_mangler_state *mung,
+ struct netlink_ext_ack *extack,
+ struct efx_tc_match *match)
+{
+ __le32 mac32;
+ __le16 mac16;
+ u8 tr_ttl;
+
+ switch (fa->mangle.htype) {
+ case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
+ BUILD_BUG_ON(offsetof(struct ethhdr, h_dest) != 0);
+ BUILD_BUG_ON(offsetof(struct ethhdr, h_source) != 6);
+ if (!efx_tc_flower_action_order_ok(act, EFX_TC_AO_PEDIT_MAC_ADDRS)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Pedit mangle mac action violates action order");
+ return -EOPNOTSUPP;
+ }
+ switch (fa->mangle.offset) {
+ case 0:
+ if (fa->mangle.mask) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: mask (%#x) of eth.dst32 mangle",
+ fa->mangle.mask);
+ return -EOPNOTSUPP;
+ }
+ /* Ethernet address is little-endian */
+ mac32 = cpu_to_le32(fa->mangle.val);
+ memcpy(mung->dst_mac, &mac32, sizeof(mac32));
+ mung->dst_mac_32 = 1;
+ return efx_tc_complete_mac_mangle(efx, act, mung, extack);
+ case 4:
+ if (fa->mangle.mask == 0xffff) {
+ mac16 = cpu_to_le16(fa->mangle.val >> 16);
+ memcpy(mung->src_mac, &mac16, sizeof(mac16));
+ mung->src_mac_16 = 1;
+ } else if (fa->mangle.mask == 0xffff0000) {
+ mac16 = cpu_to_le16((u16)fa->mangle.val);
+ memcpy(mung->dst_mac + 4, &mac16, sizeof(mac16));
+ mung->dst_mac_16 = 1;
+ } else {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: mask (%#x) of eth+4 mangle is not high or low 16b",
+ fa->mangle.mask);
+ return -EOPNOTSUPP;
+ }
+ return efx_tc_complete_mac_mangle(efx, act, mung, extack);
+ case 8:
+ if (fa->mangle.mask) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: mask (%#x) of eth.src32 mangle",
+ fa->mangle.mask);
+ return -EOPNOTSUPP;
+ }
+ mac32 = cpu_to_le32(fa->mangle.val);
+ memcpy(mung->src_mac + 2, &mac32, sizeof(mac32));
+ mung->src_mac_32 = 1;
+ return efx_tc_complete_mac_mangle(efx, act, mung, extack);
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported: mangle eth+%u %x/%x",
+ fa->mangle.offset, fa->mangle.val, fa->mangle.mask);
+ return -EOPNOTSUPP;
+ }
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
+ switch (fa->mangle.offset) {
+ case offsetof(struct iphdr, ttl):
+ /* we currently only support pedit IP4 when it applies
+ * to TTL and then only when it can be achieved with a
+ * decrement ttl action
+ */
+
+ /* check that pedit applies to ttl only */
+ if (fa->mangle.mask != ~EFX_TC_HDR_TYPE_TTL_MASK) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: mask (%#x) out of range, only support mangle action on ipv4.ttl",
+ fa->mangle.mask);
+ return -EOPNOTSUPP;
+ }
+
+ /* we can only convert to a dec ttl when we have an
+ * exact match on the ttl field
+ */
+ if (match->mask.ip_ttl != U8_MAX) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: only support mangle ipv4.ttl when we have an exact match on ttl, mask used for match (%#x)",
+ match->mask.ip_ttl);
+ return -EOPNOTSUPP;
+ }
+
+ /* check that we don't try to decrement 0, which equates
+ * to setting the ttl to 0xff
+ */
+ if (match->value.ip_ttl == 0) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Unsupported: we cannot decrement ttl past 0");
+ return -EOPNOTSUPP;
+ }
+
+ /* check that we do not decrement ttl twice */
+ if (!efx_tc_flower_action_order_ok(act,
+ EFX_TC_AO_DEC_TTL)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Unsupported: multiple dec ttl");
+ return -EOPNOTSUPP;
+ }
+
+ /* check pedit can be achieved with decrement action */
+ tr_ttl = match->value.ip_ttl - 1;
+ if ((fa->mangle.val & EFX_TC_HDR_TYPE_TTL_MASK) == tr_ttl) {
+ act->do_ttl_dec = 1;
+ return 0;
+ }
+
+ fallthrough;
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: only support mangle on the ttl field (offset is %u)",
+ fa->mangle.offset);
+ return -EOPNOTSUPP;
+ }
+ break;
+ case FLOW_ACT_MANGLE_HDR_TYPE_IP6:
+ switch (fa->mangle.offset) {
+ case round_down(offsetof(struct ipv6hdr, hop_limit), 4):
+ /* we currently only support pedit IP6 when it applies
+ * to the hoplimit and then only when it can be achieved
+ * with a decrement hoplimit action
+ */
+
+ /* check that pedit applies to ttl only */
+ if (fa->mangle.mask != EFX_TC_HDR_TYPE_HLIMIT_MASK) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: mask (%#x) out of range, only support mangle action on ipv6.hop_limit",
+ fa->mangle.mask);
+
+ return -EOPNOTSUPP;
+ }
+
+ /* we can only convert to a dec ttl when we have an
+ * exact match on the ttl field
+ */
+ if (match->mask.ip_ttl != U8_MAX) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: only support mangle ipv6.hop_limit when we have an exact match on ttl, mask used for match (%#x)",
+ match->mask.ip_ttl);
+ return -EOPNOTSUPP;
+ }
+
+ /* check that we don't try to decrement 0, which equates
+ * to setting the ttl to 0xff
+ */
+ if (match->value.ip_ttl == 0) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Unsupported: we cannot decrement hop_limit past 0");
+ return -EOPNOTSUPP;
+ }
+
+ /* check that we do not decrement hoplimit twice */
+ if (!efx_tc_flower_action_order_ok(act,
+ EFX_TC_AO_DEC_TTL)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Unsupported: multiple dec ttl");
+ return -EOPNOTSUPP;
+ }
+
+ /* check pedit can be achieved with decrement action */
+ tr_ttl = match->value.ip_ttl - 1;
+ if ((fa->mangle.val >> 24) == tr_ttl) {
+ act->do_ttl_dec = 1;
+ return 0;
+ }
+
+ fallthrough;
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Unsupported: only support mangle on the hop_limit field");
+ return -EOPNOTSUPP;
+ }
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled mangle htype %u for action rule",
+ fa->mangle.htype);
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/**
+ * efx_tc_incomplete_mangle() - check for leftover partial pedits
+ * @mung: accumulator for partial mangles
+ * @extack: netlink extended ack for reporting errors
+ *
+ * Since the MAE can only overwrite whole fields, any partial
+ * field mangle left over on reaching packet delivery (mirred or
+ * end of TC actions) cannot be offloaded. Check for any such
+ * and reject them with -%EOPNOTSUPP.
+ */
+
+static int efx_tc_incomplete_mangle(struct efx_tc_mangler_state *mung,
+ struct netlink_ext_ack *extack)
+{
+ if (mung->dst_mac_32 || mung->dst_mac_16) {
+ NL_SET_ERR_MSG_MOD(extack, "Incomplete pedit of destination MAC address");
+ return -EOPNOTSUPP;
+ }
+ if (mung->src_mac_16 || mung->src_mac_32) {
+ NL_SET_ERR_MSG_MOD(extack, "Incomplete pedit of source MAC address");
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
struct net_device *net_dev,
struct flow_cls_offload *tc)
@@ -681,11 +1382,40 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
match.mask.ingress_port = ~0;
if (tc->common.chain_index) {
- NL_SET_ERR_MSG_MOD(extack, "No support for nonzero chain_index");
- return -EOPNOTSUPP;
+ struct efx_tc_recirc_id *rid;
+
+ rid = efx_tc_get_recirc_id(efx, tc->common.chain_index, net_dev);
+ if (IS_ERR(rid)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Failed to allocate a hardware recirculation ID for chain_index %u",
+ tc->common.chain_index);
+ return PTR_ERR(rid);
+ }
+ match.rid = rid;
+ match.value.recirc_id = rid->fw_id;
}
match.mask.recirc_id = 0xff;
+ /* AR table can't match on DO_CT (+trk). But a commonly used pattern is
+ * +trk+est, which is strictly implied by +est, so rewrite it to that.
+ */
+ if (match.mask.ct_state_trk && match.value.ct_state_trk &&
+ match.mask.ct_state_est && match.value.ct_state_est)
+ match.mask.ct_state_trk = 0;
+ /* Thanks to CT_TCP_FLAGS_INHIBIT, packets with interesting flags could
+ * match +trk-est (CT_HIT=0) despite being on an established connection.
+ * So make -est imply -tcp_syn_fin_rst match to ensure these packets
+ * still hit the software path.
+ */
+ if (match.mask.ct_state_est && !match.value.ct_state_est) {
+ if (match.value.tcp_syn_fin_rst) {
+ /* Can't offload this combination */
+ rc = -EOPNOTSUPP;
+ goto release;
+ }
+ match.mask.tcp_syn_fin_rst = true;
+ }
+
flow_action_for_each(i, fa, &fr->action) {
switch (fa->id) {
case FLOW_ACTION_REDIRECT:
@@ -702,12 +1432,13 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
if (!found) { /* We don't care. */
netif_dbg(efx, drv, efx->net_dev,
"Ignoring foreign filter that doesn't egdev us\n");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto release;
}
rc = efx_mae_match_check_caps(efx, &match.mask, NULL);
if (rc)
- return rc;
+ goto release;
if (efx_tc_match_is_encap(&match.mask)) {
enum efx_encap_type type;
@@ -716,7 +1447,8 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
if (type == EFX_ENCAP_TYPE_NONE) {
NL_SET_ERR_MSG_MOD(extack,
"Egress encap match on unsupported tunnel device");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto release;
}
rc = efx_mae_check_encap_type_supported(efx, type);
@@ -724,25 +1456,26 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
NL_SET_ERR_MSG_FMT_MOD(extack,
"Firmware reports no support for %s encap match",
efx_tc_encap_type_name(type));
- return rc;
+ goto release;
}
rc = efx_tc_flower_record_encap_match(efx, &match, type,
EFX_TC_EM_DIRECT, 0, 0,
extack);
if (rc)
- return rc;
+ goto release;
} else {
/* This is not a tunnel decap rule, ignore it */
netif_dbg(efx, drv, efx->net_dev,
"Ignoring foreign filter without encap match\n");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto release;
}
rule = kzalloc(sizeof(*rule), GFP_USER);
if (!rule) {
rc = -ENOMEM;
- goto out_free;
+ goto release;
}
INIT_LIST_HEAD(&rule->acts.list);
rule->cookie = tc->cookie;
@@ -754,7 +1487,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
"Ignoring already-offloaded rule (cookie %lx)\n",
tc->cookie);
rc = -EEXIST;
- goto out_free;
+ goto release;
}
act = kzalloc(sizeof(*act), GFP_USER);
@@ -912,21 +1645,95 @@ release:
/* We failed to insert the rule, so free up any entries we created in
* subsidiary tables.
*/
+ if (match.rid)
+ efx_tc_put_recirc_id(efx, match.rid);
if (act)
efx_tc_free_action_set(efx, act, false);
if (rule) {
- rhashtable_remove_fast(&efx->tc->match_action_ht,
- &rule->linkage,
- efx_tc_match_action_ht_params);
+ if (!old)
+ rhashtable_remove_fast(&efx->tc->match_action_ht,
+ &rule->linkage,
+ efx_tc_match_action_ht_params);
efx_tc_free_action_set_list(efx, &rule->acts, false);
}
-out_free:
kfree(rule);
if (match.encap)
efx_tc_flower_release_encap_match(efx, match.encap);
return rc;
}
+static int efx_tc_flower_replace_lhs(struct efx_nic *efx,
+ struct flow_cls_offload *tc,
+ struct flow_rule *fr,
+ struct efx_tc_match *match,
+ struct efx_rep *efv,
+ struct net_device *net_dev)
+{
+ struct netlink_ext_ack *extack = tc->common.extack;
+ struct efx_tc_lhs_rule *rule, *old;
+ int rc;
+
+ if (tc->common.chain_index) {
+ NL_SET_ERR_MSG_MOD(extack, "LHS rule only allowed in chain 0");
+ return -EOPNOTSUPP;
+ }
+
+ if (match->mask.ct_state_trk && match->value.ct_state_trk) {
+ NL_SET_ERR_MSG_MOD(extack, "LHS rule can never match +trk");
+ return -EOPNOTSUPP;
+ }
+ /* LHS rules are always -trk, so we don't need to match on that */
+ match->mask.ct_state_trk = 0;
+ match->value.ct_state_trk = 0;
+
+ rc = efx_mae_match_check_caps_lhs(efx, &match->mask, extack);
+ if (rc)
+ return rc;
+
+ rule = kzalloc(sizeof(*rule), GFP_USER);
+ if (!rule)
+ return -ENOMEM;
+ rule->cookie = tc->cookie;
+ old = rhashtable_lookup_get_insert_fast(&efx->tc->lhs_rule_ht,
+ &rule->linkage,
+ efx_tc_lhs_rule_ht_params);
+ if (old) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Already offloaded rule (cookie %lx)\n", tc->cookie);
+ rc = -EEXIST;
+ NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded");
+ goto release;
+ }
+
+ /* Parse actions */
+ /* See note in efx_tc_flower_replace() regarding passed net_dev
+ * (used for efx_tc_get_recirc_id()).
+ */
+ rc = efx_tc_flower_handle_lhs_actions(efx, tc, fr, efx->net_dev, rule);
+ if (rc)
+ goto release;
+
+ rule->match = *match;
+
+ rc = efx_mae_insert_lhs_rule(efx, rule, EFX_TC_PRIO_TC);
+ if (rc) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to insert rule in hw");
+ goto release;
+ }
+ netif_dbg(efx, drv, efx->net_dev,
+ "Successfully parsed lhs rule (cookie %lx)\n",
+ tc->cookie);
+ return 0;
+
+release:
+ efx_tc_flower_release_lhs_actions(efx, &rule->lhs_act);
+ if (!old)
+ rhashtable_remove_fast(&efx->tc->lhs_rule_ht, &rule->linkage,
+ efx_tc_lhs_rule_ht_params);
+ kfree(rule);
+ return rc;
+}
+
static int efx_tc_flower_replace(struct efx_nic *efx,
struct net_device *net_dev,
struct flow_cls_offload *tc,
@@ -936,6 +1743,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
struct netlink_ext_ack *extack = tc->common.extack;
const struct ip_tunnel_info *encap_info = NULL;
struct efx_tc_flow_rule *rule = NULL, *old;
+ struct efx_tc_mangler_state mung = {};
struct efx_tc_action_set *act = NULL;
const struct flow_action_entry *fa;
struct efx_rep *from_efv, *to_efv;
@@ -982,19 +1790,69 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
return -EOPNOTSUPP;
}
+ if (efx_tc_rule_is_lhs_rule(fr, &match))
+ return efx_tc_flower_replace_lhs(efx, tc, fr, &match, efv,
+ net_dev);
+
+ /* chain_index 0 is always recirc_id 0 (and does not appear in recirc_ht).
+ * Conveniently, match.rid == NULL and match.value.recirc_id == 0 owing
+ * to the initial memset(), so we don't need to do anything in that case.
+ */
if (tc->common.chain_index) {
- NL_SET_ERR_MSG_MOD(extack, "No support for nonzero chain_index");
- return -EOPNOTSUPP;
+ struct efx_tc_recirc_id *rid;
+
+ /* Note regarding passed net_dev:
+ * VFreps and PF can share chain namespace, as they have
+ * distinct ingress_mports. So we don't need to burn an
+ * extra recirc_id if both use the same chain_index.
+ * (Strictly speaking, we could give each VFrep its own
+ * recirc_id namespace that doesn't take IDs away from the
+ * PF, but that would require a bunch of additional IDAs -
+ * one for each representor - and that's not likely to be
+ * the main cause of recirc_id exhaustion anyway.)
+ */
+ rid = efx_tc_get_recirc_id(efx, tc->common.chain_index,
+ efx->net_dev);
+ if (IS_ERR(rid)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Failed to allocate a hardware recirculation ID for chain_index %u",
+ tc->common.chain_index);
+ return PTR_ERR(rid);
+ }
+ match.rid = rid;
+ match.value.recirc_id = rid->fw_id;
}
match.mask.recirc_id = 0xff;
+ /* AR table can't match on DO_CT (+trk). But a commonly used pattern is
+ * +trk+est, which is strictly implied by +est, so rewrite it to that.
+ */
+ if (match.mask.ct_state_trk && match.value.ct_state_trk &&
+ match.mask.ct_state_est && match.value.ct_state_est)
+ match.mask.ct_state_trk = 0;
+ /* Thanks to CT_TCP_FLAGS_INHIBIT, packets with interesting flags could
+ * match +trk-est (CT_HIT=0) despite being on an established connection.
+ * So make -est imply -tcp_syn_fin_rst match to ensure these packets
+ * still hit the software path.
+ */
+ if (match.mask.ct_state_est && !match.value.ct_state_est) {
+ if (match.value.tcp_syn_fin_rst) {
+ /* Can't offload this combination */
+ rc = -EOPNOTSUPP;
+ goto release;
+ }
+ match.mask.tcp_syn_fin_rst = true;
+ }
+
rc = efx_mae_match_check_caps(efx, &match.mask, extack);
if (rc)
- return rc;
+ goto release;
rule = kzalloc(sizeof(*rule), GFP_USER);
- if (!rule)
- return -ENOMEM;
+ if (!rule) {
+ rc = -ENOMEM;
+ goto release;
+ }
INIT_LIST_HEAD(&rule->acts.list);
rule->cookie = tc->cookie;
old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht,
@@ -1004,8 +1862,8 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
netif_dbg(efx, drv, efx->net_dev,
"Already offloaded rule (cookie %lx)\n", tc->cookie);
NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded");
- kfree(rule);
- return -EEXIST;
+ rc = -EEXIST;
+ goto release;
}
/* Parse actions */
@@ -1222,6 +2080,16 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
act->vlan_proto[act->vlan_push] = fa->vlan.proto;
act->vlan_push++;
break;
+ case FLOW_ACTION_ADD:
+ rc = efx_tc_pedit_add(efx, act, fa, extack);
+ if (rc < 0)
+ goto release;
+ break;
+ case FLOW_ACTION_MANGLE:
+ rc = efx_tc_mangle(efx, act, fa, &mung, extack, &match);
+ if (rc < 0)
+ goto release;
+ break;
case FLOW_ACTION_TUNNEL_ENCAP:
if (encap_info) {
/* Can't specify encap multiple times.
@@ -1261,6 +2129,9 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
}
}
+ rc = efx_tc_incomplete_mangle(&mung, extack);
+ if (rc < 0)
+ goto release;
if (act) {
/* Not shot/redirected, so deliver to default dest */
if (from_efv == EFX_EFV_PF)
@@ -1323,12 +2194,15 @@ release:
/* We failed to insert the rule, so free up any entries we created in
* subsidiary tables.
*/
+ if (match.rid)
+ efx_tc_put_recirc_id(efx, match.rid);
if (act)
efx_tc_free_action_set(efx, act, false);
if (rule) {
- rhashtable_remove_fast(&efx->tc->match_action_ht,
- &rule->linkage,
- efx_tc_match_action_ht_params);
+ if (!old)
+ rhashtable_remove_fast(&efx->tc->match_action_ht,
+ &rule->linkage,
+ efx_tc_match_action_ht_params);
efx_tc_free_action_set_list(efx, &rule->acts, false);
}
kfree(rule);
@@ -1340,8 +2214,26 @@ static int efx_tc_flower_destroy(struct efx_nic *efx,
struct flow_cls_offload *tc)
{
struct netlink_ext_ack *extack = tc->common.extack;
+ struct efx_tc_lhs_rule *lhs_rule;
struct efx_tc_flow_rule *rule;
+ lhs_rule = rhashtable_lookup_fast(&efx->tc->lhs_rule_ht, &tc->cookie,
+ efx_tc_lhs_rule_ht_params);
+ if (lhs_rule) {
+ /* Remove it from HW */
+ efx_mae_remove_lhs_rule(efx, lhs_rule);
+ /* Delete it from SW */
+ efx_tc_flower_release_lhs_actions(efx, &lhs_rule->lhs_act);
+ rhashtable_remove_fast(&efx->tc->lhs_rule_ht, &lhs_rule->linkage,
+ efx_tc_lhs_rule_ht_params);
+ if (lhs_rule->match.encap)
+ efx_tc_flower_release_encap_match(efx, lhs_rule->match.encap);
+ netif_dbg(efx, drv, efx->net_dev, "Removed (lhs) filter %lx\n",
+ lhs_rule->cookie);
+ kfree(lhs_rule);
+ return 0;
+ }
+
rule = rhashtable_lookup_fast(&efx->tc->match_action_ht, &tc->cookie,
efx_tc_match_action_ht_params);
if (!rule) {
@@ -1657,11 +2549,17 @@ int efx_init_tc(struct efx_nic *efx)
rc = efx_tc_configure_fallback_acts_reps(efx);
if (rc)
return rc;
- rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx);
+ rc = efx_mae_get_tables(efx);
if (rc)
return rc;
+ rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx);
+ if (rc)
+ goto out_free;
efx->tc->up = true;
return 0;
+out_free:
+ efx_mae_free_tables(efx);
+ return rc;
}
void efx_fini_tc(struct efx_nic *efx)
@@ -1677,6 +2575,7 @@ void efx_fini_tc(struct efx_nic *efx)
efx_tc_deconfigure_fallback_acts(efx, &efx->tc->facts.pf);
efx_tc_deconfigure_fallback_acts(efx, &efx->tc->facts.reps);
efx->tc->up = false;
+ efx_mae_free_tables(efx);
}
/* At teardown time, all TC filter rules (and thus all resources they created)
@@ -1691,6 +2590,42 @@ static void efx_tc_encap_match_free(void *ptr, void *__unused)
kfree(encap);
}
+static void efx_tc_recirc_free(void *ptr, void *arg)
+{
+ struct efx_tc_recirc_id *rid = ptr;
+ struct efx_nic *efx = arg;
+
+ WARN_ON(refcount_read(&rid->ref));
+ ida_free(&efx->tc->recirc_ida, rid->fw_id);
+ kfree(rid);
+}
+
+static void efx_tc_lhs_free(void *ptr, void *arg)
+{
+ struct efx_tc_lhs_rule *rule = ptr;
+ struct efx_nic *efx = arg;
+
+ netif_err(efx, drv, efx->net_dev,
+ "tc lhs_rule %lx still present at teardown, removing\n",
+ rule->cookie);
+
+ if (rule->lhs_act.zone)
+ efx_tc_ct_unregister_zone(efx, rule->lhs_act.zone);
+ if (rule->lhs_act.count)
+ efx_tc_flower_put_counter_index(efx, rule->lhs_act.count);
+ efx_mae_remove_lhs_rule(efx, rule);
+
+ kfree(rule);
+}
+
+static void efx_tc_mac_free(void *ptr, void *__unused)
+{
+ struct efx_tc_mac_pedit_action *ped = ptr;
+
+ WARN_ON(refcount_read(&ped->ref));
+ kfree(ped);
+}
+
static void efx_tc_flow_free(void *ptr, void *arg)
{
struct efx_tc_flow_rule *rule = ptr;
@@ -1731,12 +2666,25 @@ int efx_init_struct_tc(struct efx_nic *efx)
rc = efx_tc_init_counters(efx);
if (rc < 0)
goto fail_counters;
+ rc = rhashtable_init(&efx->tc->mac_ht, &efx_tc_mac_ht_params);
+ if (rc < 0)
+ goto fail_mac_ht;
rc = rhashtable_init(&efx->tc->encap_match_ht, &efx_tc_encap_match_ht_params);
if (rc < 0)
goto fail_encap_match_ht;
rc = rhashtable_init(&efx->tc->match_action_ht, &efx_tc_match_action_ht_params);
if (rc < 0)
goto fail_match_action_ht;
+ rc = rhashtable_init(&efx->tc->lhs_rule_ht, &efx_tc_lhs_rule_ht_params);
+ if (rc < 0)
+ goto fail_lhs_rule_ht;
+ rc = efx_tc_init_conntrack(efx);
+ if (rc < 0)
+ goto fail_conntrack;
+ rc = rhashtable_init(&efx->tc->recirc_ht, &efx_tc_recirc_ht_params);
+ if (rc < 0)
+ goto fail_recirc_ht;
+ ida_init(&efx->tc->recirc_ida);
efx->tc->reps_filter_uc = -1;
efx->tc->reps_filter_mc = -1;
INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list);
@@ -1749,9 +2697,17 @@ int efx_init_struct_tc(struct efx_nic *efx)
efx->tc->facts.reps.fw_id = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL;
efx->extra_channel_type[EFX_EXTRA_CHANNEL_TC] = &efx_tc_channel_type;
return 0;
+fail_recirc_ht:
+ efx_tc_destroy_conntrack(efx);
+fail_conntrack:
+ rhashtable_destroy(&efx->tc->lhs_rule_ht);
+fail_lhs_rule_ht:
+ rhashtable_destroy(&efx->tc->match_action_ht);
fail_match_action_ht:
rhashtable_destroy(&efx->tc->encap_match_ht);
fail_encap_match_ht:
+ rhashtable_destroy(&efx->tc->mac_ht);
+fail_mac_ht:
efx_tc_destroy_counters(efx);
fail_counters:
efx_tc_destroy_encap_actions(efx);
@@ -1778,10 +2734,16 @@ void efx_fini_struct_tc(struct efx_nic *efx)
MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
EFX_WARN_ON_PARANOID(efx->tc->facts.reps.fw_id !=
MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
+ rhashtable_free_and_destroy(&efx->tc->lhs_rule_ht, efx_tc_lhs_free, efx);
rhashtable_free_and_destroy(&efx->tc->match_action_ht, efx_tc_flow_free,
efx);
rhashtable_free_and_destroy(&efx->tc->encap_match_ht,
efx_tc_encap_match_free, NULL);
+ efx_tc_fini_conntrack(efx);
+ rhashtable_free_and_destroy(&efx->tc->recirc_ht, efx_tc_recirc_free, efx);
+ WARN_ON(!ida_is_empty(&efx->tc->recirc_ida));
+ ida_destroy(&efx->tc->recirc_ida);
+ rhashtable_free_and_destroy(&efx->tc->mac_ht, efx_tc_mac_free, NULL);
efx_tc_fini_counters(efx);
efx_tc_fini_encap_actions(efx);
mutex_unlock(&efx->tc->mutex);
diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h
index 1549c3df43bb..4dd2c378fd9f 100644
--- a/drivers/net/ethernet/sfc/tc.h
+++ b/drivers/net/ethernet/sfc/tc.h
@@ -18,36 +18,76 @@
#define IS_ALL_ONES(v) (!(typeof (v))~(v))
-#ifdef CONFIG_IPV6
+/**
+ * struct efx_tc_mac_pedit_action - mac pedit action fields
+ *
+ * @h_addr: mac address field of ethernet header
+ * @linkage: rhashtable reference
+ * @ref: reference count
+ * @fw_id: index of this entry in firmware MAC address table
+ *
+ * MAC address edits are indirected through a table in the hardware
+ */
+struct efx_tc_mac_pedit_action {
+ u8 h_addr[ETH_ALEN];
+ struct rhash_head linkage;
+ refcount_t ref;
+ u32 fw_id; /* index of this entry in firmware MAC address table */
+};
+
static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr)
{
return !memchr_inv(addr, 0xff, sizeof(*addr));
}
-#endif
struct efx_tc_encap_action; /* see tc_encap_actions.h */
+/**
+ * struct efx_tc_action_set - collection of tc action fields
+ *
+ * @vlan_push: the number of vlan headers to push
+ * @vlan_pop: the number of vlan headers to pop
+ * @decap: used to indicate a tunnel header decapsulation should take place
+ * @do_ttl_dec: used to indicate IP TTL / Hop Limit should be decremented
+ * @deliver: used to indicate a deliver action should take place
+ * @vlan_tci: tci fields for vlan push actions
+ * @vlan_proto: ethernet types for vlan push actions
+ * @count: counter mapping
+ * @encap_md: encap entry in tc_encap_ht table
+ * @encap_user: linked list of encap users (encap_md->users)
+ * @user: owning action-set-list. Only populated if @encap_md is; used by efx_tc_update_encap() fallback handling
+ * @count_user: linked list of counter users (counter->users)
+ * @dest_mport: destination mport
+ * @src_mac: source mac entry in tc_mac_ht table
+ * @dst_mac: destination mac entry in tc_mac_ht table
+ * @fw_id: index of this entry in firmware actions table
+ * @list: linked list of tc actions
+ *
+ */
struct efx_tc_action_set {
u16 vlan_push:2;
u16 vlan_pop:2;
u16 decap:1;
+ u16 do_ttl_dec:1;
u16 deliver:1;
- __be16 vlan_tci[2]; /* TCIs for vlan_push */
- __be16 vlan_proto[2]; /* Ethertypes for vlan_push */
+ __be16 vlan_tci[2];
+ __be16 vlan_proto[2];
struct efx_tc_counter_index *count;
- struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */
- struct list_head encap_user; /* entry on encap_md->users list */
- struct efx_tc_action_set_list *user; /* Only populated if encap_md */
- struct list_head count_user; /* entry on counter->users list, if encap */
+ struct efx_tc_encap_action *encap_md;
+ struct list_head encap_user;
+ struct efx_tc_action_set_list *user;
+ struct list_head count_user;
u32 dest_mport;
- u32 fw_id; /* index of this entry in firmware actions table */
+ struct efx_tc_mac_pedit_action *src_mac;
+ struct efx_tc_mac_pedit_action *dst_mac;
+ u32 fw_id;
struct list_head list;
};
struct efx_tc_match_fields {
/* L1 */
u32 ingress_port;
- u8 recirc_id;
+ u8 recirc_id; /* mapped from (u32) TC chain_index to smaller space */
/* L2 (inner when encap) */
__be16 eth_proto;
__be16 vlan_tci[2], vlan_proto[2];
@@ -62,6 +102,7 @@ struct efx_tc_match_fields {
/* L4 */
__be16 l4_sport, l4_dport; /* Ports (UDP, TCP) */
__be16 tcp_flags;
+ bool tcp_syn_fin_rst; /* true if ANY of SYN/FIN/RST are set */
/* Encap. The following are *outer* fields. Note that there are no
* outer eth (L2) fields; this is because TC doesn't have them.
*/
@@ -70,6 +111,10 @@ struct efx_tc_match_fields {
u8 enc_ip_tos, enc_ip_ttl;
__be16 enc_sport, enc_dport;
__be32 enc_keyid; /* e.g. VNI, VSID */
+ /* Conntrack. */
+ u16 ct_state_trk:1, ct_state_est:1;
+ u32 ct_mark;
+ u16 ct_zone;
};
static inline bool efx_tc_match_is_encap(const struct efx_tc_match_fields *mask)
@@ -117,10 +162,19 @@ struct efx_tc_encap_match {
struct efx_tc_encap_match *pseudo; /* Referenced pseudo EM if needed */
};
+struct efx_tc_recirc_id {
+ u32 chain_index;
+ struct net_device *net_dev;
+ struct rhash_head linkage;
+ refcount_t ref;
+ u8 fw_id; /* index allocated for use in the MAE */
+};
+
struct efx_tc_match {
struct efx_tc_match_fields value;
struct efx_tc_match_fields mask;
struct efx_tc_encap_match *encap;
+ struct efx_tc_recirc_id *rid;
};
struct efx_tc_action_set_list {
@@ -128,6 +182,12 @@ struct efx_tc_action_set_list {
u32 fw_id;
};
+struct efx_tc_lhs_action {
+ struct efx_tc_recirc_id *rid;
+ struct efx_tc_ct_zone *zone;
+ struct efx_tc_counter_index *count;
+};
+
struct efx_tc_flow_rule {
unsigned long cookie;
struct rhash_head linkage;
@@ -137,12 +197,62 @@ struct efx_tc_flow_rule {
u32 fw_id;
};
+struct efx_tc_lhs_rule {
+ unsigned long cookie;
+ struct efx_tc_match match;
+ struct efx_tc_lhs_action lhs_act;
+ struct rhash_head linkage;
+ u32 fw_id;
+};
+
enum efx_tc_rule_prios {
EFX_TC_PRIO_TC, /* Rule inserted by TC */
EFX_TC_PRIO_DFLT, /* Default switch rule; one of efx_tc_default_rules */
EFX_TC_PRIO__NUM
};
+struct efx_tc_table_field_fmt {
+ u16 field_id;
+ u16 lbn;
+ u16 width;
+ u8 masking;
+ u8 scheme;
+};
+
+struct efx_tc_table_desc {
+ u16 type;
+ u16 key_width;
+ u16 resp_width;
+ u16 n_keys;
+ u16 n_resps;
+ u16 n_prios;
+ u8 flags;
+ u8 scheme;
+ struct efx_tc_table_field_fmt *keys;
+ struct efx_tc_table_field_fmt *resps;
+};
+
+struct efx_tc_table_ct { /* TABLE_ID_CONNTRACK_TABLE */
+ struct efx_tc_table_desc desc;
+ bool hooked;
+ struct { /* indices of named fields within @desc.keys */
+ u8 eth_proto_idx;
+ u8 ip_proto_idx;
+ u8 src_ip_idx; /* either v4 or v6 */
+ u8 dst_ip_idx;
+ u8 l4_sport_idx;
+ u8 l4_dport_idx;
+ u8 zone_idx; /* for TABLE_FIELD_ID_DOMAIN */
+ } keys;
+ struct { /* indices of named fields within @desc.resps */
+ u8 dnat_idx;
+ u8 nat_ip_idx;
+ u8 l4_natport_idx;
+ u8 mark_idx;
+ u8 counter_id_idx;
+ } resps;
+};
+
/**
* struct efx_tc_state - control plane data for TC offload
*
@@ -152,9 +262,16 @@ enum efx_tc_rule_prios {
* @counter_ht: Hashtable of TC counters (FW IDs and counter values)
* @counter_id_ht: Hashtable mapping TC counter cookies to counters
* @encap_ht: Hashtable of TC encap actions
+ * @mac_ht: Hashtable of MAC address entries (for pedits)
* @encap_match_ht: Hashtable of TC encap matches
* @match_action_ht: Hashtable of TC match-action rules
+ * @lhs_rule_ht: Hashtable of TC left-hand (act ct & goto chain) rules
+ * @ct_zone_ht: Hashtable of TC conntrack flowtable bindings
+ * @ct_ht: Hashtable of TC conntrack flow entries
* @neigh_ht: Hashtable of neighbour watches (&struct efx_neigh_binder)
+ * @recirc_ht: Hashtable of recirculation ID mappings (&struct efx_tc_recirc_id)
+ * @recirc_ida: Recirculation ID allocator
+ * @meta_ct: MAE table layout for conntrack table
* @reps_mport_id: MAE port allocated for representor RX
* @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
* @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
@@ -183,9 +300,16 @@ struct efx_tc_state {
struct rhashtable counter_ht;
struct rhashtable counter_id_ht;
struct rhashtable encap_ht;
+ struct rhashtable mac_ht;
struct rhashtable encap_match_ht;
struct rhashtable match_action_ht;
+ struct rhashtable lhs_rule_ht;
+ struct rhashtable ct_zone_ht;
+ struct rhashtable ct_ht;
struct rhashtable neigh_ht;
+ struct rhashtable recirc_ht;
+ struct ida recirc_ida;
+ struct efx_tc_table_ct meta_ct;
u32 reps_mport_id, reps_mport_vport_id;
s32 reps_filter_uc, reps_filter_mc;
bool flush_counters;
diff --git a/drivers/net/ethernet/sfc/tc_conntrack.c b/drivers/net/ethernet/sfc/tc_conntrack.c
new file mode 100644
index 000000000000..8e06bfbcbea1
--- /dev/null
+++ b/drivers/net/ethernet/sfc/tc_conntrack.c
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2023, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include "tc_conntrack.h"
+#include "tc.h"
+#include "mae.h"
+
+static int efx_tc_flow_block(enum tc_setup_type type, void *type_data,
+ void *cb_priv);
+
+static const struct rhashtable_params efx_tc_ct_zone_ht_params = {
+ .key_len = offsetof(struct efx_tc_ct_zone, linkage),
+ .key_offset = 0,
+ .head_offset = offsetof(struct efx_tc_ct_zone, linkage),
+};
+
+static const struct rhashtable_params efx_tc_ct_ht_params = {
+ .key_len = offsetof(struct efx_tc_ct_entry, linkage),
+ .key_offset = 0,
+ .head_offset = offsetof(struct efx_tc_ct_entry, linkage),
+};
+
+static void efx_tc_ct_zone_free(void *ptr, void *arg)
+{
+ struct efx_tc_ct_zone *zone = ptr;
+ struct efx_nic *efx = zone->efx;
+
+ netif_err(efx, drv, efx->net_dev,
+ "tc ct_zone %u still present at teardown, removing\n",
+ zone->zone);
+
+ nf_flow_table_offload_del_cb(zone->nf_ft, efx_tc_flow_block, zone);
+ kfree(zone);
+}
+
+static void efx_tc_ct_free(void *ptr, void *arg)
+{
+ struct efx_tc_ct_entry *conn = ptr;
+ struct efx_nic *efx = arg;
+
+ netif_err(efx, drv, efx->net_dev,
+ "tc ct_entry %lx still present at teardown\n",
+ conn->cookie);
+
+ /* We can release the counter, but we can't remove the CT itself
+ * from hardware because the table meta is already gone.
+ */
+ efx_tc_flower_release_counter(efx, conn->cnt);
+ kfree(conn);
+}
+
+int efx_tc_init_conntrack(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = rhashtable_init(&efx->tc->ct_zone_ht, &efx_tc_ct_zone_ht_params);
+ if (rc < 0)
+ goto fail_ct_zone_ht;
+ rc = rhashtable_init(&efx->tc->ct_ht, &efx_tc_ct_ht_params);
+ if (rc < 0)
+ goto fail_ct_ht;
+ return 0;
+fail_ct_ht:
+ rhashtable_destroy(&efx->tc->ct_zone_ht);
+fail_ct_zone_ht:
+ return rc;
+}
+
+/* Only call this in init failure teardown.
+ * Normal exit should fini instead as there may be entries in the table.
+ */
+void efx_tc_destroy_conntrack(struct efx_nic *efx)
+{
+ rhashtable_destroy(&efx->tc->ct_ht);
+ rhashtable_destroy(&efx->tc->ct_zone_ht);
+}
+
+void efx_tc_fini_conntrack(struct efx_nic *efx)
+{
+ rhashtable_free_and_destroy(&efx->tc->ct_zone_ht, efx_tc_ct_zone_free, NULL);
+ rhashtable_free_and_destroy(&efx->tc->ct_ht, efx_tc_ct_free, efx);
+}
+
+#define EFX_NF_TCP_FLAG(flg) cpu_to_be16(be32_to_cpu(TCP_FLAG_##flg) >> 16)
+
+static int efx_tc_ct_parse_match(struct efx_nic *efx, struct flow_rule *fr,
+ struct efx_tc_ct_entry *conn)
+{
+ struct flow_dissector *dissector = fr->match.dissector;
+ unsigned char ipv = 0;
+ bool tcp = false;
+
+ if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_CONTROL)) {
+ struct flow_match_control fm;
+
+ flow_rule_match_control(fr, &fm);
+ if (IS_ALL_ONES(fm.mask->addr_type))
+ switch (fm.key->addr_type) {
+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
+ ipv = 4;
+ break;
+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
+ ipv = 6;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!ipv) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack missing ipv specification\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (dissector->used_keys &
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_TCP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_META))) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Unsupported conntrack keys %#llx\n",
+ dissector->used_keys);
+ return -EOPNOTSUPP;
+ }
+
+ if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_BASIC)) {
+ struct flow_match_basic fm;
+
+ flow_rule_match_basic(fr, &fm);
+ if (!IS_ALL_ONES(fm.mask->n_proto)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack eth_proto is not exact-match; mask %04x\n",
+ ntohs(fm.mask->n_proto));
+ return -EOPNOTSUPP;
+ }
+ conn->eth_proto = fm.key->n_proto;
+ if (conn->eth_proto != (ipv == 4 ? htons(ETH_P_IP)
+ : htons(ETH_P_IPV6))) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack eth_proto is not IPv%u, is %04x\n",
+ ipv, ntohs(conn->eth_proto));
+ return -EOPNOTSUPP;
+ }
+ if (!IS_ALL_ONES(fm.mask->ip_proto)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ip_proto is not exact-match; mask %02x\n",
+ fm.mask->ip_proto);
+ return -EOPNOTSUPP;
+ }
+ conn->ip_proto = fm.key->ip_proto;
+ switch (conn->ip_proto) {
+ case IPPROTO_TCP:
+ tcp = true;
+ break;
+ case IPPROTO_UDP:
+ break;
+ default:
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ip_proto not TCP or UDP, is %02x\n",
+ conn->ip_proto);
+ return -EOPNOTSUPP;
+ }
+ } else {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack missing eth_proto, ip_proto\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (ipv == 4 && flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+ struct flow_match_ipv4_addrs fm;
+
+ flow_rule_match_ipv4_addrs(fr, &fm);
+ if (!IS_ALL_ONES(fm.mask->src)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ipv4.src is not exact-match; mask %08x\n",
+ ntohl(fm.mask->src));
+ return -EOPNOTSUPP;
+ }
+ conn->src_ip = fm.key->src;
+ if (!IS_ALL_ONES(fm.mask->dst)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ipv4.dst is not exact-match; mask %08x\n",
+ ntohl(fm.mask->dst));
+ return -EOPNOTSUPP;
+ }
+ conn->dst_ip = fm.key->dst;
+ } else if (ipv == 6 && flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
+ struct flow_match_ipv6_addrs fm;
+
+ flow_rule_match_ipv6_addrs(fr, &fm);
+ if (!efx_ipv6_addr_all_ones(&fm.mask->src)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ipv6.src is not exact-match; mask %pI6\n",
+ &fm.mask->src);
+ return -EOPNOTSUPP;
+ }
+ conn->src_ip6 = fm.key->src;
+ if (!efx_ipv6_addr_all_ones(&fm.mask->dst)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ipv6.dst is not exact-match; mask %pI6\n",
+ &fm.mask->dst);
+ return -EOPNOTSUPP;
+ }
+ conn->dst_ip6 = fm.key->dst;
+ } else {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack missing IPv%u addrs\n", ipv);
+ return -EOPNOTSUPP;
+ }
+
+ if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_PORTS)) {
+ struct flow_match_ports fm;
+
+ flow_rule_match_ports(fr, &fm);
+ if (!IS_ALL_ONES(fm.mask->src)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ports.src is not exact-match; mask %04x\n",
+ ntohs(fm.mask->src));
+ return -EOPNOTSUPP;
+ }
+ conn->l4_sport = fm.key->src;
+ if (!IS_ALL_ONES(fm.mask->dst)) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack ports.dst is not exact-match; mask %04x\n",
+ ntohs(fm.mask->dst));
+ return -EOPNOTSUPP;
+ }
+ conn->l4_dport = fm.key->dst;
+ } else {
+ netif_dbg(efx, drv, efx->net_dev, "Conntrack missing L4 ports\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_TCP)) {
+ __be16 tcp_interesting_flags;
+ struct flow_match_tcp fm;
+
+ if (!tcp) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Conntrack matching on TCP keys but ipproto is not tcp\n");
+ return -EOPNOTSUPP;
+ }
+ flow_rule_match_tcp(fr, &fm);
+ tcp_interesting_flags = EFX_NF_TCP_FLAG(SYN) |
+ EFX_NF_TCP_FLAG(RST) |
+ EFX_NF_TCP_FLAG(FIN);
+ /* If any of the tcp_interesting_flags is set, we always
+ * inhibit CT lookup in LHS (so SW can update CT table).
+ */
+ if (fm.key->flags & tcp_interesting_flags) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Unsupported conntrack tcp.flags %04x/%04x\n",
+ ntohs(fm.key->flags), ntohs(fm.mask->flags));
+ return -EOPNOTSUPP;
+ }
+ /* Other TCP flags cannot be filtered at CT */
+ if (fm.mask->flags & ~tcp_interesting_flags) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Unsupported conntrack tcp.flags %04x/%04x\n",
+ ntohs(fm.key->flags), ntohs(fm.mask->flags));
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int efx_tc_ct_replace(struct efx_tc_ct_zone *ct_zone,
+ struct flow_cls_offload *tc)
+{
+ struct flow_rule *fr = flow_cls_offload_flow_rule(tc);
+ struct efx_tc_ct_entry *conn, *old;
+ struct efx_nic *efx = ct_zone->efx;
+ const struct flow_action_entry *fa;
+ struct efx_tc_counter *cnt;
+ int rc, i;
+
+ if (WARN_ON(!efx->tc))
+ return -ENETDOWN;
+ if (WARN_ON(!efx->tc->up))
+ return -ENETDOWN;
+
+ conn = kzalloc(sizeof(*conn), GFP_USER);
+ if (!conn)
+ return -ENOMEM;
+ conn->cookie = tc->cookie;
+ old = rhashtable_lookup_get_insert_fast(&efx->tc->ct_ht,
+ &conn->linkage,
+ efx_tc_ct_ht_params);
+ if (old) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Already offloaded conntrack (cookie %lx)\n", tc->cookie);
+ rc = -EEXIST;
+ goto release;
+ }
+
+ /* Parse match */
+ conn->zone = ct_zone;
+ rc = efx_tc_ct_parse_match(efx, fr, conn);
+ if (rc)
+ goto release;
+
+ /* Parse actions */
+ flow_action_for_each(i, fa, &fr->action) {
+ switch (fa->id) {
+ case FLOW_ACTION_CT_METADATA:
+ conn->mark = fa->ct_metadata.mark;
+ if (memchr_inv(fa->ct_metadata.labels, 0, sizeof(fa->ct_metadata.labels))) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Setting CT label not supported\n");
+ rc = -EOPNOTSUPP;
+ goto release;
+ }
+ break;
+ default:
+ netif_dbg(efx, drv, efx->net_dev,
+ "Unhandled action %u for conntrack\n", fa->id);
+ rc = -EOPNOTSUPP;
+ goto release;
+ }
+ }
+
+ /* fill in defaults for unmangled values */
+ conn->nat_ip = conn->dnat ? conn->dst_ip : conn->src_ip;
+ conn->l4_natport = conn->dnat ? conn->l4_dport : conn->l4_sport;
+
+ cnt = efx_tc_flower_allocate_counter(efx, EFX_TC_COUNTER_TYPE_CT);
+ if (IS_ERR(cnt)) {
+ rc = PTR_ERR(cnt);
+ goto release;
+ }
+ conn->cnt = cnt;
+
+ rc = efx_mae_insert_ct(efx, conn);
+ if (rc) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "Failed to insert conntrack, %d\n", rc);
+ goto release;
+ }
+ mutex_lock(&ct_zone->mutex);
+ list_add_tail(&conn->list, &ct_zone->cts);
+ mutex_unlock(&ct_zone->mutex);
+ return 0;
+release:
+ if (conn->cnt)
+ efx_tc_flower_release_counter(efx, conn->cnt);
+ if (!old)
+ rhashtable_remove_fast(&efx->tc->ct_ht, &conn->linkage,
+ efx_tc_ct_ht_params);
+ kfree(conn);
+ return rc;
+}
+
+/* Caller must follow with efx_tc_ct_remove_finish() after RCU grace period! */
+static void efx_tc_ct_remove(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
+{
+ int rc;
+
+ /* Remove it from HW */
+ rc = efx_mae_remove_ct(efx, conn);
+ /* Delete it from SW */
+ rhashtable_remove_fast(&efx->tc->ct_ht, &conn->linkage,
+ efx_tc_ct_ht_params);
+ if (rc) {
+ netif_err(efx, drv, efx->net_dev,
+ "Failed to remove conntrack %lx from hw, rc %d\n",
+ conn->cookie, rc);
+ } else {
+ netif_dbg(efx, drv, efx->net_dev, "Removed conntrack %lx\n",
+ conn->cookie);
+ }
+}
+
+static void efx_tc_ct_remove_finish(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
+{
+ /* Remove related CT counter. This is delayed after the conn object we
+ * are working with has been successfully removed. This protects the
+ * counter from being used-after-free inside efx_tc_ct_stats.
+ */
+ efx_tc_flower_release_counter(efx, conn->cnt);
+ kfree(conn);
+}
+
+static int efx_tc_ct_destroy(struct efx_tc_ct_zone *ct_zone,
+ struct flow_cls_offload *tc)
+{
+ struct efx_nic *efx = ct_zone->efx;
+ struct efx_tc_ct_entry *conn;
+
+ conn = rhashtable_lookup_fast(&efx->tc->ct_ht, &tc->cookie,
+ efx_tc_ct_ht_params);
+ if (!conn) {
+ netif_warn(efx, drv, efx->net_dev,
+ "Conntrack %lx not found to remove\n", tc->cookie);
+ return -ENOENT;
+ }
+
+ mutex_lock(&ct_zone->mutex);
+ list_del(&conn->list);
+ efx_tc_ct_remove(efx, conn);
+ mutex_unlock(&ct_zone->mutex);
+ synchronize_rcu();
+ efx_tc_ct_remove_finish(efx, conn);
+ return 0;
+}
+
+static int efx_tc_ct_stats(struct efx_tc_ct_zone *ct_zone,
+ struct flow_cls_offload *tc)
+{
+ struct efx_nic *efx = ct_zone->efx;
+ struct efx_tc_ct_entry *conn;
+ struct efx_tc_counter *cnt;
+
+ rcu_read_lock();
+ conn = rhashtable_lookup_fast(&efx->tc->ct_ht, &tc->cookie,
+ efx_tc_ct_ht_params);
+ if (!conn) {
+ netif_warn(efx, drv, efx->net_dev,
+ "Conntrack %lx not found for stats\n", tc->cookie);
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ cnt = conn->cnt;
+ spin_lock_bh(&cnt->lock);
+ /* Report only last use */
+ flow_stats_update(&tc->stats, 0, 0, 0, cnt->touched,
+ FLOW_ACTION_HW_STATS_DELAYED);
+ spin_unlock_bh(&cnt->lock);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int efx_tc_flow_block(enum tc_setup_type type, void *type_data,
+ void *cb_priv)
+{
+ struct flow_cls_offload *tcb = type_data;
+ struct efx_tc_ct_zone *ct_zone = cb_priv;
+
+ if (type != TC_SETUP_CLSFLOWER)
+ return -EOPNOTSUPP;
+
+ switch (tcb->command) {
+ case FLOW_CLS_REPLACE:
+ return efx_tc_ct_replace(ct_zone, tcb);
+ case FLOW_CLS_DESTROY:
+ return efx_tc_ct_destroy(ct_zone, tcb);
+ case FLOW_CLS_STATS:
+ return efx_tc_ct_stats(ct_zone, tcb);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+struct efx_tc_ct_zone *efx_tc_ct_register_zone(struct efx_nic *efx, u16 zone,
+ struct nf_flowtable *ct_ft)
+{
+ struct efx_tc_ct_zone *ct_zone, *old;
+ int rc;
+
+ ct_zone = kzalloc(sizeof(*ct_zone), GFP_USER);
+ if (!ct_zone)
+ return ERR_PTR(-ENOMEM);
+ ct_zone->zone = zone;
+ old = rhashtable_lookup_get_insert_fast(&efx->tc->ct_zone_ht,
+ &ct_zone->linkage,
+ efx_tc_ct_zone_ht_params);
+ if (old) {
+ /* don't need our new entry */
+ kfree(ct_zone);
+ if (!refcount_inc_not_zero(&old->ref))
+ return ERR_PTR(-EAGAIN);
+ /* existing entry found */
+ WARN_ON_ONCE(old->nf_ft != ct_ft);
+ netif_dbg(efx, drv, efx->net_dev,
+ "Found existing ct_zone for %u\n", zone);
+ return old;
+ }
+ ct_zone->nf_ft = ct_ft;
+ ct_zone->efx = efx;
+ INIT_LIST_HEAD(&ct_zone->cts);
+ mutex_init(&ct_zone->mutex);
+ rc = nf_flow_table_offload_add_cb(ct_ft, efx_tc_flow_block, ct_zone);
+ netif_dbg(efx, drv, efx->net_dev, "Adding new ct_zone for %u, rc %d\n",
+ zone, rc);
+ if (rc < 0)
+ goto fail;
+ refcount_set(&ct_zone->ref, 1);
+ return ct_zone;
+fail:
+ rhashtable_remove_fast(&efx->tc->ct_zone_ht, &ct_zone->linkage,
+ efx_tc_ct_zone_ht_params);
+ kfree(ct_zone);
+ return ERR_PTR(rc);
+}
+
+void efx_tc_ct_unregister_zone(struct efx_nic *efx,
+ struct efx_tc_ct_zone *ct_zone)
+{
+ struct efx_tc_ct_entry *conn, *next;
+
+ if (!refcount_dec_and_test(&ct_zone->ref))
+ return; /* still in use */
+ nf_flow_table_offload_del_cb(ct_zone->nf_ft, efx_tc_flow_block, ct_zone);
+ rhashtable_remove_fast(&efx->tc->ct_zone_ht, &ct_zone->linkage,
+ efx_tc_ct_zone_ht_params);
+ mutex_lock(&ct_zone->mutex);
+ list_for_each_entry(conn, &ct_zone->cts, list)
+ efx_tc_ct_remove(efx, conn);
+ synchronize_rcu();
+ /* need to use _safe because efx_tc_ct_remove_finish() frees conn */
+ list_for_each_entry_safe(conn, next, &ct_zone->cts, list)
+ efx_tc_ct_remove_finish(efx, conn);
+ mutex_unlock(&ct_zone->mutex);
+ mutex_destroy(&ct_zone->mutex);
+ netif_dbg(efx, drv, efx->net_dev, "Removed ct_zone for %u\n",
+ ct_zone->zone);
+ kfree(ct_zone);
+}
diff --git a/drivers/net/ethernet/sfc/tc_conntrack.h b/drivers/net/ethernet/sfc/tc_conntrack.h
new file mode 100644
index 000000000000..e75c8eb1965d
--- /dev/null
+++ b/drivers/net/ethernet/sfc/tc_conntrack.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2023, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_TC_CONNTRACK_H
+#define EFX_TC_CONNTRACK_H
+#include "net_driver.h"
+
+#if IS_ENABLED(CONFIG_SFC_SRIOV)
+#include <linux/refcount.h>
+#include <net/netfilter/nf_flow_table.h>
+
+struct efx_tc_ct_zone {
+ u16 zone;
+ struct rhash_head linkage;
+ refcount_t ref;
+ struct nf_flowtable *nf_ft;
+ struct efx_nic *efx;
+ struct mutex mutex; /* protects cts list */
+ struct list_head cts; /* list of efx_tc_ct_entry in this zone */
+};
+
+/* create/uncreate/teardown hashtables */
+int efx_tc_init_conntrack(struct efx_nic *efx);
+void efx_tc_destroy_conntrack(struct efx_nic *efx);
+void efx_tc_fini_conntrack(struct efx_nic *efx);
+
+struct efx_tc_ct_zone *efx_tc_ct_register_zone(struct efx_nic *efx, u16 zone,
+ struct nf_flowtable *ct_ft);
+void efx_tc_ct_unregister_zone(struct efx_nic *efx,
+ struct efx_tc_ct_zone *ct_zone);
+
+struct efx_tc_ct_entry {
+ unsigned long cookie;
+ struct rhash_head linkage;
+ __be16 eth_proto;
+ u8 ip_proto;
+ bool dnat;
+ __be32 src_ip, dst_ip, nat_ip;
+ struct in6_addr src_ip6, dst_ip6;
+ __be16 l4_sport, l4_dport, l4_natport; /* Ports (UDP, TCP) */
+ struct efx_tc_ct_zone *zone;
+ u32 mark;
+ struct efx_tc_counter *cnt;
+ struct list_head list; /* entry on zone->cts */
+};
+
+#endif /* CONFIG_SFC_SRIOV */
+#endif /* EFX_TC_CONNTRACK_H */
diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
index 979f49058a0c..0fafb47ea082 100644
--- a/drivers/net/ethernet/sfc/tc_counters.c
+++ b/drivers/net/ethernet/sfc/tc_counters.c
@@ -129,8 +129,8 @@ static void efx_tc_counter_work(struct work_struct *work)
/* Counter allocation */
-static struct efx_tc_counter *efx_tc_flower_allocate_counter(struct efx_nic *efx,
- int type)
+struct efx_tc_counter *efx_tc_flower_allocate_counter(struct efx_nic *efx,
+ int type)
{
struct efx_tc_counter *cnt;
int rc, rc2;
@@ -169,8 +169,8 @@ fail1:
return ERR_PTR(rc > 0 ? -EIO : rc);
}
-static void efx_tc_flower_release_counter(struct efx_nic *efx,
- struct efx_tc_counter *cnt)
+void efx_tc_flower_release_counter(struct efx_nic *efx,
+ struct efx_tc_counter *cnt)
{
int rc;
diff --git a/drivers/net/ethernet/sfc/tc_counters.h b/drivers/net/ethernet/sfc/tc_counters.h
index 41e57f34b763..f18d71c13600 100644
--- a/drivers/net/ethernet/sfc/tc_counters.h
+++ b/drivers/net/ethernet/sfc/tc_counters.h
@@ -49,6 +49,10 @@ int efx_tc_init_counters(struct efx_nic *efx);
void efx_tc_destroy_counters(struct efx_nic *efx);
void efx_tc_fini_counters(struct efx_nic *efx);
+struct efx_tc_counter *efx_tc_flower_allocate_counter(struct efx_nic *efx,
+ int type);
+void efx_tc_flower_release_counter(struct efx_nic *efx,
+ struct efx_tc_counter *cnt);
struct efx_tc_counter_index *efx_tc_flower_get_counter_index(
struct efx_nic *efx, unsigned long cookie,
enum efx_tc_counter_type type);
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 4ed4082836a9..fe2d476028e7 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -517,13 +517,8 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
unsigned index, type;
EFX_WARN_ON_PARANOID(!netif_device_present(net_dev));
-
index = skb_get_queue_mapping(skb);
type = efx_tx_csum_type_skb(skb);
- if (index >= efx->n_tx_channels) {
- index -= efx->n_tx_channels;
- type |= EFX_TXQ_TYPE_HIGHPRI;
- }
/* PTP "event" packet */
if (unlikely(efx_xmit_with_hwtstamp(skb)) &&
@@ -603,43 +598,5 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
/* Must be inverse of queue lookup in efx_hard_start_xmit() */
tx_queue->core_txq =
netdev_get_tx_queue(efx->net_dev,
- tx_queue->channel->channel +
- ((tx_queue->type & EFX_TXQ_TYPE_HIGHPRI) ?
- efx->n_tx_channels : 0));
-}
-
-int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
- void *type_data)
-{
- struct efx_nic *efx = efx_netdev_priv(net_dev);
- struct tc_mqprio_qopt *mqprio = type_data;
- unsigned tc, num_tc;
-
- if (type != TC_SETUP_QDISC_MQPRIO)
- return -EOPNOTSUPP;
-
- /* Only Siena supported highpri queues */
- if (efx_nic_rev(efx) > EFX_REV_SIENA_A0)
- return -EOPNOTSUPP;
-
- num_tc = mqprio->num_tc;
-
- if (num_tc > EFX_MAX_TX_TC)
- return -EINVAL;
-
- mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
-
- if (num_tc == net_dev->num_tc)
- return 0;
-
- for (tc = 0; tc < num_tc; tc++) {
- net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels;
- net_dev->tc_to_txq[tc].count = efx->n_tx_channels;
- }
-
- net_dev->num_tc = num_tc;
-
- return netif_set_real_num_tx_queues(net_dev,
- max_t(int, num_tc, 1) *
- efx->n_tx_channels);
+ tx_queue->channel->channel);
}
diff --git a/drivers/net/ethernet/sfc/tx_tso.c b/drivers/net/ethernet/sfc/tx_tso.c
index d381d8164f07..64a6768f75ea 100644
--- a/drivers/net/ethernet/sfc/tx_tso.c
+++ b/drivers/net/ethernet/sfc/tx_tso.c
@@ -85,7 +85,7 @@ static inline void prefetch_ptr(struct efx_tx_queue *tx_queue)
prefetch(ptr);
prefetch(ptr + 0x80);
- ptr = (char *) (((efx_qword_t *)tx_queue->txd.buf.addr) + insert_ptr);
+ ptr = (char *)(((efx_qword_t *)tx_queue->txd.addr) + insert_ptr);
prefetch(ptr);
prefetch(ptr + 0x80);
}
diff --git a/drivers/net/ethernet/sfc/vfdi.h b/drivers/net/ethernet/sfc/vfdi.h
deleted file mode 100644
index 480b872eb4d1..000000000000
--- a/drivers/net/ethernet/sfc/vfdi.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/****************************************************************************
- * Driver for Solarflare network controllers and boards
- * Copyright 2010-2012 Solarflare Communications Inc.
- */
-#ifndef _VFDI_H
-#define _VFDI_H
-
-/**
- * DOC: Virtual Function Driver Interface
- *
- * This file contains software structures used to form a two way
- * communication channel between the VF driver and the PF driver,
- * named Virtual Function Driver Interface (VFDI).
- *
- * For the purposes of VFDI, a page is a memory region with size and
- * alignment of 4K. All addresses are DMA addresses to be used within
- * the domain of the relevant VF.
- *
- * The only hardware-defined channels for a VF driver to communicate
- * with the PF driver are the event mailboxes (%FR_CZ_USR_EV
- * registers). Writing to these registers generates an event with
- * EV_CODE = EV_CODE_USR_EV, USER_QID set to the index of the mailbox
- * and USER_EV_REG_VALUE set to the value written. The PF driver may
- * direct or disable delivery of these events by setting
- * %FR_CZ_USR_EV_CFG.
- *
- * The PF driver can send arbitrary events to arbitrary event queues.
- * However, for consistency, VFDI events from the PF are defined to
- * follow the same form and be sent to the first event queue assigned
- * to the VF while that queue is enabled by the VF driver.
- *
- * The general form of the variable bits of VFDI events is:
- *
- * 0 16 24 31
- * | DATA | TYPE | SEQ |
- *
- * SEQ is a sequence number which should be incremented by 1 (modulo
- * 256) for each event. The sequence numbers used in each direction
- * are independent.
- *
- * The VF submits requests of type &struct vfdi_req by sending the
- * address of the request (ADDR) in a series of 4 events:
- *
- * 0 16 24 31
- * | ADDR[0:15] | VFDI_EV_TYPE_REQ_WORD0 | SEQ |
- * | ADDR[16:31] | VFDI_EV_TYPE_REQ_WORD1 | SEQ+1 |
- * | ADDR[32:47] | VFDI_EV_TYPE_REQ_WORD2 | SEQ+2 |
- * | ADDR[48:63] | VFDI_EV_TYPE_REQ_WORD3 | SEQ+3 |
- *
- * The address must be page-aligned. After receiving such a valid
- * series of events, the PF driver will attempt to read the request
- * and write a response to the same address. In case of an invalid
- * sequence of events or a DMA error, there will be no response.
- *
- * The VF driver may request that the PF driver writes status
- * information into its domain asynchronously. After writing the
- * status, the PF driver will send an event of the form:
- *
- * 0 16 24 31
- * | reserved | VFDI_EV_TYPE_STATUS | SEQ |
- *
- * In case the VF must be reset for any reason, the PF driver will
- * send an event of the form:
- *
- * 0 16 24 31
- * | reserved | VFDI_EV_TYPE_RESET | SEQ |
- *
- * It is then the responsibility of the VF driver to request
- * reinitialisation of its queues.
- */
-#define VFDI_EV_SEQ_LBN 24
-#define VFDI_EV_SEQ_WIDTH 8
-#define VFDI_EV_TYPE_LBN 16
-#define VFDI_EV_TYPE_WIDTH 8
-#define VFDI_EV_TYPE_REQ_WORD0 0
-#define VFDI_EV_TYPE_REQ_WORD1 1
-#define VFDI_EV_TYPE_REQ_WORD2 2
-#define VFDI_EV_TYPE_REQ_WORD3 3
-#define VFDI_EV_TYPE_STATUS 4
-#define VFDI_EV_TYPE_RESET 5
-#define VFDI_EV_DATA_LBN 0
-#define VFDI_EV_DATA_WIDTH 16
-
-struct vfdi_endpoint {
- u8 mac_addr[ETH_ALEN];
- __be16 tci;
-};
-
-/**
- * enum vfdi_op - VFDI operation enumeration
- * @VFDI_OP_RESPONSE: Indicates a response to the request.
- * @VFDI_OP_INIT_EVQ: Initialize SRAM entries and initialize an EVQ.
- * @VFDI_OP_INIT_RXQ: Initialize SRAM entries and initialize an RXQ.
- * @VFDI_OP_INIT_TXQ: Initialize SRAM entries and initialize a TXQ.
- * @VFDI_OP_FINI_ALL_QUEUES: Flush all queues, finalize all queues, then
- * finalize the SRAM entries.
- * @VFDI_OP_INSERT_FILTER: Insert a MAC filter targeting the given RXQ.
- * @VFDI_OP_REMOVE_ALL_FILTERS: Remove all filters.
- * @VFDI_OP_SET_STATUS_PAGE: Set the DMA page(s) used for status updates
- * from PF and write the initial status.
- * @VFDI_OP_CLEAR_STATUS_PAGE: Clear the DMA page(s) used for status
- * updates from PF.
- */
-enum vfdi_op {
- VFDI_OP_RESPONSE = 0,
- VFDI_OP_INIT_EVQ = 1,
- VFDI_OP_INIT_RXQ = 2,
- VFDI_OP_INIT_TXQ = 3,
- VFDI_OP_FINI_ALL_QUEUES = 4,
- VFDI_OP_INSERT_FILTER = 5,
- VFDI_OP_REMOVE_ALL_FILTERS = 6,
- VFDI_OP_SET_STATUS_PAGE = 7,
- VFDI_OP_CLEAR_STATUS_PAGE = 8,
- VFDI_OP_LIMIT,
-};
-
-/* Response codes for VFDI operations. Other values may be used in future. */
-#define VFDI_RC_SUCCESS 0
-#define VFDI_RC_ENOMEM (-12)
-#define VFDI_RC_EINVAL (-22)
-#define VFDI_RC_EOPNOTSUPP (-95)
-#define VFDI_RC_ETIMEDOUT (-110)
-
-/**
- * struct vfdi_req - Request from VF driver to PF driver
- * @op: Operation code or response indicator, taken from &enum vfdi_op.
- * @rc: Response code. Set to 0 on success or a negative error code on failure.
- * @u.init_evq.index: Index of event queue to create.
- * @u.init_evq.buf_count: Number of 4k buffers backing event queue.
- * @u.init_evq.addr: Array of length %u.init_evq.buf_count containing DMA
- * address of each page backing the event queue.
- * @u.init_rxq.index: Index of receive queue to create.
- * @u.init_rxq.buf_count: Number of 4k buffers backing receive queue.
- * @u.init_rxq.evq: Instance of event queue to target receive events at.
- * @u.init_rxq.label: Label used in receive events.
- * @u.init_rxq.flags: Unused.
- * @u.init_rxq.addr: Array of length %u.init_rxq.buf_count containing DMA
- * address of each page backing the receive queue.
- * @u.init_txq.index: Index of transmit queue to create.
- * @u.init_txq.buf_count: Number of 4k buffers backing transmit queue.
- * @u.init_txq.evq: Instance of event queue to target transmit completion
- * events at.
- * @u.init_txq.label: Label used in transmit completion events.
- * @u.init_txq.flags: Checksum offload flags.
- * @u.init_txq.addr: Array of length %u.init_txq.buf_count containing DMA
- * address of each page backing the transmit queue.
- * @u.mac_filter.rxq: Insert MAC filter at VF local address/VLAN targeting
- * all traffic at this receive queue.
- * @u.mac_filter.flags: MAC filter flags.
- * @u.set_status_page.dma_addr: Base address for the &struct vfdi_status.
- * This address must be page-aligned and the PF may write up to a
- * whole page (allowing for extension of the structure).
- * @u.set_status_page.peer_page_count: Number of additional pages the VF
- * has provided into which peer addresses may be DMAd.
- * @u.set_status_page.peer_page_addr: Array of DMA addresses of pages.
- * If the number of peers exceeds 256, then the VF must provide
- * additional pages in this array. The PF will then DMA up to
- * 512 vfdi_endpoint structures into each page. These addresses
- * must be page-aligned.
- */
-struct vfdi_req {
- u32 op;
- u32 reserved1;
- s32 rc;
- u32 reserved2;
- union {
- struct {
- u32 index;
- u32 buf_count;
- u64 addr[];
- } init_evq;
- struct {
- u32 index;
- u32 buf_count;
- u32 evq;
- u32 label;
- u32 flags;
-#define VFDI_RXQ_FLAG_SCATTER_EN 1
- u32 reserved;
- u64 addr[];
- } init_rxq;
- struct {
- u32 index;
- u32 buf_count;
- u32 evq;
- u32 label;
- u32 flags;
-#define VFDI_TXQ_FLAG_IP_CSUM_DIS 1
-#define VFDI_TXQ_FLAG_TCPUDP_CSUM_DIS 2
- u32 reserved;
- u64 addr[];
- } init_txq;
- struct {
- u32 rxq;
- u32 flags;
-#define VFDI_MAC_FILTER_FLAG_RSS 1
-#define VFDI_MAC_FILTER_FLAG_SCATTER 2
- } mac_filter;
- struct {
- u64 dma_addr;
- u64 peer_page_count;
- u64 peer_page_addr[];
- } set_status_page;
- } u;
-};
-
-/**
- * struct vfdi_status - Status provided by PF driver to VF driver
- * @generation_start: A generation count DMA'd to VF *before* the
- * rest of the structure.
- * @generation_end: A generation count DMA'd to VF *after* the
- * rest of the structure.
- * @version: Version of this structure; currently set to 1. Later
- * versions must either be layout-compatible or only be sent to VFs
- * that specifically request them.
- * @length: Total length of this structure including embedded tables
- * @vi_scale: log2 the number of VIs available on this VF. This quantity
- * is used by the hardware for register decoding.
- * @max_tx_channels: The maximum number of transmit queues the VF can use.
- * @rss_rxq_count: The number of receive queues present in the shared RSS
- * indirection table.
- * @peer_count: Total number of peers in the complete peer list. If larger
- * than ARRAY_SIZE(%peers), then the VF must provide sufficient
- * additional pages each of which is filled with vfdi_endpoint structures.
- * @local: The MAC address and outer VLAN tag of *this* VF
- * @peers: Table of peer addresses. The @tci fields in these structures
- * are currently unused and must be ignored. Additional peers are
- * written into any additional pages provided by the VF.
- * @timer_quantum_ns: Timer quantum (nominal period between timer ticks)
- * for interrupt moderation timers, in nanoseconds. This member is only
- * present if @length is sufficiently large.
- */
-struct vfdi_status {
- u32 generation_start;
- u32 generation_end;
- u32 version;
- u32 length;
- u8 vi_scale;
- u8 max_tx_channels;
- u8 rss_rxq_count;
- u8 reserved1;
- u16 peer_count;
- u16 reserved2;
- struct vfdi_endpoint local;
- struct vfdi_endpoint peers[256];
-
- /* Members below here extend version 1 of this structure */
- u32 timer_quantum_ns;
-};
-
-#endif
diff --git a/drivers/net/ethernet/sfc/workarounds.h b/drivers/net/ethernet/sfc/workarounds.h
index 815be2d20c4b..e10e7f84958d 100644
--- a/drivers/net/ethernet/sfc/workarounds.h
+++ b/drivers/net/ethernet/sfc/workarounds.h
@@ -12,14 +12,7 @@
* Bug numbers are from Solarflare's Bugzilla.
*/
-#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0)
#define EFX_WORKAROUND_EF10(efx) (efx_nic_rev(efx) >= EFX_REV_HUNT_A0)
-#define EFX_WORKAROUND_10G(efx) 1
-
-/* Bit-bashed I2C reads cause performance drop */
-#define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G
-/* Legacy interrupt storm when interrupt fifo fills */
-#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
/* Lockup when writing event block registers at gen2/gen3 */
#define EFX_EF10_WORKAROUND_35388(efx) \
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 174dc8908b72..cb590db625e8 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -43,7 +43,6 @@
#include <linux/smsc911x.h>
#include <linux/device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
#include <linux/acpi.h>
@@ -552,7 +551,7 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata,
/* Get a phy register */
static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
{
- struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+ struct smsc911x_data *pdata = bus->priv;
unsigned long flags;
unsigned int addr;
int i, reg;
@@ -591,7 +590,7 @@ out:
static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
u16 val)
{
- struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+ struct smsc911x_data *pdata = bus->priv;
unsigned long flags;
unsigned int addr;
int i, reg;
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index 71fbb358bb7d..e1c4a11c1f18 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -102,7 +102,7 @@ static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd)
static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
{
- struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+ struct smsc9420_pdata *pd = bus->priv;
unsigned long flags;
u32 addr;
int i, reg = -EIO;
@@ -140,7 +140,7 @@ out:
static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
u16 val)
{
- struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+ struct smsc9420_pdata *pd = bus->priv;
unsigned long flags;
u32 addr;
int i, reg = -EIO;
@@ -1144,8 +1144,7 @@ static int smsc9420_mii_init(struct net_device *dev)
goto err_out_1;
}
pd->mii_bus->name = DRV_MDIONAME;
- snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x",
- (pd->pdev->bus->number << 8) | pd->pdev->devfn);
+ snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(pd->pdev));
pd->mii_bus->priv = pd;
pd->mii_bus->read = smsc9420_mii_read;
pd->mii_bus->write = smsc9420_mii_write;
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index 0dcd6a568b06..f358ea003193 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -15,7 +15,7 @@
#include <linux/bpf_trace.h>
#include <net/tcp.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/ip6_checksum.h>
#define NETSEC_REG_SOFT_RST 0x104
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
index 492c39c08af1..4838d2383a43 100644
--- a/drivers/net/ethernet/socionext/sni_ave.c
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -15,10 +15,11 @@
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
-#include <linux/of_platform.h>
#include <linux/phy.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/types.h>
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 5583f0b055ec..06c6871f8788 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -121,17 +121,6 @@ config DWMAC_MESON
the stmmac device driver. This driver is used for Meson6,
Meson8, Meson8b and GXBB SoCs.
-config DWMAC_OXNAS
- tristate "Oxford Semiconductor OXNAS dwmac support"
- default ARCH_OXNAS
- depends on OF && COMMON_CLK && (ARCH_OXNAS || COMPILE_TEST)
- select MFD_SYSCON
- help
- Support for Ethernet controller on Oxford Semiconductor OXNAS SoCs.
-
- This selects the Oxford Semiconductor OXNASSoC glue layer support for
- the stmmac device driver. This driver is used for OX820.
-
config DWMAC_QCOM_ETHQOS
tristate "Qualcomm ETHQOS support"
default ARCH_QCOM
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 7dd3d388068b..5b57aee19267 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
-obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 16e67c18b6f7..403cb397d4d3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -35,6 +35,7 @@
#define DWMAC_CORE_5_10 0x51
#define DWMAC_CORE_5_20 0x52
#define DWXGMAC_CORE_2_10 0x21
+#define DWXGMAC_CORE_2_20 0x22
#define DWXLGMAC_CORE_2_00 0x20
/* Device ID */
@@ -59,13 +60,25 @@
/* #define FRAME_FILTER_DEBUG */
struct stmmac_txq_stats {
- unsigned long tx_pkt_n;
- unsigned long tx_normal_irq_n;
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_pkt_n;
+ u64 tx_normal_irq_n;
+ u64 napi_poll;
+ u64 tx_clean;
+ u64 tx_set_ic_bit;
+ u64 tx_tso_frames;
+ u64 tx_tso_nfrags;
+ struct u64_stats_sync syncp;
};
struct stmmac_rxq_stats {
- unsigned long rx_pkt_n;
- unsigned long rx_normal_irq_n;
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_pkt_n;
+ u64 rx_normal_irq_n;
+ u64 napi_poll;
+ struct u64_stats_sync syncp;
};
/* Extra statistic and debug information exposed by ethtool */
@@ -81,6 +94,7 @@ struct stmmac_extra_stats {
unsigned long tx_frame_flushed;
unsigned long tx_payload_error;
unsigned long tx_ip_header_error;
+ unsigned long tx_collision;
/* Receive errors */
unsigned long rx_desc;
unsigned long sa_filter_fail;
@@ -113,14 +127,6 @@ struct stmmac_extra_stats {
/* Tx/Rx IRQ Events */
unsigned long rx_early_irq;
unsigned long threshold;
- unsigned long tx_pkt_n;
- unsigned long rx_pkt_n;
- unsigned long normal_irq_n;
- unsigned long rx_normal_irq_n;
- unsigned long napi_poll;
- unsigned long tx_normal_irq_n;
- unsigned long tx_clean;
- unsigned long tx_set_ic_bit;
unsigned long irq_receive_pmt_irq_n;
/* MMC info */
unsigned long mmc_tx_irq_n;
@@ -190,18 +196,16 @@ struct stmmac_extra_stats {
unsigned long mtl_rx_fifo_ctrl_active;
unsigned long mac_rx_frame_ctrl_fifo;
unsigned long mac_gmii_rx_proto_engine;
- /* TSO */
- unsigned long tx_tso_frames;
- unsigned long tx_tso_nfrags;
/* EST */
unsigned long mtl_est_cgce;
unsigned long mtl_est_hlbs;
unsigned long mtl_est_hlbf;
unsigned long mtl_est_btre;
unsigned long mtl_est_btrlm;
- /* per queue statistics */
- struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
- struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
+ unsigned long rx_dropped;
+ unsigned long rx_errors;
+ unsigned long tx_dropped;
+ unsigned long tx_errors;
};
/* Safety Feature statistics exposed by ethtool */
@@ -406,6 +410,18 @@ struct dma_features {
unsigned int number_tx_queues;
/* PPS output */
unsigned int pps_out_num;
+ /* Number of Traffic Classes */
+ unsigned int numtc;
+ /* DCB Feature Enable */
+ unsigned int dcben;
+ /* IEEE 1588 High Word Register Enable */
+ unsigned int advthword;
+ /* PTP Offload Enable */
+ unsigned int ptoen;
+ /* One-Step Timestamping Enable */
+ unsigned int osten;
+ /* Priority-Based Flow Control Enable */
+ unsigned int pfcen;
/* Alternate (enhanced) DESC mode */
unsigned int enh_desc;
/* TX and RX FIFO sizes */
@@ -426,14 +442,40 @@ struct dma_features {
unsigned int dvlan;
unsigned int l3l4fnum;
unsigned int arpoffsel;
+ /* One Step for PTP over UDP/IP Feature Enable */
+ unsigned int pou_ost_en;
+ /* Tx Timestamp FIFO Depth */
+ unsigned int ttsfd;
+ /* Queue/Channel-Based VLAN tag insertion on Tx */
+ unsigned int cbtisel;
+ /* Supported Parallel Instruction Processor Engines */
+ unsigned int frppipe_num;
+ /* Number of Extended VLAN Tag Filters */
+ unsigned int nrvf_num;
/* TSN Features */
unsigned int estwid;
unsigned int estdep;
unsigned int estsel;
unsigned int fpesel;
unsigned int tbssel;
+ /* Number of DMA channels enabled for TBS */
+ unsigned int tbs_ch_num;
+ /* Per-Stream Filtering Enable */
+ unsigned int sgfsel;
/* Numbers of Auxiliary Snapshot Inputs */
unsigned int aux_snapshot_n;
+ /* Timestamp System Time Source */
+ unsigned int tssrc;
+ /* Enhanced DMA Enable */
+ unsigned int edma;
+ /* Different Descriptor Cache Enable */
+ unsigned int ediffc;
+ /* VxLAN/NVGRE Enable */
+ unsigned int vxn;
+ /* Debug Memory Interface Enable */
+ unsigned int dbgmem;
+ /* Number of Policing Counters */
+ unsigned int pcsel;
};
/* RX Buffer size must be multiple of 4/8/16 bytes */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
index 9f88530c5e8c..61ebf36da13d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
@@ -14,7 +14,7 @@
#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
@@ -113,7 +113,7 @@ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
/* dwc-qos needs GMAC4, AAL, TSO and PMT */
plat_dat->has_gmac4 = 1;
plat_dat->dma_cfg->aal = 1;
- plat_dat->tso_en = 1;
+ plat_dat->flags |= STMMAC_FLAG_TSO_EN;
plat_dat->pmt = 1;
return 0;
@@ -178,7 +178,7 @@ static void dwc_qos_remove(struct platform_device *pdev)
#define AUTO_CAL_STATUS 0x880c
#define AUTO_CAL_STATUS_ACTIVE BIT(31)
-static void tegra_eqos_fix_speed(void *priv, unsigned int speed)
+static void tegra_eqos_fix_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct tegra_eqos *eqos = priv;
unsigned long rate = 125000000;
@@ -359,7 +359,7 @@ bypass_clk_reset_gpio:
data->fix_mac_speed = tegra_eqos_fix_speed;
data->init = tegra_eqos_init;
data->bsp_priv = eqos;
- data->sph_disable = 1;
+ data->flags |= STMMAC_FLAG_SPH_DISABLE;
err = tegra_eqos_init(pdev, eqos);
if (err < 0)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
index b9378a63f0e8..df34e34cc14f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
@@ -12,7 +12,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
@@ -32,6 +31,7 @@
#define GPR_ENET_QOS_RGMII_EN (0x1 << 21)
#define MX93_GPR_ENET_QOS_INTF_MODE_MASK GENMASK(3, 0)
+#define MX93_GPR_ENET_QOS_INTF_MASK GENMASK(3, 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_MII (0x0 << 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 1)
@@ -40,13 +40,16 @@
#define DMA_BUS_MODE 0x00001000
#define DMA_BUS_MODE_SFT_RESET (0x1 << 0)
#define RMII_RESET_SPEED (0x3 << 14)
+#define CTRL_SPEED_MASK GENMASK(15, 14)
struct imx_dwmac_ops {
u32 addr_width;
+ u32 flags;
bool mac_rgmii_txclk_auto_adj;
int (*fix_soc_reset)(void *priv, void __iomem *ioaddr);
int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);
+ void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode);
};
struct imx_priv_data {
@@ -56,6 +59,7 @@ struct imx_priv_data {
struct regmap *intf_regmap;
u32 intf_reg_off;
bool rmii_refclk_ext;
+ void __iomem *base_addr;
const struct imx_dwmac_ops *ops;
struct plat_stmmacenet_data *plat_dat;
@@ -66,7 +70,7 @@ static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
struct imx_priv_data *dwmac = plat_dat->bsp_priv;
int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
val = GPR_ENET_QOS_INTF_SEL_MII;
break;
@@ -83,7 +87,7 @@ static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
pr_debug("imx dwmac doesn't support %d interface\n",
- plat_dat->interface);
+ plat_dat->mac_interface);
return -EINVAL;
}
@@ -106,7 +110,7 @@ static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
struct imx_priv_data *dwmac = plat_dat->bsp_priv;
int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
val = MX93_GPR_ENET_QOS_INTF_SEL_MII;
break;
@@ -121,7 +125,7 @@ static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
dev_dbg(dwmac->dev, "imx dwmac doesn't support %d interface\n",
- plat_dat->interface);
+ plat_dat->mac_interface);
return -EINVAL;
}
@@ -178,7 +182,7 @@ static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
/* nothing to do now */
}
-static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
+static void imx_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct plat_stmmacenet_data *plat_dat;
struct imx_priv_data *dwmac = priv;
@@ -188,8 +192,8 @@ static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
plat_dat = dwmac->plat_dat;
if (dwmac->ops->mac_rgmii_txclk_auto_adj ||
- (plat_dat->interface == PHY_INTERFACE_MODE_RMII) ||
- (plat_dat->interface == PHY_INTERFACE_MODE_MII))
+ (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) ||
+ (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII))
return;
switch (speed) {
@@ -212,6 +216,41 @@ static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
}
+static void imx93_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
+{
+ struct imx_priv_data *dwmac = priv;
+ unsigned int iface;
+ int ctrl, old_ctrl;
+
+ imx_dwmac_fix_speed(priv, speed, mode);
+
+ if (!dwmac || mode != MLO_AN_FIXED)
+ return;
+
+ if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface))
+ return;
+
+ iface &= MX93_GPR_ENET_QOS_INTF_MASK;
+ if (iface != MX93_GPR_ENET_QOS_INTF_SEL_RGMII)
+ return;
+
+ old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG);
+ ctrl = old_ctrl & ~CTRL_SPEED_MASK;
+ regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
+ MX93_GPR_ENET_QOS_INTF_MODE_MASK, 0);
+ writel(ctrl, dwmac->base_addr + MAC_CTRL_REG);
+
+ /* Ensure the settings for CTRL are applied. */
+ readl(dwmac->base_addr + MAC_CTRL_REG);
+
+ usleep_range(10, 20);
+ iface |= MX93_GPR_ENET_QOS_CLK_GEN_EN;
+ regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
+ MX93_GPR_ENET_QOS_INTF_MODE_MASK, iface);
+
+ writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG);
+}
+
static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr)
{
struct plat_stmmacenet_data *plat_dat = priv;
@@ -221,7 +260,7 @@ static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr)
value |= DMA_BUS_MODE_SFT_RESET;
writel(value, ioaddr + DMA_BUS_MODE);
- if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) {
+ if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) {
usleep_range(100, 200);
writel(RMII_RESET_SPEED, ioaddr + MAC_CTRL_REG);
}
@@ -312,6 +351,9 @@ static int imx_dwmac_probe(struct platform_device *pdev)
goto err_parse_dt;
}
+ if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
+ plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
+
plat_dat->host_dma_width = dwmac->ops->addr_width;
plat_dat->init = imx_dwmac_init;
plat_dat->exit = imx_dwmac_exit;
@@ -319,6 +361,7 @@ static int imx_dwmac_probe(struct platform_device *pdev)
plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
plat_dat->bsp_priv = dwmac;
dwmac->plat_dat = plat_dat;
+ dwmac->base_addr = stmmac_res.addr;
ret = imx_dwmac_clks_config(dwmac, true);
if (ret)
@@ -328,6 +371,8 @@ static int imx_dwmac_probe(struct platform_device *pdev)
if (ret)
goto err_dwmac_init;
+ if (dwmac->ops->fix_mac_speed)
+ plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed;
dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
@@ -351,6 +396,7 @@ static struct imx_dwmac_ops imx8mp_dwmac_data = {
.addr_width = 34,
.mac_rgmii_txclk_auto_adj = false,
.set_intf_mode = imx8mp_set_intf_mode,
+ .flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY,
};
static struct imx_dwmac_ops imx8dxl_dwmac_data = {
@@ -364,6 +410,7 @@ static struct imx_dwmac_ops imx93_dwmac_data = {
.mac_rgmii_txclk_auto_adj = true,
.set_intf_mode = imx93_set_intf_mode,
.fix_soc_reset = imx_dwmac_mx93_reset,
+ .fix_mac_speed = imx93_dwmac_fix_speed,
};
static const struct of_device_id imx_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
index 8063ba1c3ce8..0a20c3d24722 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
@@ -11,7 +11,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
@@ -90,7 +89,7 @@ static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
struct ingenic_mac *mac = plat_dat->bsp_priv;
unsigned int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);
@@ -119,7 +118,7 @@ static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
- dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
return -EINVAL;
}
@@ -131,13 +130,13 @@ static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
{
struct ingenic_mac *mac = plat_dat->bsp_priv;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_RMII:
dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
break;
default:
- dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
return -EINVAL;
}
@@ -150,14 +149,14 @@ static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
struct ingenic_mac *mac = plat_dat->bsp_priv;
unsigned int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_RMII:
val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
break;
default:
- dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
return -EINVAL;
}
@@ -170,7 +169,7 @@ static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
struct ingenic_mac *mac = plat_dat->bsp_priv;
unsigned int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_RMII:
val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |
FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
@@ -178,7 +177,7 @@ static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
- dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
return -EINVAL;
}
@@ -191,7 +190,7 @@ static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
struct ingenic_mac *mac = plat_dat->bsp_priv;
unsigned int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_RMII:
val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |
FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |
@@ -221,7 +220,7 @@ static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
- dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
+ dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
index a5e639ab0b9e..d352a14f9d48 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
@@ -22,13 +22,13 @@ struct intel_dwmac {
};
struct intel_dwmac_data {
- void (*fix_mac_speed)(void *priv, unsigned int speed);
+ void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode);
unsigned long ptp_ref_clk_rate;
unsigned long tx_clk_rate;
bool tx_clk_en;
};
-static void kmb_eth_fix_mac_speed(void *priv, unsigned int speed)
+static void kmb_eth_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct intel_dwmac *dwmac = priv;
unsigned long rate;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index ab9f876b6df7..a3a249c63598 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -257,9 +257,8 @@ static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
/* Program PTP Clock Frequency for different variant of
* Intel mGBE that has slightly different GPO mapping
*/
-static void intel_mgbe_ptp_clk_freq_config(void *npriv)
+static void intel_mgbe_ptp_clk_freq_config(struct stmmac_priv *priv)
{
- struct stmmac_priv *priv = (struct stmmac_priv *)npriv;
struct intel_priv_data *intel_priv;
u32 gpio_value;
@@ -326,10 +325,10 @@ static int intel_crosststamp(ktime_t *device,
/* Both internal crosstimestamping and external triggered event
* timestamping cannot be run concurrently.
*/
- if (priv->plat->ext_snapshot_en)
+ if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN)
return -EBUSY;
- priv->plat->int_snapshot_en = 1;
+ priv->plat->flags |= STMMAC_FLAG_INT_SNAPSHOT_EN;
mutex_lock(&priv->aux_ts_lock);
/* Enable Internal snapshot trigger */
@@ -350,7 +349,7 @@ static int intel_crosststamp(ktime_t *device,
break;
default:
mutex_unlock(&priv->aux_ts_lock);
- priv->plat->int_snapshot_en = 0;
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
return -EINVAL;
}
writel(acr_value, ptpaddr + PTP_ACR);
@@ -376,7 +375,7 @@ static int intel_crosststamp(ktime_t *device,
if (!wait_event_interruptible_timeout(priv->tstamp_busy_wait,
stmmac_cross_ts_isr(priv),
HZ / 100)) {
- priv->plat->int_snapshot_en = 0;
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
return -ETIMEDOUT;
}
@@ -395,7 +394,7 @@ static int intel_crosststamp(ktime_t *device,
}
system->cycles *= intel_priv->crossts_adj;
- priv->plat->int_snapshot_en = 0;
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
return 0;
}
@@ -458,8 +457,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->has_gmac = 0;
plat->has_gmac4 = 1;
plat->force_sf_dma_mode = 0;
- plat->tso_en = 1;
- plat->sph_disable = 1;
+ plat->flags |= (STMMAC_FLAG_TSO_EN | STMMAC_FLAG_SPH_DISABLE);
/* Multiplying factor to the clk_eee_i clock time
* period to make it closer to 100 ns. This value
@@ -561,7 +559,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
/* Set the maxmtu to a default of JUMBO_LEN */
plat->maxmtu = JUMBO_LEN;
- plat->vlan_fail_q_en = true;
+ plat->flags |= STMMAC_FLAG_VLAN_FAIL_Q_EN;
/* Use the last Rx queue */
plat->vlan_fail_q = plat->rx_queues_to_use - 1;
@@ -610,7 +608,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->ext_snapshot_num = AUX_SNAPSHOT0;
plat->crosststamp = intel_crosststamp;
- plat->int_snapshot_en = 0;
+ plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
/* Setup MSI vector offset specific to Intel mGbE controller */
plat->msi_mac_vec = 29;
@@ -628,7 +626,8 @@ static int ehl_common_data(struct pci_dev *pdev,
{
plat->rx_queues_to_use = 8;
plat->tx_queues_to_use = 8;
- plat->use_phy_wol = 1;
+ plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
+ plat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
plat->safety_feat_cfg->tsoee = 1;
plat->safety_feat_cfg->mrxpee = 1;
@@ -954,7 +953,7 @@ static int stmmac_config_single_msi(struct pci_dev *pdev,
res->irq = pci_irq_vector(pdev, 0);
res->wol_irq = res->irq;
- plat->multi_msi_en = 0;
+ plat->flags &= ~STMMAC_FLAG_MULTI_MSI_EN;
dev_info(&pdev->dev, "%s: Single IRQ enablement successful\n",
__func__);
@@ -1006,7 +1005,7 @@ static int stmmac_config_multi_msi(struct pci_dev *pdev,
if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX)
res->sfty_ue_irq = pci_irq_vector(pdev, plat->msi_sfty_ue_vec);
- plat->multi_msi_en = 1;
+ plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
dev_info(&pdev->dev, "%s: multi MSI enablement successful\n", __func__);
return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
index e39406df8516..9b0200749109 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -257,7 +257,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
return PTR_ERR_OR_ZERO(gmac->qsgmii_csr);
}
-static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct ipq806x_gmac *gmac = priv;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
index a25c187d3185..2cd6fce5c993 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c
@@ -117,7 +117,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
}
plat->phy_interface = phy_mode;
- plat->interface = PHY_INTERFACE_MODE_GMII;
+ plat->mac_interface = PHY_INTERFACE_MODE_GMII;
pci_set_master(pdev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
index 18e84ba693a6..d0aa674ce705 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
@@ -50,9 +50,9 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev)
goto err_remove_config_dt;
}
- if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
+ if (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII) {
ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII;
- } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) {
+ } else if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) {
ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
} else {
dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 73c1dfa7ecb1..cd796ec04132 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -7,8 +7,8 @@
#include <linux/mfd/syscon.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 <linux/regmap.h>
#include <linux/stmmac.h>
@@ -587,8 +587,11 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
{
int i;
- plat->interface = priv_plat->phy_mode;
- plat->use_phy_wol = priv_plat->mac_wol ? 0 : 1;
+ 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;
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-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index 7aa5e6bc04eb..959f88c6da16 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -22,7 +22,7 @@ struct meson_dwmac {
void __iomem *reg;
};
-static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct meson_dwmac *dwmac = priv;
unsigned int val;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 92b16048f91c..0b159dc0d5f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c
deleted file mode 100644
index 42954020de2c..000000000000
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c
+++ /dev/null
@@ -1,245 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Oxford Semiconductor OXNAS DWMAC glue layer
- *
- * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
- * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
- * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
- * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/stmmac.h>
-
-#include "stmmac_platform.h"
-
-/* System Control regmap offsets */
-#define OXNAS_DWMAC_CTRL_REGOFFSET 0x78
-#define OXNAS_DWMAC_DELAY_REGOFFSET 0x100
-
-/* Control Register */
-#define DWMAC_CKEN_RX_IN 14
-#define DWMAC_CKEN_RXN_OUT 13
-#define DWMAC_CKEN_RX_OUT 12
-#define DWMAC_CKEN_TX_IN 10
-#define DWMAC_CKEN_TXN_OUT 9
-#define DWMAC_CKEN_TX_OUT 8
-#define DWMAC_RX_SOURCE 7
-#define DWMAC_TX_SOURCE 6
-#define DWMAC_LOW_TX_SOURCE 4
-#define DWMAC_AUTO_TX_SOURCE 3
-#define DWMAC_RGMII 2
-#define DWMAC_SIMPLE_MUX 1
-#define DWMAC_CKEN_GTX 0
-
-/* Delay register */
-#define DWMAC_TX_VARDELAY_SHIFT 0
-#define DWMAC_TXN_VARDELAY_SHIFT 8
-#define DWMAC_RX_VARDELAY_SHIFT 16
-#define DWMAC_RXN_VARDELAY_SHIFT 24
-#define DWMAC_TX_VARDELAY(d) ((d) << DWMAC_TX_VARDELAY_SHIFT)
-#define DWMAC_TXN_VARDELAY(d) ((d) << DWMAC_TXN_VARDELAY_SHIFT)
-#define DWMAC_RX_VARDELAY(d) ((d) << DWMAC_RX_VARDELAY_SHIFT)
-#define DWMAC_RXN_VARDELAY(d) ((d) << DWMAC_RXN_VARDELAY_SHIFT)
-
-struct oxnas_dwmac;
-
-struct oxnas_dwmac_data {
- int (*setup)(struct oxnas_dwmac *dwmac);
-};
-
-struct oxnas_dwmac {
- struct device *dev;
- struct clk *clk;
- struct regmap *regmap;
- const struct oxnas_dwmac_data *data;
-};
-
-static int oxnas_dwmac_setup_ox810se(struct oxnas_dwmac *dwmac)
-{
- unsigned int value;
- int ret;
-
- ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
- if (ret < 0)
- return ret;
-
- /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
- value |= BIT(DWMAC_CKEN_GTX) |
- /* Use simple mux for 25/125 Mhz clock switching */
- BIT(DWMAC_SIMPLE_MUX);
-
- regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
-
- return 0;
-}
-
-static int oxnas_dwmac_setup_ox820(struct oxnas_dwmac *dwmac)
-{
- unsigned int value;
- int ret;
-
- ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
- if (ret < 0)
- return ret;
-
- /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
- value |= BIT(DWMAC_CKEN_GTX) |
- /* Use simple mux for 25/125 Mhz clock switching */
- BIT(DWMAC_SIMPLE_MUX) |
- /* set auto switch tx clock source */
- BIT(DWMAC_AUTO_TX_SOURCE) |
- /* enable tx & rx vardelay */
- BIT(DWMAC_CKEN_TX_OUT) |
- BIT(DWMAC_CKEN_TXN_OUT) |
- BIT(DWMAC_CKEN_TX_IN) |
- BIT(DWMAC_CKEN_RX_OUT) |
- BIT(DWMAC_CKEN_RXN_OUT) |
- BIT(DWMAC_CKEN_RX_IN);
- regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
-
- /* set tx & rx vardelay */
- value = DWMAC_TX_VARDELAY(4) |
- DWMAC_TXN_VARDELAY(2) |
- DWMAC_RX_VARDELAY(10) |
- DWMAC_RXN_VARDELAY(8);
- regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
-
- return 0;
-}
-
-static int oxnas_dwmac_init(struct platform_device *pdev, void *priv)
-{
- struct oxnas_dwmac *dwmac = priv;
- int ret;
-
- /* Reset HW here before changing the glue configuration */
- ret = device_reset(dwmac->dev);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(dwmac->clk);
- if (ret)
- return ret;
-
- ret = dwmac->data->setup(dwmac);
- if (ret)
- clk_disable_unprepare(dwmac->clk);
-
- return ret;
-}
-
-static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv)
-{
- struct oxnas_dwmac *dwmac = priv;
-
- clk_disable_unprepare(dwmac->clk);
-}
-
-static int oxnas_dwmac_probe(struct platform_device *pdev)
-{
- struct plat_stmmacenet_data *plat_dat;
- struct stmmac_resources stmmac_res;
- struct oxnas_dwmac *dwmac;
- int ret;
-
- ret = stmmac_get_platform_resources(pdev, &stmmac_res);
- if (ret)
- return ret;
-
- plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
- if (IS_ERR(plat_dat))
- return PTR_ERR(plat_dat);
-
- dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
- if (!dwmac) {
- ret = -ENOMEM;
- goto err_remove_config_dt;
- }
-
- dwmac->data = (const struct oxnas_dwmac_data *)of_device_get_match_data(&pdev->dev);
- if (!dwmac->data) {
- ret = -EINVAL;
- goto err_remove_config_dt;
- }
-
- dwmac->dev = &pdev->dev;
- plat_dat->bsp_priv = dwmac;
- plat_dat->init = oxnas_dwmac_init;
- plat_dat->exit = oxnas_dwmac_exit;
-
- dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "oxsemi,sys-ctrl");
- if (IS_ERR(dwmac->regmap)) {
- dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
- ret = PTR_ERR(dwmac->regmap);
- goto err_remove_config_dt;
- }
-
- dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
- if (IS_ERR(dwmac->clk)) {
- ret = PTR_ERR(dwmac->clk);
- goto err_remove_config_dt;
- }
-
- ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv);
- if (ret)
- goto err_remove_config_dt;
-
- ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- if (ret)
- goto err_dwmac_exit;
-
-
- return 0;
-
-err_dwmac_exit:
- oxnas_dwmac_exit(pdev, plat_dat->bsp_priv);
-err_remove_config_dt:
- stmmac_remove_config_dt(pdev, plat_dat);
-
- return ret;
-}
-
-static const struct oxnas_dwmac_data ox810se_dwmac_data = {
- .setup = oxnas_dwmac_setup_ox810se,
-};
-
-static const struct oxnas_dwmac_data ox820_dwmac_data = {
- .setup = oxnas_dwmac_setup_ox820,
-};
-
-static const struct of_device_id oxnas_dwmac_match[] = {
- {
- .compatible = "oxsemi,ox810se-dwmac",
- .data = &ox810se_dwmac_data,
- },
- {
- .compatible = "oxsemi,ox820-dwmac",
- .data = &ox820_dwmac_data,
- },
- { }
-};
-MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
-
-static struct platform_driver oxnas_dwmac_driver = {
- .probe = oxnas_dwmac_probe,
- .remove_new = stmmac_pltfr_remove,
- .driver = {
- .name = "oxnas-dwmac",
- .pm = &stmmac_pltfr_pm_ops,
- .of_match_table = oxnas_dwmac_match,
- },
-};
-module_platform_driver(oxnas_dwmac_driver);
-
-MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
-MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index e62940414e54..d3bf42d0fceb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -3,11 +3,10 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_net.h>
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
-#include <linux/property.h>
#include "stmmac.h"
#include "stmmac_platform.h"
@@ -104,7 +103,7 @@ struct qcom_ethqos {
struct clk *link_clk;
struct phy *serdes_phy;
unsigned int speed;
- int phy_mode;
+ phy_interface_t phy_mode;
const struct ethqos_emac_por *por;
unsigned int num_por;
@@ -631,7 +630,7 @@ static int ethqos_configure(struct qcom_ethqos *ethqos)
return ethqos->configure_func(ethqos);
}
-static void ethqos_fix_mac_speed(void *priv, unsigned int speed)
+static void ethqos_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct qcom_ethqos *ethqos = priv;
@@ -694,6 +693,23 @@ static void ethqos_clks_disable(void *data)
ethqos_clks_config(data, false);
}
+static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
+{
+ struct plat_stmmacenet_data *plat_dat = priv->plat;
+ int err;
+
+ if (!plat_dat->clk_ptp_ref)
+ return;
+
+ /* Max the PTP ref clock out to get the best resolution possible */
+ err = clk_set_rate(plat_dat->clk_ptp_ref, ULONG_MAX);
+ if (err)
+ netdev_err(priv->dev, "Failed to max out clk_ptp_ref: %d\n", err);
+ plat_dat->clk_ptp_rate = clk_get_rate(plat_dat->clk_ptp_ref);
+
+ netdev_dbg(priv->dev, "PTP rate %d\n", plat_dat->clk_ptp_rate);
+}
+
static int qcom_ethqos_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -706,12 +722,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to get platform resources\n");
plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
if (IS_ERR(plat_dat)) {
- dev_err(dev, "dt configuration failed\n");
- return PTR_ERR(plat_dat);
+ return dev_err_probe(dev, PTR_ERR(plat_dat),
+ "dt configuration failed\n");
}
plat_dat->clks_config = ethqos_clks_config;
@@ -720,7 +737,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
if (!ethqos)
return -ENOMEM;
- ethqos->phy_mode = device_get_phy_mode(dev);
+ ret = of_get_phy_mode(np, &ethqos->phy_mode);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get phy mode\n");
switch (ethqos->phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
@@ -731,16 +750,17 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
case PHY_INTERFACE_MODE_SGMII:
ethqos->configure_func = ethqos_configure_sgmii;
break;
- case -ENODEV:
- return -ENODEV;
default:
+ dev_err(dev, "Unsupported phy mode %s\n",
+ phy_modes(ethqos->phy_mode));
return -EINVAL;
}
ethqos->pdev = pdev;
ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii");
if (IS_ERR(ethqos->rgmii_base))
- return PTR_ERR(ethqos->rgmii_base);
+ return dev_err_probe(dev, PTR_ERR(ethqos->rgmii_base),
+ "Failed to map rgmii resource\n");
ethqos->mac_base = stmmac_res.addr;
@@ -752,7 +772,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii");
if (IS_ERR(ethqos->link_clk))
- return PTR_ERR(ethqos->link_clk);
+ return dev_err_probe(dev, PTR_ERR(ethqos->link_clk),
+ "Failed to get link_clk\n");
ret = ethqos_clks_config(ethqos, true);
if (ret)
@@ -764,7 +785,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes");
if (IS_ERR(ethqos->serdes_phy))
- return PTR_ERR(ethqos->serdes_phy);
+ return dev_err_probe(dev, PTR_ERR(ethqos->serdes_phy),
+ "Failed to get serdes phy\n");
ethqos->speed = SPEED_1000;
ethqos_update_link_clk(ethqos, SPEED_1000);
@@ -773,14 +795,17 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
plat_dat->bsp_priv = ethqos;
plat_dat->fix_mac_speed = ethqos_fix_mac_speed;
plat_dat->dump_debug_regs = rgmii_dump;
+ plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config;
plat_dat->has_gmac4 = 1;
if (ethqos->has_emac_ge_3)
plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
plat_dat->pmt = 1;
- plat_dat->tso_en = of_property_read_bool(np, "snps,tso");
+ if (of_property_read_bool(np, "snps,tso"))
+ plat_dat->flags |= STMMAC_FLAG_TSO_EN;
if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
- plat_dat->rx_clk_runs_in_lpi = 1;
- plat_dat->has_integrated_pcs = data->has_integrated_pcs;
+ plat_dat->flags |= STMMAC_FLAG_RX_CLK_RUNS_IN_LPI;
+ if (data->has_integrated_pcs)
+ plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS;
if (ethqos->serdes_phy) {
plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index d81591b470a2..d920a50dd16c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -14,8 +14,8 @@
#include <linux/of_net.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
@@ -1785,7 +1785,7 @@ static void rk_gmac_powerdown(struct rk_priv_data *gmac)
gmac_clk_enable(gmac, false);
}
-static void rk_fix_speed(void *priv, unsigned int speed)
+static void rk_fix_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct rk_priv_data *bsp_priv = priv;
struct device *dev = &bsp_priv->pdev->dev;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 6267bcb60206..9bf102bbc6a0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -61,7 +61,7 @@ struct socfpga_dwmac {
struct mdio_device *pcs_mdiodev;
};
-static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
void __iomem *splitter_base = dwmac->splitter_base;
@@ -236,7 +236,7 @@ static int socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac)
struct net_device *ndev = dev_get_drvdata(dwmac->dev);
struct stmmac_priv *priv = netdev_priv(ndev);
- return priv->plat->interface;
+ return priv->plat->mac_interface;
}
static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c
index d3a39d2fb3a9..9289bb87c3e3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c
@@ -7,8 +7,10 @@
*
*/
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include "stmmac_platform.h"
@@ -22,7 +24,7 @@ struct starfive_dwmac {
struct clk *clk_tx;
};
-static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct starfive_dwmac *dwmac = priv;
unsigned long rate;
@@ -58,7 +60,7 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat)
unsigned int mode;
int err;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_RMII:
mode = STARFIVE_DWMAC_PHY_INFT_RMII;
break;
@@ -70,7 +72,7 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat)
default:
dev_err(dwmac->dev, "unsupported interface %d\n",
- plat_dat->interface);
+ plat_dat->mac_interface);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
index dcbb17c4f07a..0d653bbb931b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -17,7 +17,6 @@
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include "stmmac_platform.h"
@@ -104,11 +103,11 @@ struct sti_dwmac {
struct regmap *regmap;
bool gmac_en;
u32 speed;
- void (*fix_retime_src)(void *priv, unsigned int speed);
+ void (*fix_retime_src)(void *priv, unsigned int speed, unsigned int mode);
};
struct sti_dwmac_of_data {
- void (*fix_retime_src)(void *priv, unsigned int speed);
+ void (*fix_retime_src)(void *priv, unsigned int speed, unsigned int mode);
};
static u32 phy_intf_sels[] = {
@@ -136,7 +135,7 @@ static u32 stih4xx_tx_retime_val[] = {
| STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
};
-static void stih4xx_fix_retime_src(void *priv, u32 spd)
+static void stih4xx_fix_retime_src(void *priv, u32 spd, unsigned int mode)
{
struct sti_dwmac *dwmac = priv;
u32 src = dwmac->tx_retime_src;
@@ -188,7 +187,7 @@ static int sti_dwmac_set_mode(struct sti_dwmac *dwmac)
val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
regmap_update_bits(regmap, reg, ENMII_MASK, val);
- dwmac->fix_retime_src(dwmac, dwmac->speed);
+ dwmac->fix_retime_src(dwmac, dwmac->speed, 0);
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
index bdb4de59a672..26ea8c687881 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
@@ -11,7 +11,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
@@ -172,7 +171,7 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
clk_rate = clk_get_rate(dwmac->clk_eth_ck);
dwmac->enable_eth_ck = false;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
if (clk_rate == ETH_CK_F_25M && dwmac->ext_phyclk)
dwmac->enable_eth_ck = true;
@@ -211,7 +210,7 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
pr_debug("SYSCFG init : Do not manage %d interface\n",
- plat_dat->interface);
+ plat_dat->mac_interface);
/* Do not manage others interfaces */
return -EINVAL;
}
@@ -231,7 +230,7 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
u32 reg = dwmac->mode_reg;
int val;
- switch (plat_dat->interface) {
+ switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
val = SYSCFG_MCU_ETH_SEL_MII;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
@@ -242,7 +241,7 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
break;
default:
pr_debug("SYSCFG init : Do not manage %d interface\n",
- plat_dat->interface);
+ plat_dat->mac_interface);
/* Do not manage others interfaces */
return -EINVAL;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 1e714380d125..01e77368eef1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -11,9 +11,10 @@
#include <linux/mdio-mux.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
+#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -440,8 +441,10 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
- u32 v;
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0;
+ u32 v;
v = readl(ioaddr + EMAC_INT_STA);
@@ -452,7 +455,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_TX_INT) {
ret |= handle_tx;
- x->tx_normal_irq_n++;
+ u64_stats_update_begin(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_normal_irq_n++;
+ u64_stats_update_end(&tx_q->txq_stats.syncp);
}
if (v & EMAC_TX_DMA_STOP_INT)
@@ -474,7 +479,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_RX_INT) {
ret |= handle_rx;
- x->rx_normal_irq_n++;
+ u64_stats_update_begin(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_normal_irq_n++;
+ u64_stats_update_end(&rx_q->rxq_stats.syncp);
}
if (v & EMAC_RX_BUF_UA_INT)
@@ -1009,7 +1016,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev,
if (gmac->variant->support_rmii)
reg &= ~SYSCON_RMII_EN;
- switch (plat->interface) {
+ switch (plat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
/* default */
break;
@@ -1024,7 +1031,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev,
break;
default:
dev_err(dev, "Unsupported interface mode: %s",
- phy_modes(plat->interface));
+ phy_modes(plat->mac_interface));
return -EINVAL;
}
@@ -1224,10 +1231,10 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
/* platform data specifying hardware features and callbacks.
* hardware features were copied from Allwinner drivers.
*/
- plat_dat->interface = interface;
+ plat_dat->mac_interface = interface;
plat_dat->rx_coe = STMMAC_RX_COE_TYPE2;
plat_dat->tx_coe = 1;
- plat_dat->has_sun8i = true;
+ plat_dat->flags |= STMMAC_FLAG_HAS_SUN8I;
plat_dat->bsp_priv = gmac;
plat_dat->init = sun8i_dwmac_init;
plat_dat->exit = sun8i_dwmac_exit;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
index 50963e91c347..beceeae579bf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -72,7 +72,7 @@ static void sun7i_gmac_exit(struct platform_device *pdev, void *priv)
regulator_disable(gmac->regulator);
}
-static void sun7i_fix_speed(void *priv, unsigned int speed)
+static void sun7i_fix_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct sunxi_priv_data *gmac = priv;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
index fbb0ccf84afc..e0f3cbd36852 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/platform_device.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/module.h>
#include <linux/stmmac.h>
#include <linux/clk.h>
@@ -291,7 +291,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
}
plat->has_xgmac = 1;
- plat->tso_en = 1;
+ plat->flags |= STMMAC_FLAG_TSO_EN;
plat->pmt = 1;
plat->bsp_priv = mgbe;
@@ -338,7 +338,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
/* Program SID */
writel(MGBE_SID, mgbe->hv + MGBE_WRAP_AXI_ASID0_CTRL);
- plat->serdes_up_after_phy_linkup = 1;
+ plat->flags |= STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP;
err = stmmac_dvr_probe(&pdev->dev, plat, &res);
if (err < 0)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
index acbb284be174..22d113fb8e09 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
@@ -6,7 +6,8 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/of_net.h>
#include <linux/stmmac.h>
@@ -53,7 +54,7 @@ struct visconti_eth {
spinlock_t lock; /* lock to protect register update */
};
-static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
+static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
{
struct visconti_eth *dwmac = priv;
struct net_device *netdev = dev_get_drvdata(dwmac->dev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index 1c32b1788f02..dea270f60cc3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -82,29 +82,24 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
}
/* DMA controller has two counters to track the number of the missed frames. */
-static void dwmac100_dma_diagnostic_fr(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
void __iomem *ioaddr)
{
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
if (unlikely(csr8)) {
if (csr8 & DMA_MISSED_FRAME_OVE) {
- stats->rx_over_errors += 0x800;
x->rx_overflow_cntr += 0x800;
} else {
unsigned int ove_cntr;
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
- stats->rx_over_errors += ove_cntr;
x->rx_overflow_cntr += ove_cntr;
}
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
- stats->rx_missed_errors += 0xffff;
x->rx_missed_cntr += 0xffff;
} else {
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
- stats->rx_missed_errors += miss_f;
x->rx_missed_cntr += miss_f;
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 03b1c5a97826..c6ff1fa0e04d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -68,6 +68,11 @@ static void dwmac4_core_init(struct mac_device_info *hw,
init_waitqueue_head(&priv->tstamp_busy_wait);
}
+static void dwmac4_phylink_get_caps(struct stmmac_priv *priv)
+{
+ priv->phylink_config.mac_capabilities |= MAC_2500FD;
+}
+
static void dwmac4_rx_queue_enable(struct mac_device_info *hw,
u8 mode, u32 queue)
{
@@ -1131,6 +1136,7 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
const struct stmmac_ops dwmac4_ops = {
.core_init = dwmac4_core_init,
+ .phylink_get_caps = dwmac4_phylink_get_caps,
.set_mac = stmmac_set_mac,
.rx_ipc = dwmac4_rx_ipc_enable,
.rx_queue_enable = dwmac4_rx_queue_enable,
@@ -1173,6 +1179,7 @@ const struct stmmac_ops dwmac4_ops = {
const struct stmmac_ops dwmac410_ops = {
.core_init = dwmac4_core_init,
+ .phylink_get_caps = dwmac4_phylink_get_caps,
.set_mac = stmmac_dwmac4_set_mac,
.rx_ipc = dwmac4_rx_ipc_enable,
.rx_queue_enable = dwmac4_rx_queue_enable,
@@ -1221,6 +1228,7 @@ const struct stmmac_ops dwmac410_ops = {
const struct stmmac_ops dwmac510_ops = {
.core_init = dwmac4_core_init,
+ .phylink_get_caps = dwmac4_phylink_get_caps,
.set_mac = stmmac_dwmac4_set_mac,
.rx_ipc = dwmac4_rx_ipc_enable,
.rx_queue_enable = dwmac4_rx_queue_enable,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 6a011d8633e8..89a14084c611 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -13,8 +13,7 @@
#include "dwmac4.h"
#include "dwmac4_descs.h"
-static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x,
struct dma_desc *p,
void __iomem *ioaddr)
{
@@ -40,15 +39,13 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
x->tx_frame_flushed++;
if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) {
x->tx_losscarrier++;
- stats->tx_carrier_errors++;
}
if (unlikely(tdes3 & TDES3_NO_CARRIER)) {
x->tx_carrier++;
- stats->tx_carrier_errors++;
}
if (unlikely((tdes3 & TDES3_LATE_COLLISION) ||
(tdes3 & TDES3_EXCESSIVE_COLLISION)))
- stats->collisions +=
+ x->tx_collision +=
(tdes3 & TDES3_COLLISION_COUNT_MASK)
>> TDES3_COLLISION_COUNT_SHIFT;
@@ -73,8 +70,7 @@ static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats,
return ret;
}
-static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
struct dma_desc *p)
{
unsigned int rdes1 = le32_to_cpu(p->des1);
@@ -93,7 +89,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
if (unlikely(rdes3 & RDES3_GIANT_PACKET))
- stats->rx_length_errors++;
+ x->rx_length++;
if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
x->rx_gmac_overflow++;
@@ -103,10 +99,8 @@ static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
x->rx_mii++;
- if (unlikely(rdes3 & RDES3_CRC_ERROR)) {
+ if (unlikely(rdes3 & RDES3_CRC_ERROR))
x->rx_crc_errors++;
- stats->rx_crc_errors++;
- }
if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
x->dribbling_bit++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 03ceb6a94073..980e5f8a37ec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -171,6 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0;
if (dir == DMA_DIR_RX)
@@ -198,18 +200,19 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
}
}
/* TX/RX NORMAL interrupts */
- if (likely(intr_status & DMA_CHAN_STATUS_NIS))
- x->normal_irq_n++;
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
- x->rx_normal_irq_n++;
- x->rxq_stats[chan].rx_normal_irq_n++;
+ u64_stats_update_begin(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_normal_irq_n++;
+ u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx;
}
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
- x->tx_normal_irq_n++;
- x->txq_stats[chan].tx_normal_irq_n++;
+ u64_stats_update_begin(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_normal_irq_n++;
+ u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx;
}
+
if (unlikely(intr_status & DMA_CHAN_STATUS_TBU))
ret |= handle_tx;
if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 0b6f999a8305..aaa09b16b016 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -10,6 +10,7 @@
#include <linux/iopoll.h>
#include "common.h"
#include "dwmac_dma.h"
+#include "stmmac.h"
#define GMAC_HI_REG_AE 0x80000000
@@ -161,6 +162,8 @@ static void show_rx_process_state(unsigned int status)
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
int ret = 0;
/* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS);
@@ -208,17 +211,20 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
}
/* TX/RX NORMAL interrupts */
if (likely(intr_status & DMA_STATUS_NIS)) {
- x->normal_irq_n++;
if (likely(intr_status & DMA_STATUS_RI)) {
u32 value = readl(ioaddr + DMA_INTR_ENA);
/* to schedule NAPI on real RIE event. */
if (likely(value & DMA_INTR_ENA_RIE)) {
- x->rx_normal_irq_n++;
+ u64_stats_update_begin(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_normal_irq_n++;
+ u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx;
}
}
if (likely(intr_status & DMA_STATUS_TI)) {
- x->tx_normal_irq_n++;
+ u64_stats_update_begin(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_normal_irq_n++;
+ u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx;
}
if (unlikely(intr_status & DMA_STATUS_ERI))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 1913385df685..7a8f47e7b728 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -74,8 +74,20 @@
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
#define XGMAC_RXQ_CTRL1 0x000000a4
+#define XGMAC_AVCPQ GENMASK(31, 28)
+#define XGMAC_AVCPQ_SHIFT 28
+#define XGMAC_PTPQ GENMASK(27, 24)
+#define XGMAC_PTPQ_SHIFT 24
+#define XGMAC_TACPQE BIT(23)
+#define XGMAC_DCBCPQ GENMASK(19, 16)
+#define XGMAC_DCBCPQ_SHIFT 16
+#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_UPQ GENMASK(3, 0)
+#define XGMAC_UPQ_SHIFT 0
#define XGMAC_RXQ_CTRL2 0x000000a8
#define XGMAC_RXQ_CTRL3 0x000000ac
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
@@ -110,7 +122,12 @@
#define XGMAC_TLPIEN BIT(0)
#define XGMAC_LPI_TIMER_CTRL 0x000000d4
#define XGMAC_HW_FEATURE0 0x0000011c
+#define XGMAC_HWFEAT_EDMA BIT(31)
+#define XGMAC_HWFEAT_EDIFFC BIT(30)
+#define XGMAC_HWFEAT_VXN BIT(29)
#define XGMAC_HWFEAT_SAVLANINS BIT(27)
+#define XGMAC_HWFEAT_TSSTSSEL GENMASK(26, 25)
+#define XGMAC_HWFEAT_ADDMACADRSEL GENMASK(22, 18)
#define XGMAC_HWFEAT_RXCOESEL BIT(16)
#define XGMAC_HWFEAT_TXCOESEL BIT(14)
#define XGMAC_HWFEAT_EEESEL BIT(13)
@@ -121,34 +138,54 @@
#define XGMAC_HWFEAT_MMCSEL BIT(8)
#define XGMAC_HWFEAT_MGKSEL BIT(7)
#define XGMAC_HWFEAT_RWKSEL BIT(6)
+#define XGMAC_HWFEAT_SMASEL BIT(5)
#define XGMAC_HWFEAT_VLHASH BIT(4)
+#define XGMAC_HWFEAT_HDSEL BIT(3)
#define XGMAC_HWFEAT_GMIISEL BIT(1)
#define XGMAC_HW_FEATURE1 0x00000120
#define XGMAC_HWFEAT_L3L4FNUM GENMASK(30, 27)
#define XGMAC_HWFEAT_HASHTBLSZ GENMASK(25, 24)
+#define XGMAC_HWFEAT_NUMTC GENMASK(23, 21)
#define XGMAC_HWFEAT_RSSEN BIT(20)
+#define XGMAC_HWFEAT_DBGMEMA BIT(19)
#define XGMAC_HWFEAT_TSOEN BIT(18)
#define XGMAC_HWFEAT_SPHEN BIT(17)
+#define XGMAC_HWFEAT_DCBEN BIT(16)
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
+#define XGMAC_HWFEAT_ADVTHWORD BIT(13)
+#define XGMAC_HWFEAT_PTOEN BIT(12)
+#define XGMAC_HWFEAT_OSTEN BIT(11)
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
+#define XGMAC_HWFEAT_PFCEN BIT(5)
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
#define XGMAC_HW_FEATURE2 0x00000124
+#define XGMAC_HWFEAT_AUXSNAPNUM GENMASK(30, 28)
#define XGMAC_HWFEAT_PPSOUTNUM GENMASK(26, 24)
#define XGMAC_HWFEAT_TXCHCNT GENMASK(21, 18)
#define XGMAC_HWFEAT_RXCHCNT GENMASK(15, 12)
#define XGMAC_HWFEAT_TXQCNT GENMASK(9, 6)
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
#define XGMAC_HW_FEATURE3 0x00000128
+#define XGMAC_HWFEAT_TBSCH GENMASK(31, 28)
#define XGMAC_HWFEAT_TBSSEL BIT(27)
#define XGMAC_HWFEAT_FPESEL BIT(26)
+#define XGMAC_HWFEAT_SGFSEL BIT(25)
#define XGMAC_HWFEAT_ESTWID GENMASK(24, 23)
#define XGMAC_HWFEAT_ESTDEP GENMASK(22, 20)
#define XGMAC_HWFEAT_ESTSEL BIT(19)
+#define XGMAC_HWFEAT_TTSFD GENMASK(18, 16)
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
#define XGMAC_HWFEAT_DVLAN BIT(13)
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
+#define XGMAC_HWFEAT_POUOST BIT(8)
+#define XGMAC_HWFEAT_FRPPIPE GENMASK(7, 5)
+#define XGMAC_HWFEAT_CBTISEL BIT(4)
#define XGMAC_HWFEAT_FRPSEL BIT(3)
+#define XGMAC_HWFEAT_NRVF GENMASK(2, 0)
+#define XGMAC_HW_FEATURE4 0x0000012c
+#define XGMAC_HWFEAT_EASP BIT(4)
+#define XGMAC_HWFEAT_PCSEL GENMASK(1, 0)
#define XGMAC_MAC_DPP_FSM_INT_STATUS 0x00000150
#define XGMAC_MAC_FSM_CONTROL 0x00000158
#define XGMAC_PRTYEN BIT(1)
@@ -165,7 +202,7 @@
#define XGMAC_DCS_SHIFT 16
#define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8)
#define XGMAC_L3L4_ADDR_CTRL 0x00000c00
-#define XGMAC_IDDR GENMASK(15, 8)
+#define XGMAC_IDDR GENMASK(16, 8)
#define XGMAC_IDDR_SHIFT 8
#define XGMAC_IDDR_FNUM 4
#define XGMAC_TT BIT(1)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index a0c2ef8bb0ac..f352be269deb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -47,6 +47,14 @@ static void dwxgmac2_core_init(struct mac_device_info *hw,
writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN);
}
+static void xgmac_phylink_get_caps(struct stmmac_priv *priv)
+{
+ priv->phylink_config.mac_capabilities |= MAC_2500FD | MAC_5000FD |
+ MAC_10000FD | MAC_25000FD |
+ MAC_40000FD | MAC_50000FD |
+ MAC_100000FD;
+}
+
static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable)
{
u32 tx = readl(ioaddr + XGMAC_TX_CONFIG);
@@ -127,6 +135,36 @@ static void dwxgmac2_tx_queue_prio(struct mac_device_info *hw, u32 prio,
writel(value, ioaddr + reg);
}
+static void dwxgmac2_rx_queue_routing(struct mac_device_info *hw,
+ u8 packet, u32 queue)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value;
+
+ static const struct stmmac_rx_routing dwxgmac2_route_possibilities[] = {
+ { XGMAC_AVCPQ, XGMAC_AVCPQ_SHIFT },
+ { XGMAC_PTPQ, XGMAC_PTPQ_SHIFT },
+ { XGMAC_DCBCPQ, XGMAC_DCBCPQ_SHIFT },
+ { XGMAC_UPQ, XGMAC_UPQ_SHIFT },
+ { XGMAC_MCBCQ, XGMAC_MCBCQ_SHIFT },
+ };
+
+ value = readl(ioaddr + XGMAC_RXQ_CTRL1);
+
+ /* routing configuration */
+ value &= ~dwxgmac2_route_possibilities[packet - 1].reg_mask;
+ value |= (queue << dwxgmac2_route_possibilities[packet - 1].reg_shift) &
+ dwxgmac2_route_possibilities[packet - 1].reg_mask;
+
+ /* some packets require extra ops */
+ if (packet == PACKET_AVCPQ)
+ value |= FIELD_PREP(XGMAC_TACPQE, 1);
+ else if (packet == PACKET_MCBCQ)
+ value |= FIELD_PREP(XGMAC_MCBCQEN, 1);
+
+ writel(value, ioaddr + XGMAC_RXQ_CTRL1);
+}
+
static void dwxgmac2_prog_mtl_rx_algorithms(struct mac_device_info *hw,
u32 rx_alg)
{
@@ -831,8 +869,10 @@ dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
value |= XGMAC_TCEIE; /* TSO Memory Correctable Error */
writel(value, ioaddr + XGMAC_DMA_ECC_INT_ENABLE);
- /* Only ECC Protection for External Memory feature is selected */
- if (asp <= 0x1)
+ /* 0x2: Without ECC or Parity Ports on External Application Interface
+ * 0x4: Only ECC Protection for External Memory feature is selected
+ */
+ if (asp == 0x2 || asp == 0x4)
return 0;
/* 4. Enable Parity and Timeout for FSM */
@@ -1458,12 +1498,13 @@ static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq,
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
+ .phylink_get_caps = xgmac_phylink_get_caps,
.set_mac = dwxgmac2_set_mac,
.rx_ipc = dwxgmac2_rx_ipc,
.rx_queue_enable = dwxgmac2_rx_queue_enable,
.rx_queue_prio = dwxgmac2_rx_queue_prio,
.tx_queue_prio = dwxgmac2_tx_queue_prio,
- .rx_queue_routing = NULL,
+ .rx_queue_routing = dwxgmac2_rx_queue_routing,
.prog_mtl_rx_algorithms = dwxgmac2_prog_mtl_rx_algorithms,
.prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms,
.set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight,
@@ -1519,12 +1560,13 @@ static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode,
const struct stmmac_ops dwxlgmac2_ops = {
.core_init = dwxgmac2_core_init,
+ .phylink_get_caps = xgmac_phylink_get_caps,
.set_mac = dwxgmac2_set_mac,
.rx_ipc = dwxgmac2_rx_ipc,
.rx_queue_enable = dwxlgmac2_rx_queue_enable,
.rx_queue_prio = dwxgmac2_rx_queue_prio,
.tx_queue_prio = dwxgmac2_tx_queue_prio,
- .rx_queue_routing = NULL,
+ .rx_queue_routing = dwxgmac2_rx_queue_routing,
.prog_mtl_rx_algorithms = dwxgmac2_prog_mtl_rx_algorithms,
.prog_mtl_tx_algorithms = dwxgmac2_prog_mtl_tx_algorithms,
.set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 13c347ee8be9..fc82862a612c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -8,8 +8,7 @@
#include "common.h"
#include "dwxgmac2.h"
-static int dwxgmac2_get_tx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
unsigned int tdes3 = le32_to_cpu(p->des3);
@@ -23,8 +22,7 @@ static int dwxgmac2_get_tx_status(struct net_device_stats *stats,
return ret;
}
-static int dwxgmac2_get_rx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
struct dma_desc *p)
{
unsigned int rdes3 = le32_to_cpu(p->des3);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 070bd912580b..fa69d64a8694 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -337,6 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
int ret = 0;
@@ -364,16 +366,16 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
/* TX/RX NORMAL interrupts */
if (likely(intr_status & XGMAC_NIS)) {
- x->normal_irq_n++;
-
if (likely(intr_status & XGMAC_RI)) {
- x->rx_normal_irq_n++;
- x->rxq_stats[chan].rx_normal_irq_n++;
+ u64_stats_update_begin(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_normal_irq_n++;
+ u64_stats_update_end(&rx_q->rxq_stats.syncp);
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
- x->tx_normal_irq_n++;
- x->txq_stats[chan].tx_normal_irq_n++;
+ u64_stats_update_begin(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_normal_irq_n++;
+ u64_stats_update_end(&tx_q->txq_stats.syncp);
ret |= handle_tx;
}
}
@@ -389,9 +391,14 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
{
u32 hw_cap;
- /* MAC HW feature 0 */
+ /* MAC HW feature 0 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
+ dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31;
+ dma_cap->ediffc = (hw_cap & XGMAC_HWFEAT_EDIFFC) >> 30;
+ dma_cap->vxn = (hw_cap & XGMAC_HWFEAT_VXN) >> 29;
dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
+ dma_cap->tssrc = (hw_cap & XGMAC_HWFEAT_TSSTSSEL) >> 25;
+ dma_cap->multi_addr = (hw_cap & XGMAC_HWFEAT_ADDMACADRSEL) >> 18;
dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16;
dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14;
dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
@@ -402,16 +409,31 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
dma_cap->rmon = (hw_cap & XGMAC_HWFEAT_MMCSEL) >> 8;
dma_cap->pmt_magic_frame = (hw_cap & XGMAC_HWFEAT_MGKSEL) >> 7;
dma_cap->pmt_remote_wake_up = (hw_cap & XGMAC_HWFEAT_RWKSEL) >> 6;
+ dma_cap->sma_mdio = (hw_cap & XGMAC_HWFEAT_SMASEL) >> 5;
dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4;
+ dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3;
dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1;
/* MAC HW feature 1 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
dma_cap->l3l4fnum = (hw_cap & XGMAC_HWFEAT_L3L4FNUM) >> 27;
+ /* If L3L4FNUM < 8, then the number of L3L4 filters supported by
+ * XGMAC is equal to L3L4FNUM. From L3L4FNUM >= 8 the number of
+ * L3L4 filters goes on like 8, 16, 32, ... Current maximum of
+ * L3L4FNUM = 10.
+ */
+ if (dma_cap->l3l4fnum >= 8 && dma_cap->l3l4fnum <= 10)
+ dma_cap->l3l4fnum = 8 << (dma_cap->l3l4fnum - 8);
+ else if (dma_cap->l3l4fnum > 10)
+ dma_cap->l3l4fnum = 32;
+
dma_cap->hash_tb_sz = (hw_cap & XGMAC_HWFEAT_HASHTBLSZ) >> 24;
+ dma_cap->numtc = ((hw_cap & XGMAC_HWFEAT_NUMTC) >> 21) + 1;
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
+ dma_cap->dbgmem = (hw_cap & XGMAC_HWFEAT_DBGMEMA) >> 19;
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
+ dma_cap->dcben = (hw_cap & XGMAC_HWFEAT_DCBEN) >> 16;
dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14;
switch (dma_cap->addr64) {
@@ -429,13 +451,18 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
break;
}
+ dma_cap->advthword = (hw_cap & XGMAC_HWFEAT_ADVTHWORD) >> 13;
+ dma_cap->ptoen = (hw_cap & XGMAC_HWFEAT_PTOEN) >> 12;
+ dma_cap->osten = (hw_cap & XGMAC_HWFEAT_OSTEN) >> 11;
dma_cap->tx_fifo_size =
128 << ((hw_cap & XGMAC_HWFEAT_TXFIFOSIZE) >> 6);
+ dma_cap->pfcen = (hw_cap & XGMAC_HWFEAT_PFCEN) >> 5;
dma_cap->rx_fifo_size =
128 << ((hw_cap & XGMAC_HWFEAT_RXFIFOSIZE) >> 0);
/* MAC HW feature 2 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE2);
+ dma_cap->aux_snapshot_n = (hw_cap & XGMAC_HWFEAT_AUXSNAPNUM) >> 28;
dma_cap->pps_out_num = (hw_cap & XGMAC_HWFEAT_PPSOUTNUM) >> 24;
dma_cap->number_tx_channel =
((hw_cap & XGMAC_HWFEAT_TXCHCNT) >> 18) + 1;
@@ -448,16 +475,28 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 3 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
+ dma_cap->tbs_ch_num = ((hw_cap & XGMAC_HWFEAT_TBSCH) >> 28) + 1;
dma_cap->tbssel = (hw_cap & XGMAC_HWFEAT_TBSSEL) >> 27;
dma_cap->fpesel = (hw_cap & XGMAC_HWFEAT_FPESEL) >> 26;
+ dma_cap->sgfsel = (hw_cap & XGMAC_HWFEAT_SGFSEL) >> 25;
dma_cap->estwid = (hw_cap & XGMAC_HWFEAT_ESTWID) >> 23;
dma_cap->estdep = (hw_cap & XGMAC_HWFEAT_ESTDEP) >> 20;
dma_cap->estsel = (hw_cap & XGMAC_HWFEAT_ESTSEL) >> 19;
+ dma_cap->ttsfd = (hw_cap & XGMAC_HWFEAT_TTSFD) >> 16;
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
+ dma_cap->pou_ost_en = (hw_cap & XGMAC_HWFEAT_POUOST) >> 8;
+ dma_cap->frppipe_num = ((hw_cap & XGMAC_HWFEAT_FRPPIPE) >> 5) + 1;
+ dma_cap->cbtisel = (hw_cap & XGMAC_HWFEAT_CBTISEL) >> 4;
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
+ dma_cap->nrvf_num = (hw_cap & XGMAC_HWFEAT_NRVF) >> 0;
+
+ /* MAC HW feature 4 */
+ hw_cap = readl(ioaddr + XGMAC_HW_FEATURE4);
+ dma_cap->asp |= (hw_cap & XGMAC_HWFEAT_EASP) >> 2;
+ dma_cap->pcsel = (hw_cap & XGMAC_HWFEAT_PCSEL) >> 0;
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index a91d8f13a931..937b7a0466fc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -12,8 +12,7 @@
#include "common.h"
#include "descs_com.h"
-static int enh_desc_get_tx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int enh_desc_get_tx_status(struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
unsigned int tdes0 = le32_to_cpu(p->des0);
@@ -38,15 +37,13 @@ static int enh_desc_get_tx_status(struct net_device_stats *stats,
if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
x->tx_losscarrier++;
- stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
x->tx_carrier++;
- stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
(tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
- stats->collisions +=
+ x->tx_collision +=
(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
@@ -117,8 +114,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
-static void enh_desc_get_ext_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
struct dma_extended_desc *p)
{
unsigned int rdes0 = le32_to_cpu(p->basic.des0);
@@ -182,8 +178,7 @@ static void enh_desc_get_ext_status(struct net_device_stats *stats,
}
}
-static int enh_desc_get_rx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
struct dma_desc *p)
{
unsigned int rdes0 = le32_to_cpu(p->des0);
@@ -193,14 +188,14 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
- stats->rx_length_errors++;
+ x->rx_length++;
return discard_frame;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++;
- stats->rx_length_errors++;
+ x->rx_length++;
}
if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
x->rx_gmac_overflow++;
@@ -209,7 +204,7 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
pr_err("\tIPC Csum Error/Giant frame\n");
if (unlikely(rdes0 & RDES0_COLLISION))
- stats->collisions++;
+ x->rx_collision++;
if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
x->rx_watchdog++;
@@ -218,7 +213,6 @@ static int enh_desc_get_rx_status(struct net_device_stats *stats,
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
- stats->rx_crc_errors++;
}
ret = discard_frame;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 6ee7cf07cfd7..b95d3e137813 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -57,8 +57,7 @@ struct stmmac_desc_ops {
/* Last tx segment reports the transmit status */
int (*get_tx_ls)(struct dma_desc *p);
/* Return the transmit status looking at the TDES1 */
- int (*tx_status)(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+ int (*tx_status)(struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr);
/* Get the buffer size from the descriptor */
int (*get_tx_len)(struct dma_desc *p);
@@ -67,11 +66,9 @@ struct stmmac_desc_ops {
/* Get the receive frame size */
int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type);
/* Return the reception status looking at the RDES1 */
- int (*rx_status)(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+ int (*rx_status)(struct stmmac_extra_stats *x,
struct dma_desc *p);
- void (*rx_extended_status)(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+ void (*rx_extended_status)(struct stmmac_extra_stats *x,
struct dma_extended_desc *p);
/* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p);
@@ -191,8 +188,7 @@ struct stmmac_dma_ops {
void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
int mode, u32 channel, int fifosz, u8 qmode);
/* To track extra statistic (if supported) */
- void (*dma_diagnostic_fr)(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+ void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x,
void __iomem *ioaddr);
void (*enable_dma_transmission) (void __iomem *ioaddr);
void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr,
@@ -304,6 +300,8 @@ struct stmmac_est;
struct stmmac_ops {
/* MAC core initialization */
void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
+ /* Get phylink capabilities */
+ void (*phylink_get_caps)(struct stmmac_priv *priv);
/* Enable the MAC RX/TX */
void (*set_mac)(void __iomem *ioaddr, bool enable);
/* Enable and verify that the IPC module is supported */
@@ -423,6 +421,8 @@ struct stmmac_ops {
#define stmmac_core_init(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, core_init, __args)
+#define stmmac_mac_phylink_get_caps(__priv) \
+ stmmac_do_void_callback(__priv, mac, phylink_get_caps, __priv)
#define stmmac_mac_set(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_mac, __args)
#define stmmac_rx_ipc(__priv, __args...) \
@@ -536,6 +536,7 @@ struct stmmac_hwtimestamp {
void (*get_systime) (void __iomem *ioaddr, u64 *systime);
void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
void (*timestamp_interrupt)(struct stmmac_priv *priv);
+ void (*hwtstamp_correct_latency)(struct stmmac_priv *priv);
};
#define stmmac_config_hw_tstamping(__priv, __args...) \
@@ -554,6 +555,8 @@ struct stmmac_hwtimestamp {
stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
#define stmmac_timestamp_interrupt(__priv, __args...) \
stmmac_do_void_callback(__priv, ptp, timestamp_interrupt, __args)
+#define stmmac_hwtstamp_correct_latency(__priv, __args...) \
+ stmmac_do_void_callback(__priv, ptp, hwtstamp_correct_latency, __args)
struct stmmac_tx_queue;
struct stmmac_rx_queue;
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 350e6670a576..68a7cfcb1d8f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -12,8 +12,7 @@
#include "common.h"
#include "descs_com.h"
-static int ndesc_get_tx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int ndesc_get_tx_status(struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
{
unsigned int tdes0 = le32_to_cpu(p->des0);
@@ -31,15 +30,12 @@ static int ndesc_get_tx_status(struct net_device_stats *stats,
if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
x->tx_underflow++;
- stats->tx_fifo_errors++;
}
if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
x->tx_carrier++;
- stats->tx_carrier_errors++;
}
if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
x->tx_losscarrier++;
- stats->tx_carrier_errors++;
}
if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
(tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
@@ -47,7 +43,7 @@ static int ndesc_get_tx_status(struct net_device_stats *stats,
unsigned int collisions;
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
- stats->collisions += collisions;
+ x->tx_collision += collisions;
}
ret = tx_err;
}
@@ -70,8 +66,7 @@ static int ndesc_get_tx_len(struct dma_desc *p)
* and, if required, updates the multicast statistics.
* In case of success, it returns good_frame because the GMAC device
* is supposed to be able to compute the csum in HW. */
-static int ndesc_get_rx_status(struct net_device_stats *stats,
- struct stmmac_extra_stats *x,
+static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
struct dma_desc *p)
{
int ret = good_frame;
@@ -81,7 +76,7 @@ static int ndesc_get_rx_status(struct net_device_stats *stats,
return dma_own;
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
- stats->rx_length_errors++;
+ x->rx_length++;
return discard_frame;
}
@@ -96,11 +91,9 @@ static int ndesc_get_rx_status(struct net_device_stats *stats,
x->ipc_csum_error++;
if (unlikely(rdes0 & RDES0_COLLISION)) {
x->rx_collision++;
- stats->collisions++;
}
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
- stats->rx_crc_errors++;
}
ret = discard_frame;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 07ea5ab0a60b..3401e888a9f6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -21,7 +21,8 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/reset.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
+#include <net/xdp.h>
#include <uapi/linux/bpf.h>
struct stmmac_resources {
@@ -77,6 +78,7 @@ struct stmmac_tx_queue {
dma_addr_t dma_tx_phy;
dma_addr_t tx_tail_addr;
u32 mss;
+ struct stmmac_txq_stats txq_stats;
};
struct stmmac_rx_buffer {
@@ -121,6 +123,7 @@ struct stmmac_rx_queue {
unsigned int len;
unsigned int error;
} state;
+ struct stmmac_rxq_stats rxq_stats;
};
struct stmmac_channel {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 2ae73ab842d4..b7ac7abecdd3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -89,14 +89,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
/* Tx/Rx IRQ Events */
STMMAC_STAT(rx_early_irq),
STMMAC_STAT(threshold),
- STMMAC_STAT(tx_pkt_n),
- STMMAC_STAT(rx_pkt_n),
- STMMAC_STAT(normal_irq_n),
- STMMAC_STAT(rx_normal_irq_n),
- STMMAC_STAT(napi_poll),
- STMMAC_STAT(tx_normal_irq_n),
- STMMAC_STAT(tx_clean),
- STMMAC_STAT(tx_set_ic_bit),
STMMAC_STAT(irq_receive_pmt_irq_n),
/* MMC info */
STMMAC_STAT(mmc_tx_irq_n),
@@ -163,9 +155,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(mtl_rx_fifo_ctrl_active),
STMMAC_STAT(mac_rx_frame_ctrl_fifo),
STMMAC_STAT(mac_gmii_rx_proto_engine),
- /* TSO */
- STMMAC_STAT(tx_tso_frames),
- STMMAC_STAT(tx_tso_nfrags),
/* EST */
STMMAC_STAT(mtl_est_cgce),
STMMAC_STAT(mtl_est_hlbs),
@@ -175,6 +164,23 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
+/* statistics collected in queue which will be summed up for all TX or RX
+ * queues, or summed up for both TX and RX queues(napi_poll, normal_irq_n).
+ */
+static const char stmmac_qstats_string[][ETH_GSTRING_LEN] = {
+ "rx_pkt_n",
+ "rx_normal_irq_n",
+ "tx_pkt_n",
+ "tx_normal_irq_n",
+ "tx_clean",
+ "tx_set_ic_bit",
+ "tx_tso_frames",
+ "tx_tso_nfrags",
+ "normal_irq_n",
+ "napi_poll",
+};
+#define STMMAC_QSTATS ARRAY_SIZE(stmmac_qstats_string)
+
/* HW MAC Management counters (if supported) */
#define STMMAC_MMC_STAT(m) \
{ #m, sizeof_field(struct stmmac_counters, m), \
@@ -535,23 +541,44 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
{
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 rx_cnt = priv->plat->rx_queues_to_use;
+ unsigned int start;
int q, stat;
+ u64 *pos;
char *p;
+ pos = data;
for (q = 0; q < tx_cnt; q++) {
- p = (char *)priv + offsetof(struct stmmac_priv,
- xstats.txq_stats[q].tx_pkt_n);
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[q];
+ struct stmmac_txq_stats snapshot;
+
+ data = pos;
+ do {
+ start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
+ snapshot = tx_q->txq_stats;
+ } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
+
+ p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n);
for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
- *data++ = (*(unsigned long *)p);
- p += sizeof(unsigned long);
+ *data++ += (*(u64 *)p);
+ p += sizeof(u64);
}
}
+
+ pos = data;
for (q = 0; q < rx_cnt; q++) {
- p = (char *)priv + offsetof(struct stmmac_priv,
- xstats.rxq_stats[q].rx_pkt_n);
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[q];
+ struct stmmac_rxq_stats snapshot;
+
+ data = pos;
+ do {
+ start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
+ snapshot = rx_q->rxq_stats;
+ } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
+
+ p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n);
for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
- *data++ = (*(unsigned long *)p);
- p += sizeof(unsigned long);
+ *data++ += (*(u64 *)p);
+ p += sizeof(u64);
}
}
}
@@ -562,8 +589,10 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
struct stmmac_priv *priv = netdev_priv(dev);
u32 rx_queues_count = priv->plat->rx_queues_to_use;
u32 tx_queues_count = priv->plat->tx_queues_to_use;
+ u64 napi_poll = 0, normal_irq_n = 0;
+ int i, j = 0, pos, ret;
unsigned long count;
- int i, j = 0, ret;
+ unsigned int start;
if (priv->dma_cap.asp) {
for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) {
@@ -574,8 +603,7 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
}
/* Update the DMA HW counters for dwmac10/100 */
- ret = stmmac_dma_diagnostic_fr(priv, &dev->stats, (void *) &priv->xstats,
- priv->ioaddr);
+ ret = stmmac_dma_diagnostic_fr(priv, &priv->xstats, priv->ioaddr);
if (ret) {
/* If supported, for new GMAC chips expose the MMC counters */
if (priv->dma_cap.rmon) {
@@ -606,6 +634,48 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
}
+
+ pos = j;
+ for (i = 0; i < rx_queues_count; i++) {
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[i];
+ struct stmmac_rxq_stats snapshot;
+
+ j = pos;
+ do {
+ start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp);
+ snapshot = rx_q->rxq_stats;
+ } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start));
+
+ data[j++] += snapshot.rx_pkt_n;
+ data[j++] += snapshot.rx_normal_irq_n;
+ normal_irq_n += snapshot.rx_normal_irq_n;
+ napi_poll += snapshot.napi_poll;
+ }
+
+ pos = j;
+ for (i = 0; i < tx_queues_count; i++) {
+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[i];
+ struct stmmac_txq_stats snapshot;
+
+ j = pos;
+ do {
+ start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp);
+ snapshot = tx_q->txq_stats;
+ } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start));
+
+ data[j++] += snapshot.tx_pkt_n;
+ data[j++] += snapshot.tx_normal_irq_n;
+ normal_irq_n += snapshot.tx_normal_irq_n;
+ data[j++] += snapshot.tx_clean;
+ data[j++] += snapshot.tx_set_ic_bit;
+ data[j++] += snapshot.tx_tso_frames;
+ data[j++] += snapshot.tx_tso_nfrags;
+ napi_poll += snapshot.napi_poll;
+ }
+ normal_irq_n += priv->xstats.rx_early_irq;
+ data[j++] = normal_irq_n;
+ data[j++] = napi_poll;
+
stmmac_get_per_qstats(priv, &data[j]);
}
@@ -618,7 +688,7 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
switch (sset) {
case ETH_SS_STATS:
- len = STMMAC_STATS_LEN +
+ len = STMMAC_STATS_LEN + STMMAC_QSTATS +
STMMAC_TXQ_STATS * tx_cnt +
STMMAC_RXQ_STATS * rx_cnt;
@@ -691,8 +761,11 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
p += ETH_GSTRING_LEN;
}
for (i = 0; i < STMMAC_STATS_LEN; i++) {
- memcpy(p, stmmac_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ memcpy(p, stmmac_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < STMMAC_QSTATS; i++) {
+ memcpy(p, stmmac_qstats_string[i], ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
stmmac_get_qstats_string(priv, p);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 8b50f03056b7..540f6a4ec0b8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -60,6 +60,48 @@ static void config_sub_second_increment(void __iomem *ioaddr,
*ssinc = data;
}
+static void hwtstamp_correct_latency(struct stmmac_priv *priv)
+{
+ void __iomem *ioaddr = priv->ptpaddr;
+ u32 reg_tsic, reg_tsicsns;
+ u32 reg_tsec, reg_tsecsns;
+ u64 scaled_ns;
+ u32 val;
+
+ /* MAC-internal ingress latency */
+ scaled_ns = readl(ioaddr + PTP_TS_INGR_LAT);
+
+ /* See section 11.7.2.5.3.1 "Ingress Correction" on page 4001 of
+ * i.MX8MP Applications Processor Reference Manual Rev. 1, 06/2021
+ */
+ val = readl(ioaddr + PTP_TCR);
+ if (val & PTP_TCR_TSCTRLSSR)
+ /* nanoseconds field is in decimal format with granularity of 1ns/bit */
+ scaled_ns = ((u64)NSEC_PER_SEC << 16) - scaled_ns;
+ else
+ /* nanoseconds field is in binary format with granularity of ~0.466ns/bit */
+ scaled_ns = ((1ULL << 31) << 16) -
+ DIV_U64_ROUND_CLOSEST(scaled_ns * PSEC_PER_NSEC, 466U);
+
+ reg_tsic = scaled_ns >> 16;
+ reg_tsicsns = scaled_ns & 0xff00;
+
+ /* set bit 31 for 2's compliment */
+ reg_tsic |= BIT(31);
+
+ writel(reg_tsic, ioaddr + PTP_TS_INGR_CORR_NS);
+ writel(reg_tsicsns, ioaddr + PTP_TS_INGR_CORR_SNS);
+
+ /* MAC-internal egress latency */
+ scaled_ns = readl(ioaddr + PTP_TS_EGR_LAT);
+
+ reg_tsec = scaled_ns >> 16;
+ reg_tsecsns = scaled_ns & 0xff00;
+
+ writel(reg_tsec, ioaddr + PTP_TS_EGR_CORR_NS);
+ writel(reg_tsecsns, ioaddr + PTP_TS_EGR_CORR_SNS);
+}
+
static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
{
u32 value;
@@ -180,7 +222,7 @@ static void timestamp_interrupt(struct stmmac_priv *priv)
u64 ptp_time;
int i;
- if (priv->plat->int_snapshot_en) {
+ if (priv->plat->flags & STMMAC_FLAG_INT_SNAPSHOT_EN) {
wake_up(&priv->tstamp_busy_wait);
return;
}
@@ -195,7 +237,7 @@ static void timestamp_interrupt(struct stmmac_priv *priv)
*/
ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
- if (!priv->plat->ext_snapshot_en)
+ if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN)
return;
num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
@@ -221,4 +263,5 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
.get_systime = get_systime,
.get_ptptime = get_ptptime,
.timestamp_interrupt = timestamp_interrupt,
+ .hwtstamp_correct_latency = hwtstamp_correct_latency,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 4727f7be4f86..9a3182b9e767 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -39,6 +39,7 @@
#include <linux/phylink.h>
#include <linux/udp.h>
#include <linux/bpf_trace.h>
+#include <net/page_pool/helpers.h>
#include <net/pkt_cls.h>
#include <net/xdp_sock_drv.h>
#include "stmmac_ptp.h"
@@ -325,7 +326,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
priv->clk_csr = STMMAC_CSR_250_300M;
}
- if (priv->plat->has_sun8i) {
+ if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) {
if (clk_rate > 160000000)
priv->clk_csr = 0x03;
else if (clk_rate > 80000000)
@@ -421,7 +422,7 @@ static int stmmac_enable_eee_mode(struct stmmac_priv *priv)
/* Check and enter in LPI mode */
if (!priv->tx_path_in_lpi_mode)
stmmac_set_eee_mode(priv, priv->hw,
- priv->plat->en_tx_lpi_clockgating);
+ priv->plat->flags & STMMAC_FLAG_EN_TX_LPI_CLOCKGATING);
return 0;
}
@@ -909,6 +910,9 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
+ if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
+ stmmac_hwtstamp_correct_latency(priv, priv);
+
return 0;
}
@@ -991,7 +995,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
u32 old_ctrl, ctrl;
- if (priv->plat->serdes_up_after_phy_linkup && priv->plat->serdes_powerup)
+ if ((priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
+ priv->plat->serdes_powerup)
priv->plat->serdes_powerup(priv->dev, priv->plat->bsp_priv);
old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
@@ -1059,7 +1064,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
priv->speed = speed;
if (priv->plat->fix_mac_speed)
- priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed);
+ priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed, mode);
if (!duplex)
ctrl &= ~priv->hw->link.duplex;
@@ -1084,7 +1089,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
stmmac_mac_set(priv, priv->ioaddr, true);
if (phy && priv->dma_cap.eee) {
priv->eee_active =
- phy_init_eee(phy, !priv->plat->rx_clk_runs_in_lpi) >= 0;
+ phy_init_eee(phy, !(priv->plat->flags &
+ STMMAC_FLAG_RX_CLK_RUNS_IN_LPI)) >= 0;
priv->eee_enabled = stmmac_eee_init(priv);
priv->tx_lpi_enabled = priv->eee_enabled;
stmmac_set_eee_pls(priv, priv->hw, true);
@@ -1092,6 +1098,9 @@ static void stmmac_mac_link_up(struct phylink_config *config,
if (priv->dma_cap.fpesel)
stmmac_fpe_link_state_handle(priv, true);
+
+ if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
+ stmmac_hwtstamp_correct_latency(priv, priv);
}
static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
@@ -1110,7 +1119,7 @@ static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
*/
static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
{
- int interface = priv->plat->interface;
+ int interface = priv->plat->mac_interface;
if (priv->dma_cap.pcs) {
if ((interface == PHY_INTERFACE_MODE_RGMII) ||
@@ -1144,7 +1153,7 @@ static int stmmac_init_phy(struct net_device *dev)
if (!phylink_expects_phy(priv->phylink))
return 0;
- fwnode = of_fwnode_handle(priv->plat->phylink_node);
+ fwnode = priv->plat->port_node;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
@@ -1190,22 +1199,24 @@ static int stmmac_init_phy(struct net_device *dev)
static int stmmac_phy_setup(struct stmmac_priv *priv)
{
- struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
- struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
- int max_speed = priv->plat->max_speed;
+ struct stmmac_mdio_bus_data *mdio_bus_data;
int mode = priv->plat->phy_interface;
+ struct fwnode_handle *fwnode;
struct phylink *phylink;
+ int max_speed;
priv->phylink_config.dev = &priv->dev->dev;
priv->phylink_config.type = PHYLINK_NETDEV;
- if (priv->plat->mdio_bus_data)
+ priv->phylink_config.mac_managed_pm = true;
+
+ mdio_bus_data = priv->plat->mdio_bus_data;
+ if (mdio_bus_data)
priv->phylink_config.ovr_an_inband =
mdio_bus_data->xpcs_an_inband;
- if (!fwnode)
- fwnode = dev_fwnode(priv->device);
-
- /* Set the platform/firmware specified interface mode */
+ /* Set the platform/firmware specified interface mode. Note, phylink
+ * deals with the PHY interface mode, not the MAC interface mode.
+ */
__set_bit(mode, priv->phylink_config.supported_interfaces);
/* If we have an xpcs, it defines which PHY interfaces are supported. */
@@ -1214,36 +1225,24 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
priv->phylink_config.supported_interfaces);
priv->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
- MAC_10 | MAC_100;
-
- if (!max_speed || max_speed >= 1000)
- priv->phylink_config.mac_capabilities |= MAC_1000;
-
- if (priv->plat->has_gmac4) {
- if (!max_speed || max_speed >= 2500)
- priv->phylink_config.mac_capabilities |= MAC_2500FD;
- } else if (priv->plat->has_xgmac) {
- if (!max_speed || max_speed >= 2500)
- priv->phylink_config.mac_capabilities |= MAC_2500FD;
- if (!max_speed || max_speed >= 5000)
- priv->phylink_config.mac_capabilities |= MAC_5000FD;
- if (!max_speed || max_speed >= 10000)
- priv->phylink_config.mac_capabilities |= MAC_10000FD;
- if (!max_speed || max_speed >= 25000)
- priv->phylink_config.mac_capabilities |= MAC_25000FD;
- if (!max_speed || max_speed >= 40000)
- priv->phylink_config.mac_capabilities |= MAC_40000FD;
- if (!max_speed || max_speed >= 50000)
- priv->phylink_config.mac_capabilities |= MAC_50000FD;
- if (!max_speed || max_speed >= 100000)
- priv->phylink_config.mac_capabilities |= MAC_100000FD;
- }
+ MAC_10FD | MAC_100FD |
+ MAC_1000FD;
/* Half-Duplex can only work with single queue */
- if (priv->plat->tx_queues_to_use > 1)
- priv->phylink_config.mac_capabilities &=
- ~(MAC_10HD | MAC_100HD | MAC_1000HD);
- priv->phylink_config.mac_managed_pm = true;
+ if (priv->plat->tx_queues_to_use <= 1)
+ priv->phylink_config.mac_capabilities |= MAC_10HD | MAC_100HD |
+ MAC_1000HD;
+
+ /* Get the MAC specific capabilities */
+ stmmac_mac_phylink_get_caps(priv);
+
+ max_speed = priv->plat->max_speed;
+ if (max_speed)
+ phylink_limit_mac_speed(&priv->phylink_config, max_speed);
+
+ fwnode = priv->plat->port_node;
+ if (!fwnode)
+ fwnode = dev_fwnode(priv->device);
phylink = phylink_create(&priv->phylink_config, fwnode,
mode, &stmmac_phylink_mac_ops);
@@ -2432,6 +2431,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
struct dma_desc *tx_desc = NULL;
struct xdp_desc xdp_desc;
bool work_done = true;
+ u32 tx_set_ic_bit = 0;
+ unsigned long flags;
/* Avoids TX time-out as we are sharing with slow path */
txq_trans_cond_update(nq);
@@ -2492,7 +2493,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
if (set_ic) {
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, tx_desc);
- priv->xstats.tx_set_ic_bit++;
+ tx_set_ic_bit++;
}
stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len,
@@ -2504,6 +2505,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
entry = tx_q->cur_tx;
}
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_set_ic_bit += tx_set_ic_bit;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
if (tx_desc) {
stmmac_flush_tx_descriptors(priv, queue);
@@ -2545,11 +2549,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
unsigned int bytes_compl = 0, pkts_compl = 0;
unsigned int entry, xmits = 0, count = 0;
+ u32 tx_packets = 0, tx_errors = 0;
+ unsigned long flags;
__netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue));
- priv->xstats.tx_clean++;
-
tx_q->xsk_frames_done = 0;
entry = tx_q->dirty_tx;
@@ -2580,8 +2584,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
else
p = tx_q->dma_tx + entry;
- status = stmmac_tx_status(priv, &priv->dev->stats,
- &priv->xstats, p, priv->ioaddr);
+ status = stmmac_tx_status(priv, &priv->xstats, p, priv->ioaddr);
/* Check if the descriptor is owned by the DMA */
if (unlikely(status & tx_dma_own))
break;
@@ -2597,13 +2600,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
if (likely(!(status & tx_not_ls))) {
/* ... verify the status error condition */
if (unlikely(status & tx_err)) {
- priv->dev->stats.tx_errors++;
+ tx_errors++;
if (unlikely(status & tx_err_bump_tc))
stmmac_bump_dma_threshold(priv, queue);
} else {
- priv->dev->stats.tx_packets++;
- priv->xstats.tx_pkt_n++;
- priv->xstats.txq_stats[queue].tx_pkt_n++;
+ tx_packets++;
}
if (skb)
stmmac_get_tx_hwtstamp(priv, p, skb);
@@ -2707,6 +2708,14 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]),
HRTIMER_MODE_REL);
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_packets += tx_packets;
+ tx_q->txq_stats.tx_pkt_n += tx_packets;
+ tx_q->txq_stats.tx_clean++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
+
+ priv->xstats.tx_errors += tx_errors;
+
__netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
/* Combine decisions from TX clean and XSK TX */
@@ -2734,7 +2743,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
tx_q->dma_tx_phy, chan);
stmmac_start_tx_dma(priv, chan);
- priv->dev->stats.tx_errors++;
+ priv->xstats.tx_errors++;
netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, chan));
}
@@ -3710,7 +3719,7 @@ static int stmmac_request_irq(struct net_device *dev)
int ret;
/* Request the IRQ lines */
- if (priv->plat->multi_msi_en)
+ if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN)
ret = stmmac_request_irq_multi_msi(dev);
else
ret = stmmac_request_irq_single(dev);
@@ -3827,10 +3836,6 @@ static int __stmmac_open(struct net_device *dev,
}
}
- /* Extra statistics */
- memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
- priv->xstats.threshold = tc;
-
priv->rx_copybreak = STMMAC_RX_COPYBREAK;
buf_sz = dma_conf->dma_buf_sz;
@@ -3838,7 +3843,8 @@ static int __stmmac_open(struct net_device *dev,
stmmac_reset_queues_param(priv);
- if (!priv->plat->serdes_up_after_phy_linkup && priv->plat->serdes_powerup) {
+ if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
+ priv->plat->serdes_powerup) {
ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv);
if (ret < 0) {
netdev_err(priv->dev, "%s: Serdes powerup failed\n",
@@ -4110,6 +4116,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_tx_queue *tx_q;
bool has_vlan, set_ic;
u8 proto_hdr_len, hdr;
+ unsigned long flags;
u32 pay_len, mss;
dma_addr_t des;
int i;
@@ -4258,7 +4265,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
- priv->xstats.tx_set_ic_bit++;
}
/* We've used all descriptors we need for this skb, however,
@@ -4274,9 +4280,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
}
- dev->stats.tx_bytes += skb->len;
- priv->xstats.tx_tso_frames++;
- priv->xstats.tx_tso_nfrags += nfrags;
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_bytes += skb->len;
+ tx_q->txq_stats.tx_tso_frames++;
+ tx_q->txq_stats.tx_tso_nfrags += nfrags;
+ if (set_ic)
+ tx_q->txq_stats.tx_set_ic_bit++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4326,7 +4336,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
dma_map_err:
dev_err(priv->device, "Tx dma map failed\n");
dev_kfree_skb(skb);
- priv->dev->stats.tx_dropped++;
+ priv->xstats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -4352,6 +4362,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_tx_queue *tx_q;
bool has_vlan, set_ic;
int entry, first_tx;
+ unsigned long flags;
dma_addr_t des;
tx_q = &priv->dma_conf.tx_queue[queue];
@@ -4480,7 +4491,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, desc);
- priv->xstats.tx_set_ic_bit++;
}
/* We've used all descriptors we need for this skb, however,
@@ -4507,7 +4517,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
}
- dev->stats.tx_bytes += skb->len;
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_bytes += skb->len;
+ if (set_ic)
+ tx_q->txq_stats.tx_set_ic_bit++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4569,7 +4583,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dma_map_err:
netdev_err(priv->dev, "Tx DMA map failed\n");
dev_kfree_skb(skb);
- priv->dev->stats.tx_dropped++;
+ priv->xstats.tx_dropped++;
return NETDEV_TX_OK;
}
@@ -4770,9 +4784,12 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
set_ic = false;
if (set_ic) {
+ unsigned long flags;
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, tx_desc);
- priv->xstats.tx_set_ic_bit++;
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.tx_set_ic_bit++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
}
stmmac_enable_dma_transmission(priv, priv->ioaddr);
@@ -4917,16 +4934,18 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
struct dma_desc *p, struct dma_desc *np,
struct xdp_buff *xdp)
{
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue];
unsigned int len = xdp->data_end - xdp->data;
enum pkt_hash_types hash_type;
int coe = priv->hw->rx_csum;
+ unsigned long flags;
struct sk_buff *skb;
u32 hash;
skb = stmmac_construct_skb_zc(ch, xdp);
if (!skb) {
- priv->dev->stats.rx_dropped++;
+ priv->xstats.rx_dropped++;
return;
}
@@ -4945,8 +4964,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rxtx_napi, skb);
- priv->dev->stats.rx_packets++;
- priv->dev->stats.rx_bytes += len;
+ flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_pkt_n++;
+ rx_q->rxq_stats.rx_bytes += len;
+ u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
}
static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
@@ -5023,9 +5044,11 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int count = 0, error = 0, len = 0;
int dirty = stmmac_rx_dirty(priv, queue);
unsigned int next_entry = rx_q->cur_rx;
+ u32 rx_errors = 0, rx_dropped = 0;
unsigned int desc_size;
struct bpf_prog *prog;
bool failure = false;
+ unsigned long flags;
int xdp_status = 0;
int status = 0;
@@ -5081,8 +5104,7 @@ read_again:
p = rx_q->dma_rx + entry;
/* read the status of the incoming frame */
- status = stmmac_rx_status(priv, &priv->dev->stats,
- &priv->xstats, p);
+ status = stmmac_rx_status(priv, &priv->xstats, p);
/* check if managed by the DMA otherwise go ahead */
if (unlikely(status & dma_own))
break;
@@ -5104,8 +5126,7 @@ read_again:
break;
if (priv->extend_desc)
- stmmac_rx_extended_status(priv, &priv->dev->stats,
- &priv->xstats,
+ stmmac_rx_extended_status(priv, &priv->xstats,
rx_q->dma_erx + entry);
if (unlikely(status == discard_frame)) {
xsk_buff_free(buf->xdp);
@@ -5113,7 +5134,7 @@ read_again:
dirty++;
error = 1;
if (!priv->hwts_rx_en)
- priv->dev->stats.rx_errors++;
+ rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
@@ -5161,7 +5182,7 @@ read_again:
break;
case STMMAC_XDP_CONSUMED:
xsk_buff_free(buf->xdp);
- priv->dev->stats.rx_dropped++;
+ rx_dropped++;
break;
case STMMAC_XDP_TX:
case STMMAC_XDP_REDIRECT:
@@ -5182,8 +5203,12 @@ read_again:
stmmac_finalize_xdp_rx(priv, xdp_status);
- priv->xstats.rx_pkt_n += count;
- priv->xstats.rxq_stats[queue].rx_pkt_n += count;
+ flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_pkt_n += count;
+ u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+
+ priv->xstats.rx_dropped += rx_dropped;
+ priv->xstats.rx_errors += rx_errors;
if (xsk_uses_need_wakeup(rx_q->xsk_pool)) {
if (failure || stmmac_rx_dirty(priv, queue) > 0)
@@ -5207,6 +5232,7 @@ read_again:
*/
static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
{
+ u32 rx_errors = 0, rx_dropped = 0, rx_bytes = 0, rx_packets = 0;
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue];
unsigned int count = 0, error = 0, len = 0;
@@ -5216,6 +5242,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int desc_size;
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
+ unsigned long flags;
int xdp_status = 0;
int buf_sz;
@@ -5271,8 +5298,7 @@ read_again:
p = rx_q->dma_rx + entry;
/* read the status of the incoming frame */
- status = stmmac_rx_status(priv, &priv->dev->stats,
- &priv->xstats, p);
+ status = stmmac_rx_status(priv, &priv->xstats, p);
/* check if managed by the DMA otherwise go ahead */
if (unlikely(status & dma_own))
break;
@@ -5289,14 +5315,13 @@ read_again:
prefetch(np);
if (priv->extend_desc)
- stmmac_rx_extended_status(priv, &priv->dev->stats,
- &priv->xstats, rx_q->dma_erx + entry);
+ stmmac_rx_extended_status(priv, &priv->xstats, rx_q->dma_erx + entry);
if (unlikely(status == discard_frame)) {
page_pool_recycle_direct(rx_q->page_pool, buf->page);
buf->page = NULL;
error = 1;
if (!priv->hwts_rx_en)
- priv->dev->stats.rx_errors++;
+ rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
@@ -5364,7 +5389,7 @@ read_again:
virt_to_head_page(ctx.xdp.data),
sync_len, true);
buf->page = NULL;
- priv->dev->stats.rx_dropped++;
+ rx_dropped++;
/* Clear skb as it was set as
* status by XDP program.
@@ -5393,7 +5418,7 @@ read_again:
skb = napi_alloc_skb(&ch->rx_napi, buf1_len);
if (!skb) {
- priv->dev->stats.rx_dropped++;
+ rx_dropped++;
count++;
goto drain_data;
}
@@ -5413,7 +5438,7 @@ read_again:
priv->dma_conf.dma_buf_sz);
/* Data payload appended into SKB */
- page_pool_release_page(rx_q->page_pool, buf->page);
+ skb_mark_for_recycle(skb);
buf->page = NULL;
}
@@ -5425,7 +5450,7 @@ read_again:
priv->dma_conf.dma_buf_sz);
/* Data payload appended into SKB */
- page_pool_release_page(rx_q->page_pool, buf->sec_page);
+ skb_mark_for_recycle(skb);
buf->sec_page = NULL;
}
@@ -5453,8 +5478,8 @@ drain_data:
napi_gro_receive(&ch->rx_napi, skb);
skb = NULL;
- priv->dev->stats.rx_packets++;
- priv->dev->stats.rx_bytes += len;
+ rx_packets++;
+ rx_bytes += len;
count++;
}
@@ -5469,8 +5494,14 @@ drain_data:
stmmac_rx_refill(priv, queue);
- priv->xstats.rx_pkt_n += count;
- priv->xstats.rxq_stats[queue].rx_pkt_n += count;
+ flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.rx_packets += rx_packets;
+ rx_q->rxq_stats.rx_bytes += rx_bytes;
+ rx_q->rxq_stats.rx_pkt_n += count;
+ u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
+
+ priv->xstats.rx_dropped += rx_dropped;
+ priv->xstats.rx_errors += rx_errors;
return count;
}
@@ -5480,10 +5511,15 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget)
struct stmmac_channel *ch =
container_of(napi, struct stmmac_channel, rx_napi);
struct stmmac_priv *priv = ch->priv_data;
+ struct stmmac_rx_queue *rx_q;
u32 chan = ch->index;
+ unsigned long flags;
int work_done;
- priv->xstats.napi_poll++;
+ rx_q = &priv->dma_conf.rx_queue[chan];
+ flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.napi_poll++;
+ u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
work_done = stmmac_rx(priv, budget, chan);
if (work_done < budget && napi_complete_done(napi, work_done)) {
@@ -5502,10 +5538,15 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
struct stmmac_channel *ch =
container_of(napi, struct stmmac_channel, tx_napi);
struct stmmac_priv *priv = ch->priv_data;
+ struct stmmac_tx_queue *tx_q;
u32 chan = ch->index;
+ unsigned long flags;
int work_done;
- priv->xstats.napi_poll++;
+ tx_q = &priv->dma_conf.tx_queue[chan];
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.napi_poll++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
work_done = stmmac_tx_clean(priv, budget, chan);
work_done = min(work_done, budget);
@@ -5527,9 +5568,20 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget)
container_of(napi, struct stmmac_channel, rxtx_napi);
struct stmmac_priv *priv = ch->priv_data;
int rx_done, tx_done, rxtx_done;
+ struct stmmac_rx_queue *rx_q;
+ struct stmmac_tx_queue *tx_q;
u32 chan = ch->index;
+ unsigned long flags;
+
+ rx_q = &priv->dma_conf.rx_queue[chan];
+ flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp);
+ rx_q->rxq_stats.napi_poll++;
+ u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags);
- priv->xstats.napi_poll++;
+ tx_q = &priv->dma_conf.tx_queue[chan];
+ flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp);
+ tx_q->txq_stats.napi_poll++;
+ u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags);
tx_done = stmmac_tx_clean(priv, budget, chan);
tx_done = min(tx_done, budget);
@@ -5677,7 +5729,7 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
features &= ~NETIF_F_CSUM_MASK;
/* Disable tso if asked by ethtool */
- if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
+ if ((priv->plat->flags & STMMAC_FLAG_TSO_EN) && (priv->dma_cap.tsoen)) {
if (features & NETIF_F_TSO)
priv->tso = true;
else
@@ -5798,7 +5850,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
}
/* PCS link status */
- if (priv->hw->pcs && !priv->plat->has_integrated_pcs) {
+ if (priv->hw->pcs &&
+ !(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS)) {
if (priv->xstats.pcs_link)
netif_carrier_on(priv->dev);
else
@@ -5951,7 +6004,7 @@ static void stmmac_poll_controller(struct net_device *dev)
if (test_bit(STMMAC_DOWN, &priv->state))
return;
- if (priv->plat->multi_msi_en) {
+ if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN) {
for (i = 0; i < priv->plat->rx_queues_to_use; i++)
stmmac_msi_intr_rx(0, &priv->dma_conf.rx_queue[i]);
@@ -6174,6 +6227,22 @@ DEFINE_SHOW_ATTRIBUTE(stmmac_rings_status);
static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
{
+ static const char * const dwxgmac_timestamp_source[] = {
+ "None",
+ "Internal",
+ "External",
+ "Both",
+ };
+ static const char * const dwxgmac_safety_feature_desc[] = {
+ "No",
+ "All Safety Features with ECC and Parity",
+ "All Safety Features without ECC or Parity",
+ "All Safety Features with Parity Only",
+ "ECC Only",
+ "UNDEFINED",
+ "UNDEFINED",
+ "UNDEFINED",
+ };
struct net_device *dev = seq->private;
struct stmmac_priv *priv = netdev_priv(dev);
@@ -6192,10 +6261,16 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
(priv->dma_cap.mbps_1000) ? "Y" : "N");
seq_printf(seq, "\tHalf duplex: %s\n",
(priv->dma_cap.half_duplex) ? "Y" : "N");
- seq_printf(seq, "\tHash Filter: %s\n",
- (priv->dma_cap.hash_filter) ? "Y" : "N");
- seq_printf(seq, "\tMultiple MAC address registers: %s\n",
- (priv->dma_cap.multi_addr) ? "Y" : "N");
+ if (priv->plat->has_xgmac) {
+ seq_printf(seq,
+ "\tNumber of Additional MAC address registers: %d\n",
+ priv->dma_cap.multi_addr);
+ } else {
+ seq_printf(seq, "\tHash Filter: %s\n",
+ (priv->dma_cap.hash_filter) ? "Y" : "N");
+ seq_printf(seq, "\tMultiple MAC address registers: %s\n",
+ (priv->dma_cap.multi_addr) ? "Y" : "N");
+ }
seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfaces): %s\n",
(priv->dma_cap.pcs) ? "Y" : "N");
seq_printf(seq, "\tSMA (MDIO) Interface: %s\n",
@@ -6210,12 +6285,16 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
(priv->dma_cap.time_stamp) ? "Y" : "N");
seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp: %s\n",
(priv->dma_cap.atime_stamp) ? "Y" : "N");
+ if (priv->plat->has_xgmac)
+ seq_printf(seq, "\tTimestamp System Time Source: %s\n",
+ dwxgmac_timestamp_source[priv->dma_cap.tssrc]);
seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE): %s\n",
(priv->dma_cap.eee) ? "Y" : "N");
seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N");
seq_printf(seq, "\tChecksum Offload in TX: %s\n",
(priv->dma_cap.tx_coe) ? "Y" : "N");
- if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+ if (priv->synopsys_id >= DWMAC_CORE_4_00 ||
+ priv->plat->has_xgmac) {
seq_printf(seq, "\tIP Checksum Offload in RX: %s\n",
(priv->dma_cap.rx_coe) ? "Y" : "N");
} else {
@@ -6223,9 +6302,9 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
(priv->dma_cap.rx_coe_type1) ? "Y" : "N");
seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n",
(priv->dma_cap.rx_coe_type2) ? "Y" : "N");
+ seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n",
+ (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N");
}
- seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n",
- (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N");
seq_printf(seq, "\tNumber of Additional RX channel: %d\n",
priv->dma_cap.number_rx_channel);
seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
@@ -6238,12 +6317,13 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
(priv->dma_cap.enh_desc) ? "Y" : "N");
seq_printf(seq, "\tTX Fifo Size: %d\n", priv->dma_cap.tx_fifo_size);
seq_printf(seq, "\tRX Fifo Size: %d\n", priv->dma_cap.rx_fifo_size);
- seq_printf(seq, "\tHash Table Size: %d\n", priv->dma_cap.hash_tb_sz);
+ seq_printf(seq, "\tHash Table Size: %lu\n", priv->dma_cap.hash_tb_sz ?
+ (BIT(priv->dma_cap.hash_tb_sz) << 5) : 0);
seq_printf(seq, "\tTSO: %s\n", priv->dma_cap.tsoen ? "Y" : "N");
seq_printf(seq, "\tNumber of PPS Outputs: %d\n",
priv->dma_cap.pps_out_num);
seq_printf(seq, "\tSafety Features: %s\n",
- priv->dma_cap.asp ? "Y" : "N");
+ dwxgmac_safety_feature_desc[priv->dma_cap.asp]);
seq_printf(seq, "\tFlexible RX Parser: %s\n",
priv->dma_cap.frpsel ? "Y" : "N");
seq_printf(seq, "\tEnhanced Addressing: %d\n",
@@ -6268,6 +6348,53 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v)
priv->dma_cap.fpesel ? "Y" : "N");
seq_printf(seq, "\tTime-Based Scheduling (TBS): %s\n",
priv->dma_cap.tbssel ? "Y" : "N");
+ seq_printf(seq, "\tNumber of DMA Channels Enabled for TBS: %d\n",
+ priv->dma_cap.tbs_ch_num);
+ seq_printf(seq, "\tPer-Stream Filtering: %s\n",
+ priv->dma_cap.sgfsel ? "Y" : "N");
+ seq_printf(seq, "\tTX Timestamp FIFO Depth: %lu\n",
+ BIT(priv->dma_cap.ttsfd) >> 1);
+ seq_printf(seq, "\tNumber of Traffic Classes: %d\n",
+ priv->dma_cap.numtc);
+ seq_printf(seq, "\tDCB Feature: %s\n",
+ priv->dma_cap.dcben ? "Y" : "N");
+ seq_printf(seq, "\tIEEE 1588 High Word Register: %s\n",
+ priv->dma_cap.advthword ? "Y" : "N");
+ seq_printf(seq, "\tPTP Offload: %s\n",
+ priv->dma_cap.ptoen ? "Y" : "N");
+ seq_printf(seq, "\tOne-Step Timestamping: %s\n",
+ priv->dma_cap.osten ? "Y" : "N");
+ seq_printf(seq, "\tPriority-Based Flow Control: %s\n",
+ priv->dma_cap.pfcen ? "Y" : "N");
+ seq_printf(seq, "\tNumber of Flexible RX Parser Instructions: %lu\n",
+ BIT(priv->dma_cap.frpes) << 6);
+ seq_printf(seq, "\tNumber of Flexible RX Parser Parsable Bytes: %lu\n",
+ BIT(priv->dma_cap.frpbs) << 6);
+ seq_printf(seq, "\tParallel Instruction Processor Engines: %d\n",
+ priv->dma_cap.frppipe_num);
+ seq_printf(seq, "\tNumber of Extended VLAN Tag Filters: %lu\n",
+ priv->dma_cap.nrvf_num ?
+ (BIT(priv->dma_cap.nrvf_num) << 1) : 0);
+ seq_printf(seq, "\tWidth of the Time Interval Field in GCL: %d\n",
+ priv->dma_cap.estwid ? 4 * priv->dma_cap.estwid + 12 : 0);
+ seq_printf(seq, "\tDepth of GCL: %lu\n",
+ priv->dma_cap.estdep ? (BIT(priv->dma_cap.estdep) << 5) : 0);
+ seq_printf(seq, "\tQueue/Channel-Based VLAN Tag Insertion on TX: %s\n",
+ priv->dma_cap.cbtisel ? "Y" : "N");
+ seq_printf(seq, "\tNumber of Auxiliary Snapshot Inputs: %d\n",
+ priv->dma_cap.aux_snapshot_n);
+ seq_printf(seq, "\tOne-Step Timestamping for PTP over UDP/IP: %s\n",
+ priv->dma_cap.pou_ost_en ? "Y" : "N");
+ seq_printf(seq, "\tEnhanced DMA: %s\n",
+ priv->dma_cap.edma ? "Y" : "N");
+ seq_printf(seq, "\tDifferent Descriptor Cache: %s\n",
+ priv->dma_cap.ediffc ? "Y" : "N");
+ seq_printf(seq, "\tVxLAN/NVGRE: %s\n",
+ priv->dma_cap.vxn ? "Y" : "N");
+ seq_printf(seq, "\tDebug Memory Interface: %s\n",
+ priv->dma_cap.dbgmem ? "Y" : "N");
+ seq_printf(seq, "\tNumber of Policing Counters: %lu\n",
+ priv->dma_cap.pcsel ? BIT(priv->dma_cap.pcsel + 3) : 0);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(stmmac_dma_cap);
@@ -6788,6 +6915,56 @@ int stmmac_xsk_wakeup(struct net_device *dev, u32 queue, u32 flags)
return 0;
}
+static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ u32 tx_cnt = priv->plat->tx_queues_to_use;
+ u32 rx_cnt = priv->plat->rx_queues_to_use;
+ unsigned int start;
+ int q;
+
+ for (q = 0; q < tx_cnt; q++) {
+ struct stmmac_txq_stats *txq_stats = &priv->dma_conf.tx_queue[q].txq_stats;
+ u64 tx_packets;
+ u64 tx_bytes;
+
+ do {
+ start = u64_stats_fetch_begin(&txq_stats->syncp);
+ tx_packets = txq_stats->tx_packets;
+ tx_bytes = txq_stats->tx_bytes;
+ } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+
+ stats->tx_packets += tx_packets;
+ stats->tx_bytes += tx_bytes;
+ }
+
+ for (q = 0; q < rx_cnt; q++) {
+ struct stmmac_rxq_stats *rxq_stats = &priv->dma_conf.rx_queue[q].rxq_stats;
+ u64 rx_packets;
+ u64 rx_bytes;
+
+ do {
+ start = u64_stats_fetch_begin(&rxq_stats->syncp);
+ rx_packets = rxq_stats->rx_packets;
+ rx_bytes = rxq_stats->rx_bytes;
+ } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+
+ stats->rx_packets += rx_packets;
+ stats->rx_bytes += rx_bytes;
+ }
+
+ stats->rx_dropped = priv->xstats.rx_dropped;
+ stats->rx_errors = priv->xstats.rx_errors;
+ stats->tx_dropped = priv->xstats.tx_dropped;
+ stats->tx_errors = priv->xstats.tx_errors;
+ stats->tx_carrier_errors = priv->xstats.tx_losscarrier + priv->xstats.tx_carrier;
+ stats->collisions = priv->xstats.tx_collision + priv->xstats.rx_collision;
+ stats->rx_length_errors = priv->xstats.rx_length;
+ stats->rx_crc_errors = priv->xstats.rx_crc_errors;
+ stats->rx_over_errors = priv->xstats.rx_overflow_cntr;
+ stats->rx_missed_errors = priv->xstats.rx_missed_cntr;
+}
+
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
@@ -6798,6 +6975,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
.ndo_set_rx_mode = stmmac_set_rx_mode,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_eth_ioctl = stmmac_ioctl,
+ .ndo_get_stats64 = stmmac_get_stats64,
.ndo_setup_tc = stmmac_setup_tc,
.ndo_select_queue = stmmac_select_queue,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -6855,7 +7033,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
int ret;
/* dwmac-sun8i only work in chain mode */
- if (priv->plat->has_sun8i)
+ if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I)
chain_mode = 1;
priv->chain_mode = chain_mode;
@@ -6876,7 +7054,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
*/
priv->plat->enh_desc = priv->dma_cap.enh_desc;
priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up &&
- !priv->plat->use_phy_wol;
+ !(priv->plat->flags & STMMAC_FLAG_USE_PHY_WOL);
priv->hw->pmt = priv->plat->pmt;
if (priv->dma_cap.hash_tb_sz) {
priv->hw->multicast_filter_bins =
@@ -6920,7 +7098,8 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
if (priv->dma_cap.tsoen)
dev_info(priv->device, "TSO supported\n");
- priv->hw->vlan_fail_q_en = priv->plat->vlan_fail_q_en;
+ priv->hw->vlan_fail_q_en =
+ (priv->plat->flags & STMMAC_FLAG_VLAN_FAIL_Q_EN);
priv->hw->vlan_fail_q = priv->plat->vlan_fail_q;
/* Run HW quirks, if any */
@@ -7160,12 +7339,18 @@ int stmmac_dvr_probe(struct device *device,
priv->device = device;
priv->dev = ndev;
+ for (i = 0; i < MTL_MAX_RX_QUEUES; i++)
+ u64_stats_init(&priv->dma_conf.rx_queue[i].rxq_stats.syncp);
+ for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
+ u64_stats_init(&priv->dma_conf.tx_queue[i].txq_stats.syncp);
+
stmmac_set_ethtool_ops(ndev);
priv->pause = pause;
priv->plat = plat_dat;
priv->ioaddr = res->addr;
priv->dev->base_addr = (unsigned long)res->addr;
- priv->plat->dma_cfg->multi_msi_en = priv->plat->multi_msi_en;
+ priv->plat->dma_cfg->multi_msi_en =
+ (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN);
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
@@ -7249,7 +7434,7 @@ int stmmac_dvr_probe(struct device *device,
ndev->hw_features |= NETIF_F_HW_TC;
}
- if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
+ if ((priv->plat->flags & STMMAC_FLAG_TSO_EN) && (priv->dma_cap.tsoen)) {
ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
if (priv->plat->has_gmac4)
ndev->hw_features |= NETIF_F_GSO_UDP_L4;
@@ -7257,7 +7442,8 @@ int stmmac_dvr_probe(struct device *device,
dev_info(priv->device, "TSO feature enabled\n");
}
- if (priv->dma_cap.sphen && !priv->plat->sph_disable) {
+ if (priv->dma_cap.sphen &&
+ !(priv->plat->flags & STMMAC_FLAG_SPH_DISABLE)) {
ndev->hw_features |= NETIF_F_GRO;
priv->sph_cap = true;
priv->sph = priv->sph_cap;
@@ -7315,6 +7501,8 @@ int stmmac_dvr_probe(struct device *device,
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);
+ priv->xstats.threshold = tc;
+
/* Initialize RSS */
rxq = priv->plat->rx_queues_to_use;
netdev_rss_key_fill(priv->rss.key, sizeof(priv->rss.key));
@@ -7621,7 +7809,8 @@ int stmmac_resume(struct device *dev)
stmmac_mdio_reset(priv->mii);
}
- if (!priv->plat->serdes_up_after_phy_linkup && priv->plat->serdes_powerup) {
+ if (!(priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) &&
+ priv->plat->serdes_powerup) {
ret = priv->plat->serdes_powerup(ndev,
priv->plat->bsp_priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 3db1cb0fd160..fa9e7e7040b9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -62,11 +62,16 @@ static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
int phyreg, u32 *hw_addr)
{
- u32 tmp;
+ u32 tmp = 0;
+ if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
+ /* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those
+ * bits above bit 3 of XGMAC_MDIO_C22P register are reserved.
+ */
+ tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
+ tmp &= ~MII_XGMAC_C22P_MASK;
+ }
/* Set port as Clause 22 */
- tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
- tmp &= ~MII_XGMAC_C22P_MASK;
tmp |= BIT(phyaddr);
writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
@@ -132,8 +137,9 @@ static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
priv = netdev_priv(ndev);
- /* HW does not support C22 addr >= 4 */
- if (phyaddr > MII_XGMAC_MAX_C22ADDR)
+ /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
+ if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
+ phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
@@ -209,8 +215,9 @@ static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
priv = netdev_priv(ndev);
- /* HW does not support C22 addr >= 4 */
- if (phyaddr > MII_XGMAC_MAX_C22ADDR)
+ /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
+ if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
+ phyaddr > MII_XGMAC_MAX_C22ADDR)
return -ENODEV;
stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
@@ -526,11 +533,11 @@ int stmmac_mdio_register(struct net_device *ndev)
int err = 0;
struct mii_bus *new_bus;
struct stmmac_priv *priv = netdev_priv(ndev);
- struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
struct device_node *mdio_node = priv->plat->mdio_node;
struct device *dev = ndev->dev.parent;
struct fwnode_handle *fixed_node;
+ struct fwnode_handle *fwnode;
int addr, found, max_addr;
if (!mdio_bus_data)
@@ -551,13 +558,18 @@ int stmmac_mdio_register(struct net_device *ndev)
new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
- /* Right now only C22 phys are supported */
- max_addr = MII_XGMAC_MAX_C22ADDR + 1;
+ if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
+ /* Right now only C22 phys are supported */
+ max_addr = MII_XGMAC_MAX_C22ADDR + 1;
- /* Check if DT specified an unsupported phy addr */
- if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
- dev_err(dev, "Unsupported phy_addr (max=%d)\n",
+ /* Check if DT specified an unsupported phy addr */
+ if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
+ dev_err(dev, "Unsupported phy_addr (max=%d)\n",
MII_XGMAC_MAX_C22ADDR);
+ } else {
+ /* XGMAC version 2.20 onwards support 32 phy addr */
+ max_addr = PHY_MAX_ADDR;
+ }
} else {
new_bus->read = &stmmac_mdio_read_c22;
new_bus->write = &stmmac_mdio_write_c22;
@@ -589,6 +601,7 @@ int stmmac_mdio_register(struct net_device *ndev)
stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
/* If fixed-link is set, skip PHY scanning */
+ fwnode = priv->plat->port_node;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 644bb54f5f02..352b01678c22 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -77,7 +77,7 @@ static int snps_gmac5_default_data(struct pci_dev *pdev,
plat->clk_csr = 5;
plat->has_gmac4 = 1;
plat->force_sf_dma_mode = 1;
- plat->tso_en = 1;
+ plat->flags |= STMMAC_FLAG_TSO_EN;
plat->pmt = 1;
/* Set default value for multicast hash bins */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 231152ee5a32..35f4b1484029 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -15,7 +15,6 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_net.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include "stmmac.h"
@@ -420,16 +419,16 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
return ERR_PTR(phy_mode);
plat->phy_interface = phy_mode;
- plat->interface = stmmac_of_get_mac_mode(np);
- if (plat->interface < 0)
- plat->interface = plat->phy_interface;
+ plat->mac_interface = stmmac_of_get_mac_mode(np);
+ if (plat->mac_interface < 0)
+ plat->mac_interface = plat->phy_interface;
/* Some wrapper drivers still rely on phy_node. Let's save it while
* they are not converted to phylink. */
plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
/* PHYLINK automatically parses the phy-handle property */
- plat->phylink_node = np;
+ plat->port_node = of_fwnode_handle(np);
/* Get max speed of operation from device tree */
of_property_read_u32(np, "max-speed", &plat->max_speed);
@@ -466,8 +465,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
plat->force_sf_dma_mode =
of_property_read_bool(np, "snps,force_sf_dma_mode");
- plat->en_tx_lpi_clockgating =
- of_property_read_bool(np, "snps,en-tx-lpi-clockgating");
+ if (of_property_read_bool(np, "snps,en-tx-lpi-clockgating"))
+ plat->flags |= STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
/* Set the maxmtu to a default of JUMBO_LEN in case the
* parameter is not present in the device tree.
@@ -525,7 +524,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
plat->has_gmac4 = 1;
plat->has_gmac = 0;
plat->pmt = 1;
- plat->tso_en = of_property_read_bool(np, "snps,tso");
+ if (of_property_read_bool(np, "snps,tso"))
+ plat->flags |= STMMAC_FLAG_TSO_EN;
}
if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
@@ -538,7 +538,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
if (of_device_is_compatible(np, "snps,dwxgmac")) {
plat->has_xgmac = 1;
plat->pmt = 1;
- plat->tso_en = of_property_read_bool(np, "snps,tso");
+ if (of_property_read_bool(np, "snps,tso"))
+ plat->flags |= STMMAC_FLAG_TSO_EN;
}
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index b4388ca8d211..3d7825cb30bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -192,7 +192,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
write_unlock_irqrestore(&priv->ptp_lock, flags);
break;
case PTP_CLK_REQ_EXTTS:
- priv->plat->ext_snapshot_en = on;
+ if (on)
+ priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN;
+ else
+ priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
mutex_lock(&priv->aux_ts_lock);
acr_value = readl(ptpaddr + PTP_ACR);
acr_value &= ~PTP_ACR_MASK;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index bf619295d079..d1fe4b46f162 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -26,6 +26,12 @@
#define PTP_ACR 0x40 /* Auxiliary Control Reg */
#define PTP_ATNR 0x48 /* Auxiliary Timestamp - Nanoseconds Reg */
#define PTP_ATSR 0x4c /* Auxiliary Timestamp - Seconds Reg */
+#define PTP_TS_INGR_CORR_NS 0x58 /* Ingress timestamp correction nanoseconds */
+#define PTP_TS_EGR_CORR_NS 0x5C /* Egress timestamp correction nanoseconds*/
+#define PTP_TS_INGR_CORR_SNS 0x60 /* Ingress timestamp correction subnanoseconds */
+#define PTP_TS_EGR_CORR_SNS 0x64 /* Egress timestamp correction subnanoseconds */
+#define PTP_TS_INGR_LAT 0x68 /* MAC internal Ingress Latency */
+#define PTP_TS_EGR_LAT 0x6c /* MAC internal Egress Latency */
#define PTP_STNSUR_ADDSUB_SHIFT 31
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index 687f43cd466c..f9e43fc32ee8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -1355,7 +1355,7 @@ static int __stmmac_test_l3filt(struct stmmac_priv *priv, u32 dst, u32 src,
goto cleanup_rss;
}
- dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_IPV4_ADDRS);
+ dissector->used_keys |= (1ULL << FLOW_DISSECTOR_KEY_IPV4_ADDRS);
dissector->offset[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = 0;
cls = kzalloc(sizeof(*cls), GFP_KERNEL);
@@ -1481,8 +1481,8 @@ static int __stmmac_test_l4filt(struct stmmac_priv *priv, u32 dst, u32 src,
goto cleanup_rss;
}
- dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_BASIC);
- dissector->used_keys |= (1 << FLOW_DISSECTOR_KEY_PORTS);
+ dissector->used_keys |= (1ULL << FLOW_DISSECTOR_KEY_BASIC);
+ dissector->used_keys |= (1ULL << FLOW_DISSECTOR_KEY_PORTS);
dissector->offset[FLOW_DISSECTOR_KEY_BASIC] = 0;
dissector->offset[FLOW_DISSECTOR_KEY_PORTS] = offsetof(typeof(keys), key);
diff --git a/drivers/net/ethernet/sun/ldmvsw.c b/drivers/net/ethernet/sun/ldmvsw.c
index 734a817d3c94..a9a6670b5ff1 100644
--- a/drivers/net/ethernet/sun/ldmvsw.c
+++ b/drivers/net/ethernet/sun/ldmvsw.c
@@ -124,7 +124,7 @@ static void vsw_set_rx_mode(struct net_device *dev)
return sunvnet_set_rx_mode_common(dev, port->vp);
}
-int ldmvsw_open(struct net_device *dev)
+static int ldmvsw_open(struct net_device *dev)
{
struct vnet_port *port = netdev_priv(dev);
struct vio_driver_state *vio = &port->vio;
@@ -136,7 +136,6 @@ int ldmvsw_open(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL_GPL(ldmvsw_open);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void vsw_poll_controller(struct net_device *dev)
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 7a2e76776297..011d74087f86 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -31,7 +31,7 @@
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include "niu.h"
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index 34b94153bf0c..cc34d92d2e3d 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -25,7 +25,7 @@
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/gfp.h>
#include <asm/auxio.h>
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 4154e68639ac..9bd1df8308d2 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -40,6 +40,7 @@
#include <linux/bitops.h>
#include <linux/mm.h>
#include <linux/gfp.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index b93613cd1994..b983b9c23be6 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -32,9 +32,10 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/of_device.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 6418fcc3139f..b37360f44972 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -27,8 +27,8 @@
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pgtable.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index fce06663e1e1..88b5b1b47779 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -183,4 +183,29 @@ config CPMAC
help
TI AR7 CPMAC Ethernet support
+config TI_ICSSG_PRUETH
+ tristate "TI Gigabit PRU Ethernet driver"
+ select PHYLIB
+ select TI_ICSS_IEP
+ depends on PRU_REMOTEPROC
+ depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
+ help
+ Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
+ This subsystem is available starting with the AM65 platform.
+
+ This driver requires firmware binaries which will run on the PRUs
+ to support the Ethernet operation. Currently, it supports Ethernet
+ with 1G and 100M link speed.
+
+config TI_ICSS_IEP
+ tristate "TI PRU ICSS IEP driver"
+ depends on TI_PRUSS
+ default TI_PRUSS
+ help
+ This driver enables support for the PRU-ICSS Industrial Ethernet
+ Peripheral within a PRU-ICSS subsystem present on various TI SoCs.
+
+ To compile this driver as a module, choose M here. The module
+ will be called icss_iep.
+
endif # NET_VENDOR_TI
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 75f761efbea7..34fd7a716ba6 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -28,3 +28,14 @@ obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o k3-cppi-desc-pool.o am65-cpsw-qos.o
ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
+
+obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg-prueth.o
+icssg-prueth-y := k3-cppi-desc-pool.o \
+ icssg/icssg_prueth.o \
+ icssg/icssg_classifier.o \
+ icssg/icssg_queues.o \
+ icssg/icssg_config.o \
+ icssg/icssg_mii_cfg.o \
+ icssg/icssg_stats.o \
+ icssg/icssg_ethtool.o
+obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index bebcfd5e6b57..bea6fc0f324c 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -19,6 +19,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <linux/phylink.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index bf40c88fbd9b..f3dad2ab9828 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -192,7 +192,6 @@ struct am65_cpsw_ndev_priv {
extern const struct ethtool_ops am65_cpsw_ethtool_ops_slave;
-void am65_cpsw_nuss_adjust_link(struct net_device *ndev);
void am65_cpsw_nuss_set_p0_ptype(struct am65_cpsw_common *common);
void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common);
int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx);
diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.c b/drivers/net/ethernet/ti/am65-cpsw-qos.c
index eced87fa261c..9ac2ff05d501 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-qos.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-qos.c
@@ -624,9 +624,9 @@ static int am65_cpsw_qos_clsflower_add_policer(struct am65_cpsw_port *port,
int ret;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported keys used");
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c
index bfa81bbfce3f..26dc906eae90 100644
--- a/drivers/net/ethernet/ti/cpsw-common.c
+++ b/drivers/net/ethernet/ti/cpsw-common.c
@@ -3,7 +3,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c
index 25e707d7b87c..4edb7963f856 100644
--- a/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -12,7 +12,6 @@
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include "cpsw.h"
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index f9cd566d1c9b..ca4d4548f85e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -31,7 +31,7 @@
#include <linux/if_vlan.h>
#include <linux/kmemleak.h>
#include <linux/sys_soc.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
index c61e4e44a78f..0e4f526b1753 100644
--- a/drivers/net/ethernet/ti/cpsw_new.c
+++ b/drivers/net/ethernet/ti/cpsw_new.c
@@ -30,7 +30,7 @@
#include <linux/sys_soc.h>
#include <net/switchdev.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/pkt_cls.h>
#include <net/devlink.h>
diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c
index e966dd47e2db..0ec85635dfd6 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.c
+++ b/drivers/net/ethernet/ti/cpsw_priv.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/skbuff.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
@@ -1396,9 +1396,9 @@ static int cpsw_qos_clsflower_add_policer(struct cpsw_priv *priv,
int ret;
if (dissector->used_keys &
- ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+ ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
NL_SET_ERR_MSG_MOD(extack,
"Unsupported keys used");
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h
index 34230145ca0b..0e27c433098d 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.h
+++ b/drivers/net/ethernet/ti/cpsw_priv.h
@@ -6,6 +6,7 @@
#ifndef DRIVERS_NET_ETHERNET_TI_CPSW_PRIV_H_
#define DRIVERS_NET_ETHERNET_TI_CPSW_PRIV_H_
+#include <net/xdp.h>
#include <uapi/linux/bpf.h>
#include "davinci_cpdma.h"
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 23169e36a3d4..89b6d23e9937 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -23,7 +23,6 @@
#include <linux/pm_runtime.h>
#include <linux/davinci_emac.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mdio-bitbang.h>
diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.c b/drivers/net/ethernet/ti/icssg/icss_iep.c
new file mode 100644
index 000000000000..4cf2a52e4378
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icss_iep.c
@@ -0,0 +1,965 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments ICSSG Industrial Ethernet Peripheral (IEP) Driver
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/timekeeping.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+
+#include "icss_iep.h"
+
+#define IEP_MAX_DEF_INC 0xf
+#define IEP_MAX_COMPEN_INC 0xfff
+#define IEP_MAX_COMPEN_COUNT 0xffffff
+
+#define IEP_GLOBAL_CFG_CNT_ENABLE BIT(0)
+#define IEP_GLOBAL_CFG_DEFAULT_INC_MASK GENMASK(7, 4)
+#define IEP_GLOBAL_CFG_DEFAULT_INC_SHIFT 4
+#define IEP_GLOBAL_CFG_COMPEN_INC_MASK GENMASK(19, 8)
+#define IEP_GLOBAL_CFG_COMPEN_INC_SHIFT 8
+
+#define IEP_GLOBAL_STATUS_CNT_OVF BIT(0)
+
+#define IEP_CMP_CFG_SHADOW_EN BIT(17)
+#define IEP_CMP_CFG_CMP0_RST_CNT_EN BIT(0)
+#define IEP_CMP_CFG_CMP_EN(cmp) (GENMASK(16, 1) & (1 << ((cmp) + 1)))
+
+#define IEP_CMP_STATUS(cmp) (1 << (cmp))
+
+#define IEP_SYNC_CTRL_SYNC_EN BIT(0)
+#define IEP_SYNC_CTRL_SYNC_N_EN(n) (GENMASK(2, 1) & (BIT(1) << (n)))
+
+#define IEP_MIN_CMP 0
+#define IEP_MAX_CMP 15
+
+#define ICSS_IEP_64BIT_COUNTER_SUPPORT BIT(0)
+#define ICSS_IEP_SLOW_COMPEN_REG_SUPPORT BIT(1)
+#define ICSS_IEP_SHADOW_MODE_SUPPORT BIT(2)
+
+#define LATCH_INDEX(ts_index) ((ts_index) + 6)
+#define IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n))
+#define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10)
+
+enum {
+ ICSS_IEP_GLOBAL_CFG_REG,
+ ICSS_IEP_GLOBAL_STATUS_REG,
+ ICSS_IEP_COMPEN_REG,
+ ICSS_IEP_SLOW_COMPEN_REG,
+ ICSS_IEP_COUNT_REG0,
+ ICSS_IEP_COUNT_REG1,
+ ICSS_IEP_CAPTURE_CFG_REG,
+ ICSS_IEP_CAPTURE_STAT_REG,
+
+ ICSS_IEP_CAP6_RISE_REG0,
+ ICSS_IEP_CAP6_RISE_REG1,
+
+ ICSS_IEP_CAP7_RISE_REG0,
+ ICSS_IEP_CAP7_RISE_REG1,
+
+ ICSS_IEP_CMP_CFG_REG,
+ ICSS_IEP_CMP_STAT_REG,
+ ICSS_IEP_CMP0_REG0,
+ ICSS_IEP_CMP0_REG1,
+ ICSS_IEP_CMP1_REG0,
+ ICSS_IEP_CMP1_REG1,
+
+ ICSS_IEP_CMP8_REG0,
+ ICSS_IEP_CMP8_REG1,
+ ICSS_IEP_SYNC_CTRL_REG,
+ ICSS_IEP_SYNC0_STAT_REG,
+ ICSS_IEP_SYNC1_STAT_REG,
+ ICSS_IEP_SYNC_PWIDTH_REG,
+ ICSS_IEP_SYNC0_PERIOD_REG,
+ ICSS_IEP_SYNC1_DELAY_REG,
+ ICSS_IEP_SYNC_START_REG,
+ ICSS_IEP_MAX_REGS,
+};
+
+/**
+ * struct icss_iep_plat_data - Plat data to handle SoC variants
+ * @config: Regmap configuration data
+ * @reg_offs: register offsets to capture offset differences across SoCs
+ * @flags: Flags to represent IEP properties
+ */
+struct icss_iep_plat_data {
+ struct regmap_config *config;
+ u32 reg_offs[ICSS_IEP_MAX_REGS];
+ u32 flags;
+};
+
+struct icss_iep {
+ struct device *dev;
+ void __iomem *base;
+ const struct icss_iep_plat_data *plat_data;
+ struct regmap *map;
+ struct device_node *client_np;
+ unsigned long refclk_freq;
+ int clk_tick_time; /* one refclk tick time in ns */
+ struct ptp_clock_info ptp_info;
+ struct ptp_clock *ptp_clock;
+ struct mutex ptp_clk_mutex; /* PHC access serializer */
+ spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */
+ u32 def_inc;
+ s16 slow_cmp_inc;
+ u32 slow_cmp_count;
+ const struct icss_iep_clockops *ops;
+ void *clockops_data;
+ u32 cycle_time_ns;
+ u32 perout_enabled;
+ bool pps_enabled;
+ int cap_cmp_irq;
+ u64 period;
+ u32 latch_enable;
+};
+
+/**
+ * icss_iep_get_count_hi() - Get the upper 32 bit IEP counter
+ * @iep: Pointer to structure representing IEP.
+ *
+ * Return: upper 32 bit IEP counter
+ */
+int icss_iep_get_count_hi(struct icss_iep *iep)
+{
+ u32 val = 0;
+
+ if (iep && (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT))
+ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(icss_iep_get_count_hi);
+
+/**
+ * icss_iep_get_count_low() - Get the lower 32 bit IEP counter
+ * @iep: Pointer to structure representing IEP.
+ *
+ * Return: lower 32 bit IEP counter
+ */
+int icss_iep_get_count_low(struct icss_iep *iep)
+{
+ u32 val = 0;
+
+ if (iep)
+ val = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(icss_iep_get_count_low);
+
+/**
+ * icss_iep_get_ptp_clock_idx() - Get PTP clock index using IEP driver
+ * @iep: Pointer to structure representing IEP.
+ *
+ * Return: PTP clock index, -1 if not registered
+ */
+int icss_iep_get_ptp_clock_idx(struct icss_iep *iep)
+{
+ if (!iep || !iep->ptp_clock)
+ return -1;
+ return ptp_clock_index(iep->ptp_clock);
+}
+EXPORT_SYMBOL_GPL(icss_iep_get_ptp_clock_idx);
+
+static void icss_iep_set_counter(struct icss_iep *iep, u64 ns)
+{
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ writel(upper_32_bits(ns), iep->base +
+ iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]);
+ writel(upper_32_bits(ns), iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]);
+}
+
+static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns);
+
+/**
+ * icss_iep_settime() - Set time of the PTP clock using IEP driver
+ * @iep: Pointer to structure representing IEP.
+ * @ns: Time to be set in nanoseconds
+ *
+ * This API uses writel() instead of regmap_write() for write operations as
+ * regmap_write() is too slow and this API is time sensitive.
+ */
+static void icss_iep_settime(struct icss_iep *iep, u64 ns)
+{
+ unsigned long flags;
+
+ if (iep->ops && iep->ops->settime) {
+ iep->ops->settime(iep->clockops_data, ns);
+ return;
+ }
+
+ spin_lock_irqsave(&iep->irq_lock, flags);
+ if (iep->pps_enabled || iep->perout_enabled)
+ writel(0, iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]);
+
+ icss_iep_set_counter(iep, ns);
+
+ if (iep->pps_enabled || iep->perout_enabled) {
+ icss_iep_update_to_next_boundary(iep, ns);
+ writel(IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN,
+ iep->base + iep->plat_data->reg_offs[ICSS_IEP_SYNC_CTRL_REG]);
+ }
+ spin_unlock_irqrestore(&iep->irq_lock, flags);
+}
+
+/**
+ * icss_iep_gettime() - Get time of the PTP clock using IEP driver
+ * @iep: Pointer to structure representing IEP.
+ * @sts: Pointer to structure representing PTP system timestamp.
+ *
+ * This API uses readl() instead of regmap_read() for read operations as
+ * regmap_read() is too slow and this API is time sensitive.
+ *
+ * Return: The current timestamp of the PTP clock using IEP driver
+ */
+static u64 icss_iep_gettime(struct icss_iep *iep,
+ struct ptp_system_timestamp *sts)
+{
+ u32 ts_hi = 0, ts_lo;
+ unsigned long flags;
+
+ if (iep->ops && iep->ops->gettime)
+ return iep->ops->gettime(iep->clockops_data, sts);
+
+ /* use local_irq_x() to make it work for both RT/non-RT */
+ local_irq_save(flags);
+
+ /* no need to play with hi-lo, hi is latched when lo is read */
+ ptp_read_system_prets(sts);
+ ts_lo = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG0]);
+ ptp_read_system_postts(sts);
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ ts_hi = readl(iep->base + iep->plat_data->reg_offs[ICSS_IEP_COUNT_REG1]);
+
+ local_irq_restore(flags);
+
+ return (u64)ts_lo | (u64)ts_hi << 32;
+}
+
+static void icss_iep_enable(struct icss_iep *iep)
+{
+ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG,
+ IEP_GLOBAL_CFG_CNT_ENABLE,
+ IEP_GLOBAL_CFG_CNT_ENABLE);
+}
+
+static void icss_iep_disable(struct icss_iep *iep)
+{
+ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG,
+ IEP_GLOBAL_CFG_CNT_ENABLE,
+ 0);
+}
+
+static void icss_iep_enable_shadow_mode(struct icss_iep *iep)
+{
+ u32 cycle_time;
+ int cmp;
+
+ cycle_time = iep->cycle_time_ns - iep->def_inc;
+
+ icss_iep_disable(iep);
+
+ /* disable shadow mode */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_SHADOW_EN, 0);
+
+ /* enable shadow mode */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_SHADOW_EN, IEP_CMP_CFG_SHADOW_EN);
+
+ /* clear counters */
+ icss_iep_set_counter(iep, 0);
+
+ /* clear overflow status */
+ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_STATUS_REG,
+ IEP_GLOBAL_STATUS_CNT_OVF,
+ IEP_GLOBAL_STATUS_CNT_OVF);
+
+ /* clear compare status */
+ for (cmp = IEP_MIN_CMP; cmp < IEP_MAX_CMP; cmp++) {
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_STAT_REG,
+ IEP_CMP_STATUS(cmp), IEP_CMP_STATUS(cmp));
+ }
+
+ /* enable reset counter on CMP0 event */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP0_RST_CNT_EN,
+ IEP_CMP_CFG_CMP0_RST_CNT_EN);
+ /* enable compare */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP_EN(0),
+ IEP_CMP_CFG_CMP_EN(0));
+
+ /* set CMP0 value to cycle time */
+ regmap_write(iep->map, ICSS_IEP_CMP0_REG0, cycle_time);
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ regmap_write(iep->map, ICSS_IEP_CMP0_REG1, cycle_time);
+
+ icss_iep_set_counter(iep, 0);
+ icss_iep_enable(iep);
+}
+
+static void icss_iep_set_default_inc(struct icss_iep *iep, u8 def_inc)
+{
+ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG,
+ IEP_GLOBAL_CFG_DEFAULT_INC_MASK,
+ def_inc << IEP_GLOBAL_CFG_DEFAULT_INC_SHIFT);
+}
+
+static void icss_iep_set_compensation_inc(struct icss_iep *iep, u16 compen_inc)
+{
+ struct device *dev = regmap_get_device(iep->map);
+
+ if (compen_inc > IEP_MAX_COMPEN_INC) {
+ dev_err(dev, "%s: too high compensation inc %d\n",
+ __func__, compen_inc);
+ compen_inc = IEP_MAX_COMPEN_INC;
+ }
+
+ regmap_update_bits(iep->map, ICSS_IEP_GLOBAL_CFG_REG,
+ IEP_GLOBAL_CFG_COMPEN_INC_MASK,
+ compen_inc << IEP_GLOBAL_CFG_COMPEN_INC_SHIFT);
+}
+
+static void icss_iep_set_compensation_count(struct icss_iep *iep,
+ u32 compen_count)
+{
+ struct device *dev = regmap_get_device(iep->map);
+
+ if (compen_count > IEP_MAX_COMPEN_COUNT) {
+ dev_err(dev, "%s: too high compensation count %d\n",
+ __func__, compen_count);
+ compen_count = IEP_MAX_COMPEN_COUNT;
+ }
+
+ regmap_write(iep->map, ICSS_IEP_COMPEN_REG, compen_count);
+}
+
+static void icss_iep_set_slow_compensation_count(struct icss_iep *iep,
+ u32 compen_count)
+{
+ regmap_write(iep->map, ICSS_IEP_SLOW_COMPEN_REG, compen_count);
+}
+
+/* PTP PHC operations */
+static int icss_iep_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info);
+ s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
+ u32 cyc_count;
+ u16 cmp_inc;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+
+ /* ppb is amount of frequency we want to adjust in 1GHz (billion)
+ * e.g. 100ppb means we need to speed up clock by 100Hz
+ * i.e. at end of 1 second (1 billion ns) clock time, we should be
+ * counting 100 more ns.
+ * We use IEP slow compensation to achieve continuous freq. adjustment.
+ * There are 2 parts. Cycle time and adjustment per cycle.
+ * Simplest case would be 1 sec Cycle time. Then adjustment
+ * pre cycle would be (def_inc + ppb) value.
+ * Cycle time will have to be chosen based on how worse the ppb is.
+ * e.g. smaller the ppb, cycle time has to be large.
+ * The minimum adjustment we can do is +-1ns per cycle so let's
+ * reduce the cycle time to get 1ns per cycle adjustment.
+ * 1ppb = 1sec cycle time & 1ns adjust
+ * 1000ppb = 1/1000 cycle time & 1ns adjust per cycle
+ */
+
+ if (iep->cycle_time_ns)
+ iep->slow_cmp_inc = iep->clk_tick_time; /* 4ns adj per cycle */
+ else
+ iep->slow_cmp_inc = 1; /* 1ns adjust per cycle */
+
+ if (ppb < 0) {
+ iep->slow_cmp_inc = -iep->slow_cmp_inc;
+ ppb = -ppb;
+ }
+
+ cyc_count = NSEC_PER_SEC; /* 1s cycle time @1GHz */
+ cyc_count /= ppb; /* cycle time per ppb */
+
+ /* slow_cmp_count is decremented every clock cycle, e.g. @250MHz */
+ if (!iep->cycle_time_ns)
+ cyc_count /= iep->clk_tick_time;
+ iep->slow_cmp_count = cyc_count;
+
+ /* iep->clk_tick_time is def_inc */
+ cmp_inc = iep->clk_tick_time + iep->slow_cmp_inc;
+ icss_iep_set_compensation_inc(iep, cmp_inc);
+ icss_iep_set_slow_compensation_count(iep, iep->slow_cmp_count);
+
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return 0;
+}
+
+static int icss_iep_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info);
+ s64 ns;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+ if (iep->ops && iep->ops->adjtime) {
+ iep->ops->adjtime(iep->clockops_data, delta);
+ } else {
+ ns = icss_iep_gettime(iep, NULL);
+ ns += delta;
+ icss_iep_settime(iep, ns);
+ }
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return 0;
+}
+
+static int icss_iep_ptp_gettimeex(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info);
+ u64 ns;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+ ns = icss_iep_gettime(iep, sts);
+ *ts = ns_to_timespec64(ns);
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return 0;
+}
+
+static int icss_iep_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info);
+ u64 ns;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+ ns = timespec64_to_ns(ts);
+ icss_iep_settime(iep, ns);
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return 0;
+}
+
+static void icss_iep_update_to_next_boundary(struct icss_iep *iep, u64 start_ns)
+{
+ u64 ns, p_ns;
+ u32 offset;
+
+ ns = icss_iep_gettime(iep, NULL);
+ if (start_ns < ns)
+ start_ns = ns;
+ p_ns = iep->period;
+ /* Round up to next period boundary */
+ start_ns += p_ns - 1;
+ offset = do_div(start_ns, p_ns);
+ start_ns = start_ns * p_ns;
+ /* If it is too close to update, shift to next boundary */
+ if (p_ns - offset < 10)
+ start_ns += p_ns;
+
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(start_ns));
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(start_ns));
+}
+
+static int icss_iep_perout_enable_hw(struct icss_iep *iep,
+ struct ptp_perout_request *req, int on)
+{
+ int ret;
+ u64 cmp;
+
+ if (iep->ops && iep->ops->perout_enable) {
+ ret = iep->ops->perout_enable(iep->clockops_data, req, on, &cmp);
+ if (ret)
+ return ret;
+
+ if (on) {
+ /* Configure CMP */
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, lower_32_bits(cmp));
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, upper_32_bits(cmp));
+ /* Configure SYNC, 1ms pulse width */
+ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, 1000000);
+ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
+ regmap_write(iep->map, ICSS_IEP_SYNC_START_REG, 0);
+ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0); /* one-shot mode */
+ /* Enable CMP 1 */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
+ } else {
+ /* Disable CMP 1 */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP_EN(1), 0);
+
+ /* clear regs */
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0);
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0);
+ }
+ } else {
+ if (on) {
+ u64 start_ns;
+
+ iep->period = ((u64)req->period.sec * NSEC_PER_SEC) +
+ req->period.nsec;
+ start_ns = ((u64)req->period.sec * NSEC_PER_SEC)
+ + req->period.nsec;
+ icss_iep_update_to_next_boundary(iep, start_ns);
+
+ /* Enable Sync in single shot mode */
+ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG,
+ IEP_SYNC_CTRL_SYNC_N_EN(0) | IEP_SYNC_CTRL_SYNC_EN);
+ /* Enable CMP 1 */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP_EN(1), IEP_CMP_CFG_CMP_EN(1));
+ } else {
+ /* Disable CMP 1 */
+ regmap_update_bits(iep->map, ICSS_IEP_CMP_CFG_REG,
+ IEP_CMP_CFG_CMP_EN(1), 0);
+
+ /* clear CMP regs */
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG0, 0);
+ if (iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT)
+ regmap_write(iep->map, ICSS_IEP_CMP1_REG1, 0);
+
+ /* Disable sync */
+ regmap_write(iep->map, ICSS_IEP_SYNC_CTRL_REG, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int icss_iep_perout_enable(struct icss_iep *iep,
+ struct ptp_perout_request *req, int on)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+
+ if (iep->pps_enabled) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ if (iep->perout_enabled == !!on)
+ goto exit;
+
+ spin_lock_irqsave(&iep->irq_lock, flags);
+ ret = icss_iep_perout_enable_hw(iep, req, on);
+ if (!ret)
+ iep->perout_enabled = !!on;
+ spin_unlock_irqrestore(&iep->irq_lock, flags);
+
+exit:
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return ret;
+}
+
+static int icss_iep_pps_enable(struct icss_iep *iep, int on)
+{
+ struct ptp_clock_request rq;
+ struct timespec64 ts;
+ unsigned long flags;
+ int ret = 0;
+ u64 ns;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+
+ if (iep->perout_enabled) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ if (iep->pps_enabled == !!on)
+ goto exit;
+
+ spin_lock_irqsave(&iep->irq_lock, flags);
+
+ rq.perout.index = 0;
+ if (on) {
+ ns = icss_iep_gettime(iep, NULL);
+ ts = ns_to_timespec64(ns);
+ rq.perout.period.sec = 1;
+ rq.perout.period.nsec = 0;
+ rq.perout.start.sec = ts.tv_sec + 2;
+ rq.perout.start.nsec = 0;
+ ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);
+ } else {
+ ret = icss_iep_perout_enable_hw(iep, &rq.perout, on);
+ }
+
+ if (!ret)
+ iep->pps_enabled = !!on;
+
+ spin_unlock_irqrestore(&iep->irq_lock, flags);
+
+exit:
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return ret;
+}
+
+static int icss_iep_extts_enable(struct icss_iep *iep, u32 index, int on)
+{
+ u32 val, cap, ret = 0;
+
+ mutex_lock(&iep->ptp_clk_mutex);
+
+ if (iep->ops && iep->ops->extts_enable) {
+ ret = iep->ops->extts_enable(iep->clockops_data, index, on);
+ goto exit;
+ }
+
+ if (((iep->latch_enable & BIT(index)) >> index) == on)
+ goto exit;
+
+ regmap_read(iep->map, ICSS_IEP_CAPTURE_CFG_REG, &val);
+ cap = IEP_CAP_CFG_CAP_ASYNC_EN(index) | IEP_CAP_CFG_CAPNR_1ST_EVENT_EN(index);
+ if (on) {
+ val |= cap;
+ iep->latch_enable |= BIT(index);
+ } else {
+ val &= ~cap;
+ iep->latch_enable &= ~BIT(index);
+ }
+ regmap_write(iep->map, ICSS_IEP_CAPTURE_CFG_REG, val);
+
+exit:
+ mutex_unlock(&iep->ptp_clk_mutex);
+
+ return ret;
+}
+
+static int icss_iep_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct icss_iep *iep = container_of(ptp, struct icss_iep, ptp_info);
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_PEROUT:
+ return icss_iep_perout_enable(iep, &rq->perout, on);
+ case PTP_CLK_REQ_PPS:
+ return icss_iep_pps_enable(iep, on);
+ case PTP_CLK_REQ_EXTTS:
+ return icss_iep_extts_enable(iep, rq->extts.index, on);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info icss_iep_ptp_info = {
+ .owner = THIS_MODULE,
+ .name = "ICSS IEP timer",
+ .max_adj = 10000000,
+ .adjfine = icss_iep_ptp_adjfine,
+ .adjtime = icss_iep_ptp_adjtime,
+ .gettimex64 = icss_iep_ptp_gettimeex,
+ .settime64 = icss_iep_ptp_settime,
+ .enable = icss_iep_ptp_enable,
+};
+
+struct icss_iep *icss_iep_get_idx(struct device_node *np, int idx)
+{
+ struct platform_device *pdev;
+ struct device_node *iep_np;
+ struct icss_iep *iep;
+
+ iep_np = of_parse_phandle(np, "ti,iep", idx);
+ if (!iep_np || !of_device_is_available(iep_np))
+ return ERR_PTR(-ENODEV);
+
+ pdev = of_find_device_by_node(iep_np);
+ of_node_put(iep_np);
+
+ if (!pdev)
+ /* probably IEP not yet probed */
+ return ERR_PTR(-EPROBE_DEFER);
+
+ iep = platform_get_drvdata(pdev);
+ if (!iep)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ device_lock(iep->dev);
+ if (iep->client_np) {
+ device_unlock(iep->dev);
+ dev_err(iep->dev, "IEP is already acquired by %s",
+ iep->client_np->name);
+ return ERR_PTR(-EBUSY);
+ }
+ iep->client_np = np;
+ device_unlock(iep->dev);
+ get_device(iep->dev);
+
+ return iep;
+}
+EXPORT_SYMBOL_GPL(icss_iep_get_idx);
+
+struct icss_iep *icss_iep_get(struct device_node *np)
+{
+ return icss_iep_get_idx(np, 0);
+}
+EXPORT_SYMBOL_GPL(icss_iep_get);
+
+void icss_iep_put(struct icss_iep *iep)
+{
+ device_lock(iep->dev);
+ iep->client_np = NULL;
+ device_unlock(iep->dev);
+ put_device(iep->dev);
+}
+EXPORT_SYMBOL_GPL(icss_iep_put);
+
+void icss_iep_init_fw(struct icss_iep *iep)
+{
+ /* start IEP for FW use in raw 64bit mode, no PTP support */
+ iep->clk_tick_time = iep->def_inc;
+ iep->cycle_time_ns = 0;
+ iep->ops = NULL;
+ iep->clockops_data = NULL;
+ icss_iep_set_default_inc(iep, iep->def_inc);
+ icss_iep_set_compensation_inc(iep, iep->def_inc);
+ icss_iep_set_compensation_count(iep, 0);
+ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */
+ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
+ if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)
+ icss_iep_set_slow_compensation_count(iep, 0);
+
+ icss_iep_enable(iep);
+ icss_iep_settime(iep, 0);
+}
+EXPORT_SYMBOL_GPL(icss_iep_init_fw);
+
+void icss_iep_exit_fw(struct icss_iep *iep)
+{
+ icss_iep_disable(iep);
+}
+EXPORT_SYMBOL_GPL(icss_iep_exit_fw);
+
+int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops,
+ void *clockops_data, u32 cycle_time_ns)
+{
+ int ret = 0;
+
+ iep->cycle_time_ns = cycle_time_ns;
+ iep->clk_tick_time = iep->def_inc;
+ iep->ops = clkops;
+ iep->clockops_data = clockops_data;
+ icss_iep_set_default_inc(iep, iep->def_inc);
+ icss_iep_set_compensation_inc(iep, iep->def_inc);
+ icss_iep_set_compensation_count(iep, 0);
+ regmap_write(iep->map, ICSS_IEP_SYNC_PWIDTH_REG, iep->refclk_freq / 10); /* 100 ms pulse */
+ regmap_write(iep->map, ICSS_IEP_SYNC0_PERIOD_REG, 0);
+ if (iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT)
+ icss_iep_set_slow_compensation_count(iep, 0);
+
+ if (!(iep->plat_data->flags & ICSS_IEP_64BIT_COUNTER_SUPPORT) ||
+ !(iep->plat_data->flags & ICSS_IEP_SLOW_COMPEN_REG_SUPPORT))
+ goto skip_perout;
+
+ if (iep->ops && iep->ops->perout_enable) {
+ iep->ptp_info.n_per_out = 1;
+ iep->ptp_info.pps = 1;
+ }
+
+ if (iep->ops && iep->ops->extts_enable)
+ iep->ptp_info.n_ext_ts = 2;
+
+skip_perout:
+ if (cycle_time_ns)
+ icss_iep_enable_shadow_mode(iep);
+ else
+ icss_iep_enable(iep);
+ icss_iep_settime(iep, ktime_get_real_ns());
+
+ iep->ptp_clock = ptp_clock_register(&iep->ptp_info, iep->dev);
+ if (IS_ERR(iep->ptp_clock)) {
+ ret = PTR_ERR(iep->ptp_clock);
+ iep->ptp_clock = NULL;
+ dev_err(iep->dev, "Failed to register ptp clk %d\n", ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icss_iep_init);
+
+int icss_iep_exit(struct icss_iep *iep)
+{
+ if (iep->ptp_clock) {
+ ptp_clock_unregister(iep->ptp_clock);
+ iep->ptp_clock = NULL;
+ }
+ icss_iep_disable(iep);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icss_iep_exit);
+
+static int icss_iep_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct icss_iep *iep;
+ struct clk *iep_clk;
+
+ iep = devm_kzalloc(dev, sizeof(*iep), GFP_KERNEL);
+ if (!iep)
+ return -ENOMEM;
+
+ iep->dev = dev;
+ iep->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(iep->base))
+ return -ENODEV;
+
+ iep_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(iep_clk))
+ return PTR_ERR(iep_clk);
+
+ iep->refclk_freq = clk_get_rate(iep_clk);
+
+ iep->def_inc = NSEC_PER_SEC / iep->refclk_freq; /* ns per clock tick */
+ if (iep->def_inc > IEP_MAX_DEF_INC) {
+ dev_err(dev, "Failed to set def_inc %d. IEP_clock is too slow to be supported\n",
+ iep->def_inc);
+ return -EINVAL;
+ }
+
+ iep->plat_data = device_get_match_data(dev);
+ if (!iep->plat_data)
+ return -EINVAL;
+
+ iep->map = devm_regmap_init(dev, NULL, iep, iep->plat_data->config);
+ if (IS_ERR(iep->map)) {
+ dev_err(dev, "Failed to create regmap for IEP %ld\n",
+ PTR_ERR(iep->map));
+ return PTR_ERR(iep->map);
+ }
+
+ iep->ptp_info = icss_iep_ptp_info;
+ mutex_init(&iep->ptp_clk_mutex);
+ spin_lock_init(&iep->irq_lock);
+ dev_set_drvdata(dev, iep);
+ icss_iep_disable(iep);
+
+ return 0;
+}
+
+static bool am654_icss_iep_valid_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ICSS_IEP_GLOBAL_CFG_REG ... ICSS_IEP_SYNC_START_REG:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static int icss_iep_regmap_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct icss_iep *iep = context;
+
+ writel(val, iep->base + iep->plat_data->reg_offs[reg]);
+
+ return 0;
+}
+
+static int icss_iep_regmap_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct icss_iep *iep = context;
+
+ *val = readl(iep->base + iep->plat_data->reg_offs[reg]);
+
+ return 0;
+}
+
+static struct regmap_config am654_icss_iep_regmap_config = {
+ .name = "icss iep",
+ .reg_stride = 1,
+ .reg_write = icss_iep_regmap_write,
+ .reg_read = icss_iep_regmap_read,
+ .writeable_reg = am654_icss_iep_valid_reg,
+ .readable_reg = am654_icss_iep_valid_reg,
+ .fast_io = 1,
+};
+
+static const struct icss_iep_plat_data am654_icss_iep_plat_data = {
+ .flags = ICSS_IEP_64BIT_COUNTER_SUPPORT |
+ ICSS_IEP_SLOW_COMPEN_REG_SUPPORT |
+ ICSS_IEP_SHADOW_MODE_SUPPORT,
+ .reg_offs = {
+ [ICSS_IEP_GLOBAL_CFG_REG] = 0x00,
+ [ICSS_IEP_COMPEN_REG] = 0x08,
+ [ICSS_IEP_SLOW_COMPEN_REG] = 0x0C,
+ [ICSS_IEP_COUNT_REG0] = 0x10,
+ [ICSS_IEP_COUNT_REG1] = 0x14,
+ [ICSS_IEP_CAPTURE_CFG_REG] = 0x18,
+ [ICSS_IEP_CAPTURE_STAT_REG] = 0x1c,
+
+ [ICSS_IEP_CAP6_RISE_REG0] = 0x50,
+ [ICSS_IEP_CAP6_RISE_REG1] = 0x54,
+
+ [ICSS_IEP_CAP7_RISE_REG0] = 0x60,
+ [ICSS_IEP_CAP7_RISE_REG1] = 0x64,
+
+ [ICSS_IEP_CMP_CFG_REG] = 0x70,
+ [ICSS_IEP_CMP_STAT_REG] = 0x74,
+ [ICSS_IEP_CMP0_REG0] = 0x78,
+ [ICSS_IEP_CMP0_REG1] = 0x7c,
+ [ICSS_IEP_CMP1_REG0] = 0x80,
+ [ICSS_IEP_CMP1_REG1] = 0x84,
+
+ [ICSS_IEP_CMP8_REG0] = 0xc0,
+ [ICSS_IEP_CMP8_REG1] = 0xc4,
+ [ICSS_IEP_SYNC_CTRL_REG] = 0x180,
+ [ICSS_IEP_SYNC0_STAT_REG] = 0x188,
+ [ICSS_IEP_SYNC1_STAT_REG] = 0x18c,
+ [ICSS_IEP_SYNC_PWIDTH_REG] = 0x190,
+ [ICSS_IEP_SYNC0_PERIOD_REG] = 0x194,
+ [ICSS_IEP_SYNC1_DELAY_REG] = 0x198,
+ [ICSS_IEP_SYNC_START_REG] = 0x19c,
+ },
+ .config = &am654_icss_iep_regmap_config,
+};
+
+static const struct of_device_id icss_iep_of_match[] = {
+ {
+ .compatible = "ti,am654-icss-iep",
+ .data = &am654_icss_iep_plat_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, icss_iep_of_match);
+
+static struct platform_driver icss_iep_driver = {
+ .driver = {
+ .name = "icss-iep",
+ .of_match_table = icss_iep_of_match,
+ },
+ .probe = icss_iep_probe,
+};
+module_platform_driver(icss_iep_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI ICSS IEP driver");
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
+MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");
diff --git a/drivers/net/ethernet/ti/icssg/icss_iep.h b/drivers/net/ethernet/ti/icssg/icss_iep.h
new file mode 100644
index 000000000000..803a4b714893
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icss_iep.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Industrial Ethernet Peripheral (IEP) Driver
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSS_IEP_H
+#define __NET_TI_ICSS_IEP_H
+
+#include <linux/mutex.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/regmap.h>
+
+struct icss_iep;
+extern const struct icss_iep_clockops prueth_iep_clockops;
+
+/* Firmware specific clock operations */
+struct icss_iep_clockops {
+ void (*settime)(void *clockops_data, u64 ns);
+ void (*adjtime)(void *clockops_data, s64 delta);
+ u64 (*gettime)(void *clockops_data, struct ptp_system_timestamp *sts);
+ int (*perout_enable)(void *clockops_data,
+ struct ptp_perout_request *req, int on,
+ u64 *cmp);
+ int (*extts_enable)(void *clockops_data, u32 index, int on);
+};
+
+struct icss_iep *icss_iep_get(struct device_node *np);
+struct icss_iep *icss_iep_get_idx(struct device_node *np, int idx);
+void icss_iep_put(struct icss_iep *iep);
+int icss_iep_init(struct icss_iep *iep, const struct icss_iep_clockops *clkops,
+ void *clockops_data, u32 cycle_time_ns);
+int icss_iep_exit(struct icss_iep *iep);
+int icss_iep_get_count_low(struct icss_iep *iep);
+int icss_iep_get_count_hi(struct icss_iep *iep);
+int icss_iep_get_ptp_clock_idx(struct icss_iep *iep);
+void icss_iep_init_fw(struct icss_iep *iep);
+void icss_iep_exit_fw(struct icss_iep *iep);
+
+#endif /* __NET_TI_ICSS_IEP_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_classifier.c b/drivers/net/ethernet/ti/icssg/icssg_classifier.c
new file mode 100644
index 000000000000..6df53ab17fbc
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_classifier.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+#include <linux/regmap.h>
+
+#include "icssg_prueth.h"
+
+#define ICSSG_NUM_CLASSIFIERS 16
+#define ICSSG_NUM_FT1_SLOTS 8
+#define ICSSG_NUM_FT3_SLOTS 16
+
+#define ICSSG_NUM_CLASSIFIERS_IN_USE 5
+
+/* Filter 1 - FT1 */
+#define FT1_NUM_SLOTS 8
+#define FT1_SLOT_SIZE 0x10 /* bytes */
+
+/* offsets from FT1 slot base i.e. slot 1 start */
+#define FT1_DA0 0x0
+#define FT1_DA1 0x4
+#define FT1_DA0_MASK 0x8
+#define FT1_DA1_MASK 0xc
+
+#define FT1_N_REG(slize, n, reg) \
+ (offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg))
+
+#define FT1_LEN_MASK GENMASK(19, 16)
+#define FT1_LEN_SHIFT 16
+#define FT1_LEN(len) (((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK)
+#define FT1_START_MASK GENMASK(14, 0)
+#define FT1_START(start) ((start) & FT1_START_MASK)
+#define FT1_MATCH_SLOT(n) (GENMASK(23, 16) & (BIT(n) << 16))
+
+/* FT1 config type */
+enum ft1_cfg_type {
+ FT1_CFG_TYPE_DISABLED = 0,
+ FT1_CFG_TYPE_EQ,
+ FT1_CFG_TYPE_GT,
+ FT1_CFG_TYPE_LT,
+};
+
+#define FT1_CFG_SHIFT(n) (2 * (n))
+#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n)))
+
+/* Filter 3 - FT3 */
+#define FT3_NUM_SLOTS 16
+#define FT3_SLOT_SIZE 0x20 /* bytes */
+
+/* offsets from FT3 slot n's base */
+#define FT3_START 0
+#define FT3_START_AUTO 0x4
+#define FT3_START_OFFSET 0x8
+#define FT3_JUMP_OFFSET 0xc
+#define FT3_LEN 0x10
+#define FT3_CFG 0x14
+#define FT3_T 0x18
+#define FT3_T_MASK 0x1c
+
+#define FT3_N_REG(slize, n, reg) \
+ (offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg))
+
+/* offsets from rx_class n's base */
+#define RX_CLASS_AND_EN 0
+#define RX_CLASS_OR_EN 0x4
+#define RX_CLASS_NUM_SLOTS 16
+#define RX_CLASS_EN_SIZE 0x8 /* bytes */
+
+#define RX_CLASS_N_REG(slice, n, reg) \
+ (offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg))
+
+/* RX Class Gates */
+#define RX_CLASS_GATES_SIZE 0x4 /* bytes */
+
+#define RX_CLASS_GATES_N_REG(slice, n) \
+ (offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n))
+
+#define RX_CLASS_GATES_ALLOW_MASK BIT(6)
+#define RX_CLASS_GATES_RAW_MASK BIT(5)
+#define RX_CLASS_GATES_PHASE_MASK BIT(4)
+
+/* RX Class traffic data matching bits */
+#define RX_CLASS_FT_UC BIT(31)
+#define RX_CLASS_FT_MC BIT(30)
+#define RX_CLASS_FT_BC BIT(29)
+#define RX_CLASS_FT_FW BIT(28)
+#define RX_CLASS_FT_RCV BIT(27)
+#define RX_CLASS_FT_VLAN BIT(26)
+#define RX_CLASS_FT_DA_P BIT(25)
+#define RX_CLASS_FT_DA_I BIT(24)
+#define RX_CLASS_FT_FT1_MATCH_MASK GENMASK(23, 16)
+#define RX_CLASS_FT_FT1_MATCH_SHIFT 16
+#define RX_CLASS_FT_FT3_MATCH_MASK GENMASK(15, 0)
+#define RX_CLASS_FT_FT3_MATCH_SHIFT 0
+
+#define RX_CLASS_FT_FT1_MATCH(slot) \
+ ((BIT(slot) << RX_CLASS_FT_FT1_MATCH_SHIFT) & \
+ RX_CLASS_FT_FT1_MATCH_MASK)
+
+/* RX class type */
+enum rx_class_sel_type {
+ RX_CLASS_SEL_TYPE_OR = 0,
+ RX_CLASS_SEL_TYPE_AND = 1,
+ RX_CLASS_SEL_TYPE_OR_AND_AND = 2,
+ RX_CLASS_SEL_TYPE_OR_OR_AND = 3,
+};
+
+#define FT1_CFG_SHIFT(n) (2 * (n))
+#define FT1_CFG_MASK(n) (0x3 << FT1_CFG_SHIFT((n)))
+
+#define RX_CLASS_SEL_SHIFT(n) (2 * (n))
+#define RX_CLASS_SEL_MASK(n) (0x3 << RX_CLASS_SEL_SHIFT((n)))
+
+#define ICSSG_CFG_OFFSET 0
+#define MAC_INTERFACE_0 0x18
+#define MAC_INTERFACE_1 0x1c
+
+#define ICSSG_CFG_RX_L2_G_EN BIT(2)
+
+/* These are register offsets per PRU */
+struct miig_rt_offsets {
+ u32 mac0;
+ u32 mac1;
+ u32 ft1_start_len;
+ u32 ft1_cfg;
+ u32 ft1_slot_base;
+ u32 ft3_slot_base;
+ u32 ft3_p_base;
+ u32 ft_rx_ptr;
+ u32 rx_class_base;
+ u32 rx_class_cfg1;
+ u32 rx_class_cfg2;
+ u32 rx_class_gates_base;
+ u32 rx_green;
+ u32 rx_rate_cfg_base;
+ u32 rx_rate_src_sel0;
+ u32 rx_rate_src_sel1;
+ u32 tx_rate_cfg_base;
+ u32 stat_base;
+ u32 tx_hsr_tag;
+ u32 tx_hsr_seq;
+ u32 tx_vlan_type;
+ u32 tx_vlan_ins;
+};
+
+/* These are the offset values for miig_rt_offsets registers */
+static const struct miig_rt_offsets offs[] = {
+ /* PRU0 */
+ {
+ 0x8,
+ 0xc,
+ 0x80,
+ 0x84,
+ 0x88,
+ 0x108,
+ 0x308,
+ 0x408,
+ 0x40c,
+ 0x48c,
+ 0x490,
+ 0x494,
+ 0x4d4,
+ 0x4e4,
+ 0x504,
+ 0x508,
+ 0x50c,
+ 0x54c,
+ 0x63c,
+ 0x640,
+ 0x644,
+ 0x648,
+ },
+ /* PRU1 */
+ {
+ 0x10,
+ 0x14,
+ 0x64c,
+ 0x650,
+ 0x654,
+ 0x6d4,
+ 0x8d4,
+ 0x9d4,
+ 0x9d8,
+ 0xa58,
+ 0xa5c,
+ 0xa60,
+ 0xaa0,
+ 0xab0,
+ 0xad0,
+ 0xad4,
+ 0xad8,
+ 0xb18,
+ 0xc08,
+ 0xc0c,
+ 0xc10,
+ 0xc14,
+ },
+};
+
+static void rx_class_ft1_set_start_len(struct regmap *miig_rt, int slice,
+ u16 start, u8 len)
+{
+ u32 offset, val;
+
+ offset = offs[slice].ft1_start_len;
+ val = FT1_LEN(len) | FT1_START(start);
+ regmap_write(miig_rt, offset, val);
+}
+
+static void rx_class_ft1_set_da(struct regmap *miig_rt, int slice,
+ int n, const u8 *addr)
+{
+ u32 offset;
+
+ offset = FT1_N_REG(slice, n, FT1_DA0);
+ regmap_write(miig_rt, offset, (u32)(addr[0] | addr[1] << 8 |
+ addr[2] << 16 | addr[3] << 24));
+ offset = FT1_N_REG(slice, n, FT1_DA1);
+ regmap_write(miig_rt, offset, (u32)(addr[4] | addr[5] << 8));
+}
+
+static void rx_class_ft1_set_da_mask(struct regmap *miig_rt, int slice,
+ int n, const u8 *addr)
+{
+ u32 offset;
+
+ offset = FT1_N_REG(slice, n, FT1_DA0_MASK);
+ regmap_write(miig_rt, offset, (u32)(addr[0] | addr[1] << 8 |
+ addr[2] << 16 | addr[3] << 24));
+ offset = FT1_N_REG(slice, n, FT1_DA1_MASK);
+ regmap_write(miig_rt, offset, (u32)(addr[4] | addr[5] << 8));
+}
+
+static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n,
+ enum ft1_cfg_type type)
+{
+ u32 offset;
+
+ offset = offs[slice].ft1_cfg;
+ regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n),
+ type << FT1_CFG_SHIFT(n));
+}
+
+static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n,
+ enum rx_class_sel_type type)
+{
+ u32 offset;
+
+ offset = offs[slice].rx_class_cfg1;
+ regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n),
+ type << RX_CLASS_SEL_SHIFT(n));
+}
+
+static void rx_class_set_and(struct regmap *miig_rt, int slice, int n,
+ u32 data)
+{
+ u32 offset;
+
+ offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN);
+ regmap_write(miig_rt, offset, data);
+}
+
+static void rx_class_set_or(struct regmap *miig_rt, int slice, int n,
+ u32 data)
+{
+ u32 offset;
+
+ offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN);
+ regmap_write(miig_rt, offset, data);
+}
+
+void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac)
+{
+ regmap_write(miig_rt, MAC_INTERFACE_0, (u32)(mac[0] | mac[1] << 8 |
+ mac[2] << 16 | mac[3] << 24));
+ regmap_write(miig_rt, MAC_INTERFACE_1, (u32)(mac[4] | mac[5] << 8));
+}
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac)
+{
+ regmap_write(miig_rt, offs[slice].mac0, (u32)(mac[0] | mac[1] << 8 |
+ mac[2] << 16 | mac[3] << 24));
+ regmap_write(miig_rt, offs[slice].mac1, (u32)(mac[4] | mac[5] << 8));
+}
+
+/* disable all RX traffic */
+void icssg_class_disable(struct regmap *miig_rt, int slice)
+{
+ u32 data, offset;
+ int n;
+
+ /* Enable RX_L2_G */
+ regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN,
+ ICSSG_CFG_RX_L2_G_EN);
+
+ for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++) {
+ /* AND_EN = 0 */
+ rx_class_set_and(miig_rt, slice, n, 0);
+ /* OR_EN = 0 */
+ rx_class_set_or(miig_rt, slice, n, 0);
+
+ /* set CFG1 to OR */
+ rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR);
+
+ /* configure gate */
+ offset = RX_CLASS_GATES_N_REG(slice, n);
+ regmap_read(miig_rt, offset, &data);
+ /* clear class_raw so we go through filters */
+ data &= ~RX_CLASS_GATES_RAW_MASK;
+ /* set allow and phase mask */
+ data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK;
+ regmap_write(miig_rt, offset, data);
+ }
+
+ /* FT1 Disabled */
+ for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) {
+ const u8 addr[] = { 0, 0, 0, 0, 0, 0, };
+
+ rx_class_ft1_cfg_set_type(miig_rt, slice, n,
+ FT1_CFG_TYPE_DISABLED);
+ rx_class_ft1_set_da(miig_rt, slice, n, addr);
+ rx_class_ft1_set_da_mask(miig_rt, slice, n, addr);
+ }
+
+ /* clear CFG2 */
+ regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti)
+{
+ u32 data;
+
+ /* defaults */
+ icssg_class_disable(miig_rt, slice);
+
+ /* Setup Classifier */
+ /* match on Broadcast or MAC_PRU address */
+ data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P;
+
+ /* multicast */
+ if (allmulti)
+ data |= RX_CLASS_FT_MC;
+
+ rx_class_set_or(miig_rt, slice, 0, data);
+
+ /* set CFG1 for OR_OR_AND for classifier */
+ rx_class_sel_set_type(miig_rt, slice, 0, RX_CLASS_SEL_TYPE_OR_OR_AND);
+
+ /* clear CFG2 */
+ regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+/* required for SAV check */
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr)
+{
+ const u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, };
+
+ rx_class_ft1_set_start_len(miig_rt, slice, 0, 6);
+ rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr);
+ rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr);
+ rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
new file mode 100644
index 000000000000..933b84666574
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Ethernet driver
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/iopoll.h>
+#include <linux/regmap.h>
+#include <uapi/linux/if_ether.h>
+#include "icssg_config.h"
+#include "icssg_prueth.h"
+#include "icssg_switch_map.h"
+#include "icssg_mii_rt.h"
+
+/* TX IPG Values to be set for 100M link speed. These values are
+ * in ocp_clk cycles. So need change if ocp_clk is changed for a specific
+ * h/w design.
+ */
+
+/* IPG is in core_clk cycles */
+#define MII_RT_TX_IPG_100M 0x17
+#define MII_RT_TX_IPG_1G 0xb
+
+#define ICSSG_QUEUES_MAX 64
+#define ICSSG_QUEUE_OFFSET 0xd00
+#define ICSSG_QUEUE_PEEK_OFFSET 0xe00
+#define ICSSG_QUEUE_CNT_OFFSET 0xe40
+#define ICSSG_QUEUE_RESET_OFFSET 0xf40
+
+#define ICSSG_NUM_TX_QUEUES 8
+
+#define RECYCLE_Q_SLICE0 16
+#define RECYCLE_Q_SLICE1 17
+
+#define ICSSG_NUM_OTHER_QUEUES 5 /* port, host and special queues */
+
+#define PORT_HI_Q_SLICE0 32
+#define PORT_LO_Q_SLICE0 33
+#define HOST_HI_Q_SLICE0 34
+#define HOST_LO_Q_SLICE0 35
+#define HOST_SPL_Q_SLICE0 40 /* Special Queue */
+
+#define PORT_HI_Q_SLICE1 36
+#define PORT_LO_Q_SLICE1 37
+#define HOST_HI_Q_SLICE1 38
+#define HOST_LO_Q_SLICE1 39
+#define HOST_SPL_Q_SLICE1 41 /* Special Queue */
+
+#define MII_RXCFG_DEFAULT (PRUSS_MII_RT_RXCFG_RX_ENABLE | \
+ PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
+ PRUSS_MII_RT_RXCFG_RX_L2_EN | \
+ PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
+
+#define MII_TXCFG_DEFAULT (PRUSS_MII_RT_TXCFG_TX_ENABLE | \
+ PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
+ PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
+ PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
+
+#define ICSSG_CFG_DEFAULT (ICSSG_CFG_TX_L1_EN | \
+ ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
+ ICSSG_CFG_TX_PRU_EN | \
+ ICSSG_CFG_SGMII_MODE)
+
+#define FDB_GEN_CFG1 0x60
+#define SMEM_VLAN_OFFSET 8
+#define SMEM_VLAN_OFFSET_MASK GENMASK(25, 8)
+
+#define FDB_GEN_CFG2 0x64
+#define FDB_VLAN_EN BIT(6)
+#define FDB_HOST_EN BIT(2)
+#define FDB_PRU1_EN BIT(1)
+#define FDB_PRU0_EN BIT(0)
+#define FDB_EN_ALL (FDB_PRU0_EN | FDB_PRU1_EN | \
+ FDB_HOST_EN | FDB_VLAN_EN)
+
+/**
+ * struct map - ICSSG Queue Map
+ * @queue: Queue number
+ * @pd_addr_start: Packet descriptor queue reserved memory
+ * @flags: Flags
+ * @special: Indicates whether this queue is a special queue or not
+ */
+struct map {
+ int queue;
+ u32 pd_addr_start;
+ u32 flags;
+ bool special;
+};
+
+/* Hardware queue map for ICSSG */
+static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
+ {
+ { PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
+ { PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
+ { HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
+ { HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
+ { HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
+ },
+ {
+ { PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
+ { PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
+ { HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
+ { HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
+ { HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
+ },
+};
+
+static void icssg_config_mii_init(struct prueth_emac *emac)
+{
+ u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+ struct regmap *mii_rt;
+
+ mii_rt = prueth->mii_rt;
+
+ rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
+ PRUSS_MII_RT_RXCFG1;
+ txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+ PRUSS_MII_RT_TXCFG1;
+ pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+ PRUSS_MII_RT_RX_PCNT1;
+
+ rxcfg = MII_RXCFG_DEFAULT;
+ txcfg = MII_TXCFG_DEFAULT;
+
+ if (slice == ICSS_MII1)
+ rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
+
+ /* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
+ * to be swapped also comparing to RGMII mode.
+ */
+ if (emac->phy_if == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
+ txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+ else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
+ txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
+ regmap_write(mii_rt, rxcfg_reg, rxcfg);
+ regmap_write(mii_rt, txcfg_reg, txcfg);
+ regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
+static void icssg_miig_queues_init(struct prueth *prueth, int slice)
+{
+ struct regmap *miig_rt = prueth->miig_rt;
+ void __iomem *smem = prueth->shram.va;
+ u8 pd[ICSSG_SPECIAL_PD_SIZE];
+ int queue = 0, i, j;
+ u32 *pdword;
+
+ /* reset hwqueues */
+ if (slice)
+ queue = ICSSG_NUM_TX_QUEUES;
+
+ for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
+ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+ queue++;
+ }
+
+ queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
+ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+
+ for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
+ regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET,
+ hwq_map[slice][i].queue);
+ }
+
+ /* initialize packet descriptors in SMEM */
+ /* push pakcet descriptors to hwqueues */
+
+ pdword = (u32 *)pd;
+ for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
+ const struct map *mp;
+ int pd_size, num_pds;
+ u32 pdaddr;
+
+ mp = &hwq_map[slice][j];
+ if (mp->special) {
+ pd_size = ICSSG_SPECIAL_PD_SIZE;
+ num_pds = ICSSG_NUM_SPECIAL_PDS;
+ } else {
+ pd_size = ICSSG_NORMAL_PD_SIZE;
+ num_pds = ICSSG_NUM_NORMAL_PDS;
+ }
+
+ for (i = 0; i < num_pds; i++) {
+ memset(pd, 0, pd_size);
+
+ pdword[0] &= ICSSG_FLAG_MASK;
+ pdword[0] |= mp->flags;
+ pdaddr = mp->pd_addr_start + i * pd_size;
+
+ memcpy_toio(smem + pdaddr, pd, pd_size);
+ queue = mp->queue;
+ regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
+ pdaddr);
+ }
+ }
+}
+
+void icssg_config_ipg(struct prueth_emac *emac)
+{
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+
+ switch (emac->speed) {
+ case SPEED_1000:
+ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_1G);
+ break;
+ case SPEED_100:
+ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M);
+ break;
+ case SPEED_10:
+ /* IPG for 10M is same as 100M */
+ icssg_mii_update_ipg(prueth->mii_rt, slice, MII_RT_TX_IPG_100M);
+ break;
+ default:
+ /* Other links speeds not supported */
+ netdev_err(emac->ndev, "Unsupported link speed\n");
+ return;
+ }
+}
+
+static void emac_r30_cmd_init(struct prueth_emac *emac)
+{
+ struct icssg_r30_cmd __iomem *p;
+ int i;
+
+ p = emac->dram.va + MGR_R30_CMD_OFFSET;
+
+ for (i = 0; i < 4; i++)
+ writel(EMAC_NONE, &p->cmd[i]);
+}
+
+static int emac_r30_is_done(struct prueth_emac *emac)
+{
+ const struct icssg_r30_cmd __iomem *p;
+ u32 cmd;
+ int i;
+
+ p = emac->dram.va + MGR_R30_CMD_OFFSET;
+
+ for (i = 0; i < 4; i++) {
+ cmd = readl(&p->cmd[i]);
+ if (cmd != EMAC_NONE)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int prueth_emac_buffer_setup(struct prueth_emac *emac)
+{
+ struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
+ struct icssg_rxq_ctx __iomem *rxq_ctx;
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+ u32 addr;
+ int i;
+
+ /* Layout to have 64KB aligned buffer pool
+ * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
+ */
+
+ addr = lower_32_bits(prueth->msmcram.pa);
+ if (slice)
+ addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+
+ if (addr % SZ_64K) {
+ dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
+ return -EINVAL;
+ }
+
+ bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
+ /* workaround for f/w bug. bpool 0 needs to be initilalized */
+ writel(addr, &bpool_cfg[0].addr);
+ writel(0, &bpool_cfg[0].len);
+
+ for (i = PRUETH_EMAC_BUF_POOL_START;
+ i < PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS;
+ i++) {
+ writel(addr, &bpool_cfg[i].addr);
+ writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len);
+ addr += PRUETH_EMAC_BUF_POOL_SIZE;
+ }
+
+ if (!slice)
+ addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+ else
+ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2;
+
+ /* Pre-emptible RX buffer queue */
+ rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
+ for (i = 0; i < 3; i++)
+ writel(addr, &rxq_ctx->start[i]);
+
+ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+ writel(addr, &rxq_ctx->end);
+
+ /* Express RX buffer queue */
+ rxq_ctx = emac->dram.va + HOST_RX_Q_EXP_CONTEXT_OFFSET;
+ for (i = 0; i < 3; i++)
+ writel(addr, &rxq_ctx->start[i]);
+
+ addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+ writel(addr, &rxq_ctx->end);
+
+ return 0;
+}
+
+static void icssg_init_emac_mode(struct prueth *prueth)
+{
+ /* When the device is configured as a bridge and it is being brought
+ * back to the emac mode, the host mac address has to be set as 0.
+ */
+ u8 mac[ETH_ALEN] = { 0 };
+
+ if (prueth->emacs_initialized)
+ return;
+
+ regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1,
+ SMEM_VLAN_OFFSET_MASK, 0);
+ regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0);
+ /* Clear host MAC address */
+ icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
+}
+
+int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
+{
+ void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
+ struct icssg_flow_cfg __iomem *flow_cfg;
+ int ret;
+
+ icssg_init_emac_mode(prueth);
+
+ memset_io(config, 0, TAS_GATE_MASK_LIST0);
+ icssg_miig_queues_init(prueth, slice);
+
+ emac->speed = SPEED_1000;
+ emac->duplex = DUPLEX_FULL;
+ if (!phy_interface_mode_is_rgmii(emac->phy_if)) {
+ emac->speed = SPEED_100;
+ emac->duplex = DUPLEX_FULL;
+ }
+ regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
+ ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
+ icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if);
+ icssg_config_mii_init(emac);
+ icssg_config_ipg(emac);
+ icssg_update_rgmii_cfg(prueth->miig_rt, emac);
+
+ /* set GPI mode */
+ pruss_cfg_gpimode(prueth->pruss, prueth->pru_id[slice],
+ PRUSS_GPI_MODE_MII);
+
+ /* enable XFR shift for PRU and RTU */
+ pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_PRU, true);
+ pruss_cfg_xfr_enable(prueth->pruss, PRU_TYPE_RTU, true);
+
+ /* set C28 to 0x100 */
+ pru_rproc_set_ctable(prueth->pru[slice], PRU_C28, 0x100 << 8);
+ pru_rproc_set_ctable(prueth->rtu[slice], PRU_C28, 0x100 << 8);
+ pru_rproc_set_ctable(prueth->txpru[slice], PRU_C28, 0x100 << 8);
+
+ flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+ writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
+ writew(0, &flow_cfg->mgm_base_flow);
+ writeb(0, config + SPL_PKT_DEFAULT_PRIORITY);
+ writeb(0, config + QUEUE_NUM_UNTAGGED);
+
+ ret = prueth_emac_buffer_setup(emac);
+ if (ret)
+ return ret;
+
+ emac_r30_cmd_init(emac);
+
+ return 0;
+}
+
+/* Bitmask for ICSSG r30 commands */
+static const struct icssg_r30_cmd emac_r32_bitmask[] = {
+ {{0xffff0004, 0xffff0100, 0xffff0100, EMAC_NONE}}, /* EMAC_PORT_DISABLE */
+ {{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}}, /* EMAC_PORT_BLOCK */
+ {{0xffbb0000, 0xfcff0000, 0xdcff0000, EMAC_NONE}}, /* EMAC_PORT_FORWARD */
+ {{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}}, /* EMAC_PORT_FORWARD_WO_LEARNING */
+ {{0xffff0001, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT ALL */
+ {{0xfffe0002, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT TAGGED */
+ {{0xfffc0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* ACCEPT UNTAGGED and PRIO */
+ {{EMAC_NONE, 0xffff0020, EMAC_NONE, EMAC_NONE}}, /* TAS Trigger List change */
+ {{EMAC_NONE, 0xdfff1000, EMAC_NONE, EMAC_NONE}}, /* TAS set state ENABLE*/
+ {{EMAC_NONE, 0xefff2000, EMAC_NONE, EMAC_NONE}}, /* TAS set state RESET*/
+ {{EMAC_NONE, 0xcfff0000, EMAC_NONE, EMAC_NONE}}, /* TAS set state DISABLE*/
+ {{EMAC_NONE, EMAC_NONE, 0xffff0400, EMAC_NONE}}, /* UC flooding ENABLE*/
+ {{EMAC_NONE, EMAC_NONE, 0xfbff0000, EMAC_NONE}}, /* UC flooding DISABLE*/
+ {{EMAC_NONE, EMAC_NONE, 0xffff0800, EMAC_NONE}}, /* MC flooding ENABLE*/
+ {{EMAC_NONE, EMAC_NONE, 0xf7ff0000, EMAC_NONE}}, /* MC flooding DISABLE*/
+ {{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/
+ {{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/
+ {{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/
+ {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/
+};
+
+int emac_set_port_state(struct prueth_emac *emac,
+ enum icssg_port_state_cmd cmd)
+{
+ struct icssg_r30_cmd __iomem *p;
+ int ret = -ETIMEDOUT;
+ int done = 0;
+ int i;
+
+ p = emac->dram.va + MGR_R30_CMD_OFFSET;
+
+ if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
+ netdev_err(emac->ndev, "invalid port command\n");
+ return -EINVAL;
+ }
+
+ /* only one command at a time allowed to firmware */
+ mutex_lock(&emac->cmd_lock);
+
+ for (i = 0; i < 4; i++)
+ writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
+
+ /* wait for done */
+ ret = read_poll_timeout(emac_r30_is_done, done, done == 1,
+ 1000, 10000, false, emac);
+
+ if (ret == -ETIMEDOUT)
+ netdev_err(emac->ndev, "timeout waiting for command done\n");
+
+ mutex_unlock(&emac->cmd_lock);
+
+ return ret;
+}
+
+void icssg_config_set_speed(struct prueth_emac *emac)
+{
+ u8 fw_speed;
+
+ switch (emac->speed) {
+ case SPEED_1000:
+ fw_speed = FW_LINK_SPEED_1G;
+ break;
+ case SPEED_100:
+ fw_speed = FW_LINK_SPEED_100M;
+ break;
+ case SPEED_10:
+ fw_speed = FW_LINK_SPEED_10M;
+ break;
+ default:
+ /* Other links speeds not supported */
+ netdev_err(emac->ndev, "Unsupported link speed\n");
+ return;
+ }
+
+ writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
new file mode 100644
index 000000000000..43eb0922172a
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_CONFIG_H
+#define __NET_TI_ICSSG_CONFIG_H
+
+struct icssg_buffer_pool_cfg {
+ __le32 addr;
+ __le32 len;
+} __packed;
+
+struct icssg_flow_cfg {
+ __le16 rx_base_flow;
+ __le16 mgm_base_flow;
+} __packed;
+
+#define PRUETH_PKT_TYPE_CMD 0x10
+#define PRUETH_NAV_PS_DATA_SIZE 16 /* Protocol specific data size */
+#define PRUETH_NAV_SW_DATA_SIZE 16 /* SW related data size */
+#define PRUETH_MAX_TX_DESC 512
+#define PRUETH_MAX_RX_DESC 512
+#define PRUETH_MAX_RX_FLOWS 1 /* excluding default flow */
+#define PRUETH_RX_FLOW_DATA 0
+
+#define PRUETH_EMAC_BUF_POOL_SIZE SZ_8K
+#define PRUETH_EMAC_POOLS_PER_SLICE 24
+#define PRUETH_EMAC_BUF_POOL_START 8
+#define PRUETH_NUM_BUF_POOLS 8
+#define PRUETH_EMAC_RX_CTX_BUF_SIZE SZ_16K /* per slice */
+#define MSMC_RAM_SIZE \
+ (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
+ PRUETH_EMAC_RX_CTX_BUF_SIZE * 2))
+
+struct icssg_rxq_ctx {
+ __le32 start[3];
+ __le32 end;
+} __packed;
+
+/* Load time Fiwmware Configuration */
+
+#define ICSSG_FW_MGMT_CMD_HEADER 0x81
+#define ICSSG_FW_MGMT_FDB_CMD_TYPE 0x03
+#define ICSSG_FW_MGMT_CMD_TYPE 0x04
+#define ICSSG_FW_MGMT_PKT 0x80000000
+
+struct icssg_r30_cmd {
+ u32 cmd[4];
+} __packed;
+
+enum icssg_port_state_cmd {
+ ICSSG_EMAC_PORT_DISABLE = 0,
+ ICSSG_EMAC_PORT_BLOCK,
+ ICSSG_EMAC_PORT_FORWARD,
+ ICSSG_EMAC_PORT_FORWARD_WO_LEARNING,
+ ICSSG_EMAC_PORT_ACCEPT_ALL,
+ ICSSG_EMAC_PORT_ACCEPT_TAGGED,
+ ICSSG_EMAC_PORT_ACCEPT_UNTAGGED_N_PRIO,
+ ICSSG_EMAC_PORT_TAS_TRIGGER,
+ ICSSG_EMAC_PORT_TAS_ENABLE,
+ ICSSG_EMAC_PORT_TAS_RESET,
+ ICSSG_EMAC_PORT_TAS_DISABLE,
+ ICSSG_EMAC_PORT_UC_FLOODING_ENABLE,
+ ICSSG_EMAC_PORT_UC_FLOODING_DISABLE,
+ ICSSG_EMAC_PORT_MC_FLOODING_ENABLE,
+ ICSSG_EMAC_PORT_MC_FLOODING_DISABLE,
+ ICSSG_EMAC_PORT_PREMPT_TX_ENABLE,
+ ICSSG_EMAC_PORT_PREMPT_TX_DISABLE,
+ ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE,
+ ICSSG_EMAC_PORT_VLAN_AWARE_DISABLE,
+ ICSSG_EMAC_PORT_MAX_COMMANDS
+};
+
+#define EMAC_NONE 0xffff0000
+#define EMAC_PRU0_P_DI 0xffff0004
+#define EMAC_PRU1_P_DI 0xffff0040
+#define EMAC_TX_P_DI 0xffff0100
+
+#define EMAC_PRU0_P_EN 0xfffb0000
+#define EMAC_PRU1_P_EN 0xffbf0000
+#define EMAC_TX_P_EN 0xfeff0000
+
+#define EMAC_P_BLOCK 0xffff0040
+#define EMAC_TX_P_BLOCK 0xffff0200
+#define EMAC_P_UNBLOCK 0xffbf0000
+#define EMAC_TX_P_UNBLOCK 0xfdff0000
+#define EMAC_LEAN_EN 0xfff70000
+#define EMAC_LEAN_DI 0xffff0008
+
+#define EMAC_ACCEPT_ALL 0xffff0001
+#define EMAC_ACCEPT_TAG 0xfffe0002
+#define EMAC_ACCEPT_PRIOR 0xfffc0000
+
+/* Config area lies in DRAM */
+#define ICSSG_CONFIG_OFFSET 0x0
+
+/* Config area lies in shared RAM */
+#define ICSSG_CONFIG_OFFSET_SLICE0 0
+#define ICSSG_CONFIG_OFFSET_SLICE1 0x8000
+
+#define ICSSG_NUM_NORMAL_PDS 64
+#define ICSSG_NUM_SPECIAL_PDS 16
+
+#define ICSSG_NORMAL_PD_SIZE 8
+#define ICSSG_SPECIAL_PD_SIZE 20
+
+#define ICSSG_FLAG_MASK 0xff00ffff
+
+struct icssg_setclock_desc {
+ u8 request;
+ u8 restore;
+ u8 acknowledgment;
+ u8 cmp_status;
+ u32 margin;
+ u32 cyclecounter0_set;
+ u32 cyclecounter1_set;
+ u32 iepcount_set;
+ u32 rsvd1;
+ u32 rsvd2;
+ u32 CMP0_current;
+ u32 iepcount_current;
+ u32 difference;
+ u32 cyclecounter0_new;
+ u32 cyclecounter1_new;
+ u32 CMP0_new;
+} __packed;
+
+#define ICSSG_CMD_POP_SLICE0 56
+#define ICSSG_CMD_POP_SLICE1 60
+
+#define ICSSG_CMD_PUSH_SLICE0 57
+#define ICSSG_CMD_PUSH_SLICE1 61
+
+#define ICSSG_RSP_POP_SLICE0 58
+#define ICSSG_RSP_POP_SLICE1 62
+
+#define ICSSG_RSP_PUSH_SLICE0 56
+#define ICSSG_RSP_PUSH_SLICE1 60
+
+#define ICSSG_TS_POP_SLICE0 59
+#define ICSSG_TS_POP_SLICE1 63
+
+#define ICSSG_TS_PUSH_SLICE0 40
+#define ICSSG_TS_PUSH_SLICE1 41
+
+/* FDB FID_C2 flag definitions */
+/* Indicates host port membership.*/
+#define ICSSG_FDB_ENTRY_P0_MEMBERSHIP BIT(0)
+/* Indicates that MAC ID is connected to physical port 1 */
+#define ICSSG_FDB_ENTRY_P1_MEMBERSHIP BIT(1)
+/* Indicates that MAC ID is connected to physical port 2 */
+#define ICSSG_FDB_ENTRY_P2_MEMBERSHIP BIT(2)
+/* Ageable bit is set for learned entries and cleared for static entries */
+#define ICSSG_FDB_ENTRY_AGEABLE BIT(3)
+/* If set for DA then packet is determined to be a special packet */
+#define ICSSG_FDB_ENTRY_BLOCK BIT(4)
+/* If set for DA then the SA from the packet is not learned */
+#define ICSSG_FDB_ENTRY_SECURE BIT(5)
+/* If set, it means packet has been seen recently with source address + FID
+ * matching MAC address/FID of entry
+ */
+#define ICSSG_FDB_ENTRY_TOUCHED BIT(6)
+/* Set if entry is valid */
+#define ICSSG_FDB_ENTRY_VALID BIT(7)
+
+/**
+ * struct prueth_vlan_tbl - VLAN table entries struct in ICSSG SMEM
+ * @fid_c1: membership and forwarding rules flag to this table. See
+ * above to defines for bit definitions
+ * @fid: FDB index for this VID (there is 1-1 mapping b/w VID and FID)
+ */
+struct prueth_vlan_tbl {
+ u8 fid_c1;
+ u8 fid;
+} __packed;
+
+/**
+ * struct prueth_fdb_slot - Result of FDB slot lookup
+ * @mac: MAC address
+ * @fid: fid to be associated with MAC
+ * @fid_c2: FID_C2 entry for this MAC
+ */
+struct prueth_fdb_slot {
+ u8 mac[ETH_ALEN];
+ u8 fid;
+ u8 fid_c2;
+} __packed;
+
+enum icssg_ietfpe_verify_states {
+ ICSSG_IETFPE_STATE_UNKNOWN = 0,
+ ICSSG_IETFPE_STATE_INITIAL,
+ ICSSG_IETFPE_STATE_VERIFYING,
+ ICSSG_IETFPE_STATE_SUCCEEDED,
+ ICSSG_IETFPE_STATE_FAILED,
+ ICSSG_IETFPE_STATE_DISABLED
+};
+#endif /* __NET_TI_ICSSG_CONFIG_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
new file mode 100644
index 000000000000..a27ec1dcc8d5
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include "icssg_prueth.h"
+#include "icssg_stats.h"
+
+static void emac_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth *prueth = emac->prueth;
+
+ strscpy(info->driver, dev_driver_string(prueth->dev),
+ sizeof(info->driver));
+ strscpy(info->bus_info, dev_name(prueth->dev), sizeof(info->bus_info));
+}
+
+static u32 emac_get_msglevel(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ return emac->msg_enable;
+}
+
+static void emac_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ emac->msg_enable = value;
+}
+
+static int emac_get_link_ksettings(struct net_device *ndev,
+ struct ethtool_link_ksettings *ecmd)
+{
+ return phy_ethtool_get_link_ksettings(ndev, ecmd);
+}
+
+static int emac_set_link_ksettings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *ecmd)
+{
+ return phy_ethtool_set_link_ksettings(ndev, ecmd);
+}
+
+static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ if (!ndev->phydev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_get_eee(ndev->phydev, edata);
+}
+
+static int emac_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ if (!ndev->phydev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_set_eee(ndev->phydev, edata);
+}
+
+static int emac_nway_reset(struct net_device *ndev)
+{
+ return phy_ethtool_nway_reset(ndev);
+}
+
+static int emac_get_sset_count(struct net_device *ndev, int stringset)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return ICSSG_NUM_ETHTOOL_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
+ if (!icssg_all_stats[i].standard_stats) {
+ memcpy(p, icssg_all_stats[i].name,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void emac_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ int i;
+
+ emac_update_hardware_stats(emac);
+
+ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
+ if (!icssg_all_stats[i].standard_stats)
+ *(data++) = emac->stats[i];
+}
+
+static int emac_get_ts_info(struct net_device *ndev,
+ struct ethtool_ts_info *info)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->phc_index = icss_iep_get_ptp_clock_idx(emac->iep);
+ info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
+
+ return 0;
+}
+
+static int emac_set_channels(struct net_device *ndev,
+ struct ethtool_channels *ch)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ /* Check if interface is up. Can change the num queues when
+ * the interface is down.
+ */
+ if (netif_running(emac->ndev))
+ return -EBUSY;
+
+ emac->tx_ch_num = ch->tx_count;
+
+ return 0;
+}
+
+static void emac_get_channels(struct net_device *ndev,
+ struct ethtool_channels *ch)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ ch->max_rx = 1;
+ ch->max_tx = PRUETH_MAX_TX_QUEUES;
+ ch->rx_count = 1;
+ ch->tx_count = emac->tx_ch_num;
+}
+
+static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = {
+ { 0, 64},
+ { 65, 128},
+ { 129, 256},
+ { 257, 512},
+ { 513, PRUETH_MAX_PKT_SIZE},
+ {}
+};
+
+static void emac_get_rmon_stats(struct net_device *ndev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ *ranges = emac_rmon_ranges;
+
+ rmon_stats->undersize_pkts = emac_get_stat_by_name(emac, "rx_bucket1_frames") -
+ emac_get_stat_by_name(emac, "rx_64B_frames");
+
+ rmon_stats->hist[0] = emac_get_stat_by_name(emac, "rx_bucket1_frames");
+ rmon_stats->hist[1] = emac_get_stat_by_name(emac, "rx_bucket2_frames");
+ rmon_stats->hist[2] = emac_get_stat_by_name(emac, "rx_bucket3_frames");
+ rmon_stats->hist[3] = emac_get_stat_by_name(emac, "rx_bucket4_frames");
+ rmon_stats->hist[4] = emac_get_stat_by_name(emac, "rx_bucket5_frames");
+
+ rmon_stats->hist_tx[0] = emac_get_stat_by_name(emac, "tx_bucket1_frames");
+ rmon_stats->hist_tx[1] = emac_get_stat_by_name(emac, "tx_bucket2_frames");
+ rmon_stats->hist_tx[2] = emac_get_stat_by_name(emac, "tx_bucket3_frames");
+ rmon_stats->hist_tx[3] = emac_get_stat_by_name(emac, "tx_bucket4_frames");
+ rmon_stats->hist_tx[4] = emac_get_stat_by_name(emac, "tx_bucket5_frames");
+}
+
+const struct ethtool_ops icssg_ethtool_ops = {
+ .get_drvinfo = emac_get_drvinfo,
+ .get_msglevel = emac_get_msglevel,
+ .set_msglevel = emac_set_msglevel,
+ .get_sset_count = emac_get_sset_count,
+ .get_ethtool_stats = emac_get_ethtool_stats,
+ .get_strings = emac_get_strings,
+ .get_ts_info = emac_get_ts_info,
+ .get_channels = emac_get_channels,
+ .set_channels = emac_set_channels,
+ .get_link_ksettings = emac_get_link_ksettings,
+ .set_link_ksettings = emac_set_link_ksettings,
+ .get_link = ethtool_op_get_link,
+ .get_eee = emac_get_eee,
+ .set_eee = emac_set_eee,
+ .nway_reset = emac_nway_reset,
+ .get_rmon_stats = emac_get_rmon_stats,
+};
diff --git a/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c b/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c
new file mode 100644
index 000000000000..92718ae40d7e
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_mii_cfg.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "icssg_mii_rt.h"
+#include "icssg_prueth.h"
+
+void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg)
+{
+ u32 val;
+
+ if (mii == ICSS_MII0) {
+ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, ipg);
+ } else {
+ regmap_read(mii_rt, PRUSS_MII_RT_TX_IPG0, &val);
+ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG1, ipg);
+ regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, val);
+ }
+}
+
+void icssg_mii_update_mtu(struct regmap *mii_rt, int mii, int mtu)
+{
+ mtu += (ETH_HLEN + ETH_FCS_LEN);
+ if (mii == ICSS_MII0) {
+ regmap_update_bits(mii_rt,
+ PRUSS_MII_RT_RX_FRMS0,
+ PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK,
+ (mtu - 1) << PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT);
+ } else {
+ regmap_update_bits(mii_rt,
+ PRUSS_MII_RT_RX_FRMS1,
+ PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK,
+ (mtu - 1) << PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT);
+ }
+}
+
+void icssg_update_rgmii_cfg(struct regmap *miig_rt, struct prueth_emac *emac)
+{
+ u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0;
+ int slice = prueth_emac_slice(emac);
+ u32 inband_en_mask, inband_val = 0;
+
+ gig_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 :
+ RGMII_CFG_GIG_EN_MII1;
+ if (emac->speed == SPEED_1000)
+ gig_val = gig_en_mask;
+ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val);
+
+ inband_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_INBAND_EN_MII0 :
+ RGMII_CFG_INBAND_EN_MII1;
+ if (emac->speed == SPEED_10 && phy_interface_mode_is_rgmii(emac->phy_if))
+ inband_val = inband_en_mask;
+ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, inband_en_mask, inband_val);
+
+ full_duplex_mask = (slice == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 :
+ RGMII_CFG_FULL_DUPLEX_MII1;
+ if (emac->duplex == DUPLEX_FULL)
+ full_duplex_val = full_duplex_mask;
+ regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask,
+ full_duplex_val);
+}
+
+void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, phy_interface_t phy_if)
+{
+ u32 val, mask, shift;
+
+ mask = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE : ICSSG_CFG_MII1_MODE;
+ shift = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE_SHIFT : ICSSG_CFG_MII1_MODE_SHIFT;
+
+ val = MII_MODE_RGMII;
+ if (phy_if == PHY_INTERFACE_MODE_MII)
+ val = MII_MODE_MII;
+
+ val <<= shift;
+ regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, mask, val);
+ regmap_read(miig_rt, ICSSG_CFG_OFFSET, &val);
+}
+
+u32 icssg_rgmii_cfg_get_bitfield(struct regmap *miig_rt, u32 mask, u32 shift)
+{
+ u32 val;
+
+ regmap_read(miig_rt, RGMII_CFG_OFFSET, &val);
+ val &= mask;
+ val >>= shift;
+
+ return val;
+}
+
+u32 icssg_rgmii_get_speed(struct regmap *miig_rt, int mii)
+{
+ u32 shift = RGMII_CFG_SPEED_MII0_SHIFT, mask = RGMII_CFG_SPEED_MII0;
+
+ if (mii == ICSS_MII1) {
+ shift = RGMII_CFG_SPEED_MII1_SHIFT;
+ mask = RGMII_CFG_SPEED_MII1;
+ }
+
+ return icssg_rgmii_cfg_get_bitfield(miig_rt, mask, shift);
+}
+
+u32 icssg_rgmii_get_fullduplex(struct regmap *miig_rt, int mii)
+{
+ u32 shift = RGMII_CFG_FULLDUPLEX_MII0_SHIFT;
+ u32 mask = RGMII_CFG_FULLDUPLEX_MII0;
+
+ if (mii == ICSS_MII1) {
+ shift = RGMII_CFG_FULLDUPLEX_MII1_SHIFT;
+ mask = RGMII_CFG_FULLDUPLEX_MII1;
+ }
+
+ return icssg_rgmii_cfg_get_bitfield(miig_rt, mask, shift);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h
new file mode 100644
index 000000000000..55a59bf5299c
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_mii_rt.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* PRU-ICSS MII_RT register definitions
+ *
+ * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_PRUSS_MII_RT_H__
+#define __NET_PRUSS_MII_RT_H__
+
+#include <linux/if_ether.h>
+#include <linux/phy.h>
+
+/* PRUSS_MII_RT Registers */
+#define PRUSS_MII_RT_RXCFG0 0x0
+#define PRUSS_MII_RT_RXCFG1 0x4
+#define PRUSS_MII_RT_TXCFG0 0x10
+#define PRUSS_MII_RT_TXCFG1 0x14
+#define PRUSS_MII_RT_TX_CRC0 0x20
+#define PRUSS_MII_RT_TX_CRC1 0x24
+#define PRUSS_MII_RT_TX_IPG0 0x30
+#define PRUSS_MII_RT_TX_IPG1 0x34
+#define PRUSS_MII_RT_PRS0 0x38
+#define PRUSS_MII_RT_PRS1 0x3c
+#define PRUSS_MII_RT_RX_FRMS0 0x40
+#define PRUSS_MII_RT_RX_FRMS1 0x44
+#define PRUSS_MII_RT_RX_PCNT0 0x48
+#define PRUSS_MII_RT_RX_PCNT1 0x4c
+#define PRUSS_MII_RT_RX_ERR0 0x50
+#define PRUSS_MII_RT_RX_ERR1 0x54
+
+/* PRUSS_MII_RT_RXCFG0/1 bits */
+#define PRUSS_MII_RT_RXCFG_RX_ENABLE BIT(0)
+#define PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS BIT(1)
+#define PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE BIT(2)
+#define PRUSS_MII_RT_RXCFG_RX_MUX_SEL BIT(3)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EN BIT(4)
+#define PRUSS_MII_RT_RXCFG_RX_BYTE_SWAP BIT(5)
+#define PRUSS_MII_RT_RXCFG_RX_AUTO_FWD_PRE BIT(6)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS BIT(9)
+
+/* PRUSS_MII_RT_TXCFG0/1 bits */
+#define PRUSS_MII_RT_TXCFG_TX_ENABLE BIT(0)
+#define PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE BIT(1)
+#define PRUSS_MII_RT_TXCFG_TX_EN_MODE BIT(2)
+#define PRUSS_MII_RT_TXCFG_TX_BYTE_SWAP BIT(3)
+#define PRUSS_MII_RT_TXCFG_TX_MUX_SEL BIT(8)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_SEQUENCE BIT(9)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_ESC_ERR BIT(10)
+#define PRUSS_MII_RT_TXCFG_TX_32_MODE_EN BIT(11)
+#define PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN BIT(12) /* SR2.0 onwards */
+
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT 16
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_MASK GENMASK(25, 16)
+
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT 28
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK GENMASK(30, 28)
+
+/* PRUSS_MII_RT_TX_IPG0/1 bits */
+#define PRUSS_MII_RT_TX_IPG_IPG_SHIFT 0
+#define PRUSS_MII_RT_TX_IPG_IPG_MASK GENMASK(9, 0)
+
+/* PRUSS_MII_RT_PRS0/1 bits */
+#define PRUSS_MII_RT_PRS_COL BIT(0)
+#define PRUSS_MII_RT_PRS_CRS BIT(1)
+
+/* PRUSS_MII_RT_RX_FRMS0/1 bits */
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_SHIFT 0
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK GENMASK(15, 0)
+
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT 16
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK GENMASK(31, 16)
+
+/* Min/Max in MII_RT_RX_FRMS */
+/* For EMAC and Switch */
+#define PRUSS_MII_RT_RX_FRMS_MAX (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM (64)
+
+/* for HSR and PRP */
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_LRE (PRUSS_MII_RT_RX_FRMS_MAX + \
+ ICSS_LRE_TAG_RCT_SIZE)
+/* PRUSS_MII_RT_RX_PCNT0/1 bits */
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_SHIFT 0
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_MASK GENMASK(3, 0)
+
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_SHIFT 4
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_MASK GENMASK(7, 4)
+
+/* PRUSS_MII_RT_RX_ERR0/1 bits */
+#define PRUSS_MII_RT_RX_ERR_MIN_PCNT_ERR BIT(0)
+#define PRUSS_MII_RT_RX_ERR_MAX_PCNT_ERR BIT(1)
+#define PRUSS_MII_RT_RX_ERR_MIN_FRM_ERR BIT(2)
+#define PRUSS_MII_RT_RX_ERR_MAX_FRM_ERR BIT(3)
+
+#define ICSSG_CFG_OFFSET 0
+#define RGMII_CFG_OFFSET 4
+
+/* Constant to choose between MII0 and MII1 */
+#define ICSS_MII0 0
+#define ICSS_MII1 1
+
+/* ICSSG_CFG Register bits */
+#define ICSSG_CFG_SGMII_MODE BIT(16)
+#define ICSSG_CFG_TX_PRU_EN BIT(11)
+#define ICSSG_CFG_RX_SFD_TX_SOF_EN BIT(10)
+#define ICSSG_CFG_RTU_PRU_PSI_SHARE_EN BIT(9)
+#define ICSSG_CFG_IEP1_TX_EN BIT(8)
+#define ICSSG_CFG_MII1_MODE GENMASK(6, 5)
+#define ICSSG_CFG_MII1_MODE_SHIFT 5
+#define ICSSG_CFG_MII0_MODE GENMASK(4, 3)
+#define ICSSG_CFG_MII0_MODE_SHIFT 3
+#define ICSSG_CFG_RX_L2_G_EN BIT(2)
+#define ICSSG_CFG_TX_L2_EN BIT(1)
+#define ICSSG_CFG_TX_L1_EN BIT(0)
+
+enum mii_mode {
+ MII_MODE_MII = 0,
+ MII_MODE_RGMII
+};
+
+/* RGMII CFG Register bits */
+#define RGMII_CFG_INBAND_EN_MII0 BIT(16)
+#define RGMII_CFG_GIG_EN_MII0 BIT(17)
+#define RGMII_CFG_INBAND_EN_MII1 BIT(20)
+#define RGMII_CFG_GIG_EN_MII1 BIT(21)
+#define RGMII_CFG_FULL_DUPLEX_MII0 BIT(18)
+#define RGMII_CFG_FULL_DUPLEX_MII1 BIT(22)
+#define RGMII_CFG_SPEED_MII0 GENMASK(2, 1)
+#define RGMII_CFG_SPEED_MII1 GENMASK(6, 5)
+#define RGMII_CFG_SPEED_MII0_SHIFT 1
+#define RGMII_CFG_SPEED_MII1_SHIFT 5
+#define RGMII_CFG_FULLDUPLEX_MII0 BIT(3)
+#define RGMII_CFG_FULLDUPLEX_MII1 BIT(7)
+#define RGMII_CFG_FULLDUPLEX_MII0_SHIFT 3
+#define RGMII_CFG_FULLDUPLEX_MII1_SHIFT 7
+#define RGMII_CFG_SPEED_10M 0
+#define RGMII_CFG_SPEED_100M 1
+#define RGMII_CFG_SPEED_1G 2
+
+struct regmap;
+struct prueth_emac;
+
+void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg);
+void icssg_mii_update_mtu(struct regmap *mii_rt, int mii, int mtu);
+void icssg_update_rgmii_cfg(struct regmap *miig_rt, struct prueth_emac *emac);
+u32 icssg_rgmii_cfg_get_bitfield(struct regmap *miig_rt, u32 mask, u32 shift);
+u32 icssg_rgmii_get_speed(struct regmap *miig_rt, int mii);
+u32 icssg_rgmii_get_fullduplex(struct regmap *miig_rt, int mii);
+void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, phy_interface_t phy_if);
+
+#endif /* __NET_PRUSS_MII_RT_H__ */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
new file mode 100644
index 000000000000..410612f43cbd
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -0,0 +1,2336 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/ti-cppi5.h>
+#include <linux/etherdevice.h>
+#include <linux/genalloc.h>
+#include <linux/if_vlan.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/remoteproc/pruss.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+
+#include "icssg_prueth.h"
+#include "icssg_mii_rt.h"
+#include "../k3-cppi-desc-pool.h"
+
+#define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"
+
+/* Netif debug messages possible */
+#define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR | \
+ NETIF_MSG_TX_QUEUED | \
+ NETIF_MSG_INTR | \
+ NETIF_MSG_TX_DONE | \
+ NETIF_MSG_RX_STATUS | \
+ NETIF_MSG_PKTDATA | \
+ NETIF_MSG_HW | \
+ NETIF_MSG_WOL)
+
+#define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)
+
+/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
+#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
+
+#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */
+
+static void prueth_cleanup_rx_chns(struct prueth_emac *emac,
+ struct prueth_rx_chn *rx_chn,
+ int max_rflows)
+{
+ if (rx_chn->desc_pool)
+ k3_cppi_desc_pool_destroy(rx_chn->desc_pool);
+
+ if (rx_chn->rx_chn)
+ k3_udma_glue_release_rx_chn(rx_chn->rx_chn);
+}
+
+static void prueth_cleanup_tx_chns(struct prueth_emac *emac)
+{
+ int i;
+
+ for (i = 0; i < emac->tx_ch_num; i++) {
+ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
+
+ if (tx_chn->desc_pool)
+ k3_cppi_desc_pool_destroy(tx_chn->desc_pool);
+
+ if (tx_chn->tx_chn)
+ k3_udma_glue_release_tx_chn(tx_chn->tx_chn);
+
+ /* Assume prueth_cleanup_tx_chns() is called at the
+ * end after all channel resources are freed
+ */
+ memset(tx_chn, 0, sizeof(*tx_chn));
+ }
+}
+
+static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
+
+ if (tx_chn->irq)
+ free_irq(tx_chn->irq, tx_chn);
+ netif_napi_del(&tx_chn->napi_tx);
+ }
+}
+
+static void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
+ struct cppi5_host_desc_t *desc)
+{
+ struct cppi5_host_desc_t *first_desc, *next_desc;
+ dma_addr_t buf_dma, next_desc_dma;
+ u32 buf_dma_len;
+
+ first_desc = desc;
+ next_desc = first_desc;
+
+ cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
+
+ dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len,
+ DMA_TO_DEVICE);
+
+ next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
+ while (next_desc_dma) {
+ next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
+ next_desc_dma);
+ cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
+
+ dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,
+ DMA_TO_DEVICE);
+
+ next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
+
+ k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
+ }
+
+ k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
+}
+
+static int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
+ int budget)
+{
+ struct net_device *ndev = emac->ndev;
+ struct cppi5_host_desc_t *desc_tx;
+ struct netdev_queue *netif_txq;
+ struct prueth_tx_chn *tx_chn;
+ unsigned int total_bytes = 0;
+ struct sk_buff *skb;
+ dma_addr_t desc_dma;
+ int res, num_tx = 0;
+ void **swdata;
+
+ tx_chn = &emac->tx_chns[chn];
+
+ while (true) {
+ res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);
+ if (res == -ENODATA)
+ break;
+
+ /* teardown completion */
+ if (cppi5_desc_is_tdcm(desc_dma)) {
+ if (atomic_dec_and_test(&emac->tdown_cnt))
+ complete(&emac->tdown_complete);
+ break;
+ }
+
+ desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
+ desc_dma);
+ swdata = cppi5_hdesc_get_swdata(desc_tx);
+
+ skb = *(swdata);
+ prueth_xmit_free(tx_chn, desc_tx);
+
+ ndev = skb->dev;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+ total_bytes += skb->len;
+ napi_consume_skb(skb, budget);
+ num_tx++;
+ }
+
+ if (!num_tx)
+ return 0;
+
+ netif_txq = netdev_get_tx_queue(ndev, chn);
+ netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
+
+ if (netif_tx_queue_stopped(netif_txq)) {
+ /* If the TX queue was stopped, wake it now
+ * if we have enough room.
+ */
+ __netif_tx_lock(netif_txq, smp_processor_id());
+ if (netif_running(ndev) &&
+ (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
+ MAX_SKB_FRAGS))
+ netif_tx_wake_queue(netif_txq);
+ __netif_tx_unlock(netif_txq);
+ }
+
+ return num_tx;
+}
+
+static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget)
+{
+ struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx);
+ struct prueth_emac *emac = tx_chn->emac;
+ int num_tx_packets;
+
+ num_tx_packets = emac_tx_complete_packets(emac, tx_chn->id, budget);
+
+ if (num_tx_packets >= budget)
+ return budget;
+
+ if (napi_complete_done(napi_tx, num_tx_packets))
+ enable_irq(tx_chn->irq);
+
+ return num_tx_packets;
+}
+
+static irqreturn_t prueth_tx_irq(int irq, void *dev_id)
+{
+ struct prueth_tx_chn *tx_chn = dev_id;
+
+ disable_irq_nosync(irq);
+ napi_schedule(&tx_chn->napi_tx);
+
+ return IRQ_HANDLED;
+}
+
+static int prueth_ndev_add_tx_napi(struct prueth_emac *emac)
+{
+ struct prueth *prueth = emac->prueth;
+ int i, ret;
+
+ for (i = 0; i < emac->tx_ch_num; i++) {
+ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
+
+ netif_napi_add_tx(emac->ndev, &tx_chn->napi_tx, emac_napi_tx_poll);
+ ret = request_irq(tx_chn->irq, prueth_tx_irq,
+ IRQF_TRIGGER_HIGH, tx_chn->name,
+ tx_chn);
+ if (ret) {
+ netif_napi_del(&tx_chn->napi_tx);
+ dev_err(prueth->dev, "unable to request TX IRQ %d\n",
+ tx_chn->irq);
+ goto fail;
+ }
+ }
+
+ return 0;
+fail:
+ prueth_ndev_del_tx_napi(emac, i);
+ return ret;
+}
+
+static int prueth_init_tx_chns(struct prueth_emac *emac)
+{
+ static const struct k3_ring_cfg ring_cfg = {
+ .elm_size = K3_RINGACC_RING_ELSIZE_8,
+ .mode = K3_RINGACC_RING_MODE_RING,
+ .flags = 0,
+ .size = PRUETH_MAX_TX_DESC,
+ };
+ struct k3_udma_glue_tx_channel_cfg tx_cfg;
+ struct device *dev = emac->prueth->dev;
+ struct net_device *ndev = emac->ndev;
+ int ret, slice, i;
+ u32 hdesc_size;
+
+ slice = prueth_emac_slice(emac);
+ if (slice < 0)
+ return slice;
+
+ init_completion(&emac->tdown_complete);
+
+ hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
+ PRUETH_NAV_SW_DATA_SIZE);
+ memset(&tx_cfg, 0, sizeof(tx_cfg));
+ tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
+ tx_cfg.tx_cfg = ring_cfg;
+ tx_cfg.txcq_cfg = ring_cfg;
+
+ for (i = 0; i < emac->tx_ch_num; i++) {
+ struct prueth_tx_chn *tx_chn = &emac->tx_chns[i];
+
+ /* To differentiate channels for SLICE0 vs SLICE1 */
+ snprintf(tx_chn->name, sizeof(tx_chn->name),
+ "tx%d-%d", slice, i);
+
+ tx_chn->emac = emac;
+ tx_chn->id = i;
+ tx_chn->descs_num = PRUETH_MAX_TX_DESC;
+
+ tx_chn->tx_chn =
+ k3_udma_glue_request_tx_chn(dev, tx_chn->name,
+ &tx_cfg);
+ if (IS_ERR(tx_chn->tx_chn)) {
+ ret = PTR_ERR(tx_chn->tx_chn);
+ tx_chn->tx_chn = NULL;
+ netdev_err(ndev,
+ "Failed to request tx dma ch: %d\n", ret);
+ goto fail;
+ }
+
+ tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn->tx_chn);
+ tx_chn->desc_pool =
+ k3_cppi_desc_pool_create_name(tx_chn->dma_dev,
+ tx_chn->descs_num,
+ hdesc_size,
+ tx_chn->name);
+ if (IS_ERR(tx_chn->desc_pool)) {
+ ret = PTR_ERR(tx_chn->desc_pool);
+ tx_chn->desc_pool = NULL;
+ netdev_err(ndev, "Failed to create tx pool: %d\n", ret);
+ goto fail;
+ }
+
+ tx_chn->irq = k3_udma_glue_tx_get_irq(tx_chn->tx_chn);
+ if (tx_chn->irq <= 0) {
+ ret = -EINVAL;
+ netdev_err(ndev, "failed to get tx irq\n");
+ goto fail;
+ }
+
+ snprintf(tx_chn->name, sizeof(tx_chn->name), "%s-tx%d",
+ dev_name(dev), tx_chn->id);
+ }
+
+ return 0;
+
+fail:
+ prueth_cleanup_tx_chns(emac);
+ return ret;
+}
+
+static int prueth_init_rx_chns(struct prueth_emac *emac,
+ struct prueth_rx_chn *rx_chn,
+ char *name, u32 max_rflows,
+ u32 max_desc_num)
+{
+ struct k3_udma_glue_rx_channel_cfg rx_cfg;
+ struct device *dev = emac->prueth->dev;
+ struct net_device *ndev = emac->ndev;
+ u32 fdqring_id, hdesc_size;
+ int i, ret = 0, slice;
+
+ slice = prueth_emac_slice(emac);
+ if (slice < 0)
+ return slice;
+
+ /* To differentiate channels for SLICE0 vs SLICE1 */
+ snprintf(rx_chn->name, sizeof(rx_chn->name), "%s%d", name, slice);
+
+ hdesc_size = cppi5_hdesc_calc_size(true, PRUETH_NAV_PS_DATA_SIZE,
+ PRUETH_NAV_SW_DATA_SIZE);
+ memset(&rx_cfg, 0, sizeof(rx_cfg));
+ rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE;
+ rx_cfg.flow_id_num = max_rflows;
+ rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */
+
+ /* init all flows */
+ rx_chn->dev = dev;
+ rx_chn->descs_num = max_desc_num;
+
+ rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, rx_chn->name,
+ &rx_cfg);
+ if (IS_ERR(rx_chn->rx_chn)) {
+ ret = PTR_ERR(rx_chn->rx_chn);
+ rx_chn->rx_chn = NULL;
+ netdev_err(ndev, "Failed to request rx dma ch: %d\n", ret);
+ goto fail;
+ }
+
+ rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn->rx_chn);
+ rx_chn->desc_pool = k3_cppi_desc_pool_create_name(rx_chn->dma_dev,
+ rx_chn->descs_num,
+ hdesc_size,
+ rx_chn->name);
+ if (IS_ERR(rx_chn->desc_pool)) {
+ ret = PTR_ERR(rx_chn->desc_pool);
+ rx_chn->desc_pool = NULL;
+ netdev_err(ndev, "Failed to create rx pool: %d\n", ret);
+ goto fail;
+ }
+
+ emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn->rx_chn);
+ netdev_dbg(ndev, "flow id base = %d\n", emac->rx_flow_id_base);
+
+ fdqring_id = K3_RINGACC_RING_ID_ANY;
+ for (i = 0; i < rx_cfg.flow_id_num; i++) {
+ struct k3_ring_cfg rxring_cfg = {
+ .elm_size = K3_RINGACC_RING_ELSIZE_8,
+ .mode = K3_RINGACC_RING_MODE_RING,
+ .flags = 0,
+ };
+ struct k3_ring_cfg fdqring_cfg = {
+ .elm_size = K3_RINGACC_RING_ELSIZE_8,
+ .flags = K3_RINGACC_RING_SHARED,
+ };
+ struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = {
+ .rx_cfg = rxring_cfg,
+ .rxfdq_cfg = fdqring_cfg,
+ .ring_rxq_id = K3_RINGACC_RING_ID_ANY,
+ .src_tag_lo_sel =
+ K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG,
+ };
+
+ 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;
+ rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode;
+
+ ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
+ i, &rx_flow_cfg);
+ if (ret) {
+ netdev_err(ndev, "Failed to init rx flow%d %d\n",
+ i, ret);
+ goto fail;
+ }
+ if (!i)
+ fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn->rx_chn,
+ i);
+ rx_chn->irq[i] = k3_udma_glue_rx_get_irq(rx_chn->rx_chn, i);
+ if (rx_chn->irq[i] <= 0) {
+ ret = rx_chn->irq[i];
+ netdev_err(ndev, "Failed to get rx dma irq");
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ prueth_cleanup_rx_chns(emac, rx_chn, max_rflows);
+ return ret;
+}
+
+static int prueth_dma_rx_push(struct prueth_emac *emac,
+ struct sk_buff *skb,
+ struct prueth_rx_chn *rx_chn)
+{
+ struct net_device *ndev = emac->ndev;
+ struct cppi5_host_desc_t *desc_rx;
+ u32 pkt_len = skb_tailroom(skb);
+ 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) {
+ netdev_err(ndev, "rx push: failed to allocate descriptor\n");
+ return -ENOMEM;
+ }
+ desc_dma = k3_cppi_desc_pool_virt2dma(rx_chn->desc_pool, desc_rx);
+
+ buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) {
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
+ netdev_err(ndev, "rx push: failed to map rx pkt buffer\n");
+ return -EINVAL;
+ }
+
+ cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT,
+ PRUETH_NAV_PS_DATA_SIZE);
+ k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn->rx_chn, &buf_dma);
+ cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb));
+
+ swdata = cppi5_hdesc_get_swdata(desc_rx);
+ *swdata = skb;
+
+ return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, 0,
+ desc_rx, desc_dma);
+}
+
+static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns)
+{
+ u32 iepcount_lo, iepcount_hi, hi_rollover_count;
+ u64 ns;
+
+ iepcount_lo = lo & GENMASK(19, 0);
+ iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20;
+ hi_rollover_count = hi >> 11;
+
+ ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw);
+ ns = ns * cycle_time_ns + iepcount_lo;
+
+ return ns;
+}
+
+static void emac_rx_timestamp(struct prueth_emac *emac,
+ struct sk_buff *skb, u32 *psdata)
+{
+ struct skb_shared_hwtstamps *ssh;
+ u64 ns;
+
+ u32 hi_sw = readl(emac->prueth->shram.va +
+ TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
+ ns = icssg_ts_to_ns(hi_sw, psdata[1], psdata[0],
+ IEP_DEFAULT_CYCLE_TIME_NS);
+
+ ssh = skb_hwtstamps(skb);
+ memset(ssh, 0, sizeof(*ssh));
+ ssh->hwtstamp = ns_to_ktime(ns);
+}
+
+static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
+{
+ struct prueth_rx_chn *rx_chn = &emac->rx_chns;
+ u32 buf_dma_len, pkt_len, port_id = 0;
+ struct net_device *ndev = emac->ndev;
+ struct cppi5_host_desc_t *desc_rx;
+ struct sk_buff *skb, *new_skb;
+ dma_addr_t desc_dma, buf_dma;
+ void **swdata;
+ u32 *psdata;
+ int ret;
+
+ ret = k3_udma_glue_pop_rx_chn(rx_chn->rx_chn, flow_id, &desc_dma);
+ if (ret) {
+ if (ret != -ENODATA)
+ netdev_err(ndev, "rx pop: failed: %d\n", ret);
+ return ret;
+ }
+
+ if (cppi5_desc_is_tdcm(desc_dma)) /* Teardown ? */
+ return 0;
+
+ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
+
+ swdata = cppi5_hdesc_get_swdata(desc_rx);
+ skb = *swdata;
+
+ psdata = cppi5_hdesc_get_psdata(desc_rx);
+ /* RX HW timestamp */
+ if (emac->rx_ts_enabled)
+ emac_rx_timestamp(emac, skb, psdata);
+
+ 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);
+ /* firmware adds 4 CRC bytes, strip them */
+ pkt_len -= 4;
+ cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
+
+ 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);
+
+ skb->dev = ndev;
+ new_skb = netdev_alloc_skb_ip_align(ndev, PRUETH_MAX_PKT_SIZE);
+ /* if allocation fails we drop the packet but push the
+ * descriptor back to the ring with old skb to prevent a stall
+ */
+ if (!new_skb) {
+ ndev->stats.rx_dropped++;
+ new_skb = skb;
+ } else {
+ /* send the filled skb up the n/w stack */
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(&emac->napi_rx, skb);
+ ndev->stats.rx_bytes += pkt_len;
+ ndev->stats.rx_packets++;
+ }
+
+ /* queue another RX DMA */
+ ret = prueth_dma_rx_push(emac, new_skb, &emac->rx_chns);
+ if (WARN_ON(ret < 0)) {
+ dev_kfree_skb_any(new_skb);
+ ndev->stats.rx_errors++;
+ ndev->stats.rx_dropped++;
+ }
+
+ return ret;
+}
+
+static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma)
+{
+ struct prueth_rx_chn *rx_chn = data;
+ struct cppi5_host_desc_t *desc_rx;
+ struct sk_buff *skb;
+ dma_addr_t buf_dma;
+ u32 buf_dma_len;
+ void **swdata;
+
+ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
+ swdata = cppi5_hdesc_get_swdata(desc_rx);
+ skb = *swdata;
+ cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
+ k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
+
+ dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len,
+ DMA_FROM_DEVICE);
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
+
+ dev_kfree_skb_any(skb);
+}
+
+static int emac_get_tx_ts(struct prueth_emac *emac,
+ struct emac_tx_ts_response *rsp)
+{
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+ int addr;
+
+ addr = icssg_queue_pop(prueth, slice == 0 ?
+ ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1);
+ if (addr < 0)
+ return addr;
+
+ memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
+ /* return buffer back for to pool */
+ icssg_queue_push(prueth, slice == 0 ?
+ ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr);
+
+ return 0;
+}
+
+static void tx_ts_work(struct prueth_emac *emac)
+{
+ struct skb_shared_hwtstamps ssh;
+ struct emac_tx_ts_response tsr;
+ struct sk_buff *skb;
+ int ret = 0;
+ u32 hi_sw;
+ u64 ns;
+
+ /* There may be more than one pending requests */
+ while (1) {
+ ret = emac_get_tx_ts(emac, &tsr);
+ if (ret) /* nothing more */
+ break;
+
+ if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS ||
+ !emac->tx_ts_skb[tsr.cookie]) {
+ netdev_err(emac->ndev, "Invalid TX TS cookie 0x%x\n",
+ tsr.cookie);
+ break;
+ }
+
+ skb = emac->tx_ts_skb[tsr.cookie];
+ emac->tx_ts_skb[tsr.cookie] = NULL; /* free slot */
+ if (!skb) {
+ netdev_err(emac->ndev, "Driver Bug! got NULL skb\n");
+ break;
+ }
+
+ hi_sw = readl(emac->prueth->shram.va +
+ TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);
+ ns = icssg_ts_to_ns(hi_sw, tsr.hi_ts, tsr.lo_ts,
+ IEP_DEFAULT_CYCLE_TIME_NS);
+
+ memset(&ssh, 0, sizeof(ssh));
+ ssh.hwtstamp = ns_to_ktime(ns);
+
+ skb_tstamp_tx(skb, &ssh);
+ dev_consume_skb_any(skb);
+
+ if (atomic_dec_and_test(&emac->tx_ts_pending)) /* no more? */
+ break;
+ }
+}
+
+static int prueth_tx_ts_cookie_get(struct prueth_emac *emac)
+{
+ int i;
+
+ /* search and get the next free slot */
+ for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
+ if (!emac->tx_ts_skb[i]) {
+ emac->tx_ts_skb[i] = ERR_PTR(-EBUSY); /* reserve slot */
+ return i;
+ }
+ }
+
+ return -EBUSY;
+}
+
+/**
+ * emac_ndo_start_xmit - EMAC Transmit function
+ * @skb: SKB pointer
+ * @ndev: EMAC network adapter
+ *
+ * Called by the system to transmit a packet - we queue the packet in
+ * EMAC hardware transmit queue
+ * Doesn't wait for completion we'll check for TX completion in
+ * emac_tx_complete_packets().
+ *
+ * Return: enum netdev_tx
+ */
+static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc;
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct netdev_queue *netif_txq;
+ struct prueth_tx_chn *tx_chn;
+ dma_addr_t desc_dma, buf_dma;
+ int i, ret = 0, q_idx;
+ bool in_tx_ts = 0;
+ int tx_ts_cookie;
+ void **swdata;
+ u32 pkt_len;
+ u32 *epib;
+
+ pkt_len = skb_headlen(skb);
+ q_idx = skb_get_queue_mapping(skb);
+
+ tx_chn = &emac->tx_chns[q_idx];
+ netif_txq = netdev_get_tx_queue(ndev, q_idx);
+
+ /* Map the linear buffer */
+ buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
+ netdev_err(ndev, "tx: failed to map skb buffer\n");
+ ret = NETDEV_TX_OK;
+ goto drop_free_skb;
+ }
+
+ first_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
+ if (!first_desc) {
+ netdev_dbg(ndev, "tx: failed to allocate descriptor\n");
+ dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE);
+ goto drop_stop_q_busy;
+ }
+
+ cppi5_hdesc_init(first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT,
+ PRUETH_NAV_PS_DATA_SIZE);
+ cppi5_hdesc_set_pkttype(first_desc, 0);
+ epib = first_desc->epib;
+ epib[0] = 0;
+ epib[1] = 0;
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+ emac->tx_ts_enabled) {
+ tx_ts_cookie = prueth_tx_ts_cookie_get(emac);
+ if (tx_ts_cookie >= 0) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ /* Request TX timestamp */
+ epib[0] = (u32)tx_ts_cookie;
+ epib[1] = 0x80000000; /* TX TS request */
+ emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb);
+ in_tx_ts = 1;
+ }
+ }
+
+ /* set dst tag to indicate internal qid at the firmware which is at
+ * bit8..bit15. bit0..bit7 indicates port num for directed
+ * packets in case of switch mode operation
+ */
+ cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8)));
+ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
+ cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len);
+ swdata = cppi5_hdesc_get_swdata(first_desc);
+ *swdata = skb;
+
+ /* Handle the case where skb is fragmented in pages */
+ cur_desc = first_desc;
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 frag_size = skb_frag_size(frag);
+
+ next_desc = k3_cppi_desc_pool_alloc(tx_chn->desc_pool);
+ if (!next_desc) {
+ netdev_err(ndev,
+ "tx: failed to allocate frag. descriptor\n");
+ goto free_desc_stop_q_busy_cleanup_tx_ts;
+ }
+
+ buf_dma = skb_frag_dma_map(tx_chn->dma_dev, frag, 0, frag_size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(tx_chn->dma_dev, buf_dma)) {
+ netdev_err(ndev, "tx: Failed to map skb page\n");
+ k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
+ ret = NETDEV_TX_OK;
+ goto cleanup_tx_ts;
+ }
+
+ cppi5_hdesc_reset_hbdesc(next_desc);
+ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
+ cppi5_hdesc_attach_buf(next_desc,
+ buf_dma, frag_size, buf_dma, frag_size);
+
+ desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool,
+ next_desc);
+ k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &desc_dma);
+ cppi5_hdesc_link_hbdesc(cur_desc, desc_dma);
+
+ pkt_len += frag_size;
+ cur_desc = next_desc;
+ }
+ WARN_ON_ONCE(pkt_len != skb->len);
+
+ /* report bql before sending packet */
+ netdev_tx_sent_queue(netif_txq, pkt_len);
+
+ cppi5_hdesc_set_pktlen(first_desc, pkt_len);
+ desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc);
+ /* cppi5_desc_dump(first_desc, 64); */
+
+ skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */
+ ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
+ if (ret) {
+ netdev_err(ndev, "tx: push failed: %d\n", ret);
+ goto drop_free_descs;
+ }
+
+ if (in_tx_ts)
+ atomic_inc(&emac->tx_ts_pending);
+
+ if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) < MAX_SKB_FRAGS) {
+ netif_tx_stop_queue(netif_txq);
+ /* Barrier, so that stop_queue visible to other cpus */
+ smp_mb__after_atomic();
+
+ if (k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
+ MAX_SKB_FRAGS)
+ netif_tx_wake_queue(netif_txq);
+ }
+
+ return NETDEV_TX_OK;
+
+cleanup_tx_ts:
+ if (in_tx_ts) {
+ dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
+ emac->tx_ts_skb[tx_ts_cookie] = NULL;
+ }
+
+drop_free_descs:
+ prueth_xmit_free(tx_chn, first_desc);
+
+drop_free_skb:
+ dev_kfree_skb_any(skb);
+
+ /* error */
+ ndev->stats.tx_dropped++;
+ netdev_err(ndev, "tx: error: %d\n", ret);
+
+ return ret;
+
+free_desc_stop_q_busy_cleanup_tx_ts:
+ if (in_tx_ts) {
+ dev_kfree_skb_any(emac->tx_ts_skb[tx_ts_cookie]);
+ emac->tx_ts_skb[tx_ts_cookie] = NULL;
+ }
+ prueth_xmit_free(tx_chn, first_desc);
+
+drop_stop_q_busy:
+ netif_tx_stop_queue(netif_txq);
+ return NETDEV_TX_BUSY;
+}
+
+static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma)
+{
+ struct prueth_tx_chn *tx_chn = data;
+ struct cppi5_host_desc_t *desc_tx;
+ struct sk_buff *skb;
+ void **swdata;
+
+ desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);
+ swdata = cppi5_hdesc_get_swdata(desc_tx);
+ skb = *(swdata);
+ prueth_xmit_free(tx_chn, desc_tx);
+
+ dev_kfree_skb_any(skb);
+}
+
+static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)
+{
+ struct prueth_emac *emac = dev_id;
+
+ /* currently only TX timestamp is being returned */
+ tx_ts_work(emac);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t prueth_rx_irq(int irq, void *dev_id)
+{
+ struct prueth_emac *emac = dev_id;
+
+ disable_irq_nosync(irq);
+ napi_schedule(&emac->napi_rx);
+
+ return IRQ_HANDLED;
+}
+
+struct icssg_firmwares {
+ char *pru;
+ char *rtu;
+ char *txpru;
+};
+
+static struct icssg_firmwares icssg_emac_firmwares[] = {
+ {
+ .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
+ .rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
+ .txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
+ },
+ {
+ .pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
+ .rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
+ .txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
+ }
+};
+
+static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
+{
+ struct icssg_firmwares *firmwares;
+ struct device *dev = prueth->dev;
+ int slice, ret;
+
+ firmwares = icssg_emac_firmwares;
+
+ slice = prueth_emac_slice(emac);
+ if (slice < 0) {
+ netdev_err(emac->ndev, "invalid port\n");
+ return -EINVAL;
+ }
+
+ ret = icssg_config(prueth, emac, slice);
+ if (ret)
+ return ret;
+
+ ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru);
+ ret = rproc_boot(prueth->pru[slice]);
+ if (ret) {
+ dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
+ return -EINVAL;
+ }
+
+ ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu);
+ ret = rproc_boot(prueth->rtu[slice]);
+ if (ret) {
+ dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
+ goto halt_pru;
+ }
+
+ ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru);
+ ret = rproc_boot(prueth->txpru[slice]);
+ if (ret) {
+ dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);
+ goto halt_rtu;
+ }
+
+ emac->fw_running = 1;
+ return 0;
+
+halt_rtu:
+ rproc_shutdown(prueth->rtu[slice]);
+
+halt_pru:
+ rproc_shutdown(prueth->pru[slice]);
+
+ return ret;
+}
+
+static void prueth_emac_stop(struct prueth_emac *emac)
+{
+ struct prueth *prueth = emac->prueth;
+ int slice;
+
+ switch (emac->port_id) {
+ case PRUETH_PORT_MII0:
+ slice = ICSS_SLICE0;
+ break;
+ case PRUETH_PORT_MII1:
+ slice = ICSS_SLICE1;
+ break;
+ default:
+ netdev_err(emac->ndev, "invalid port\n");
+ return;
+ }
+
+ emac->fw_running = 0;
+ rproc_shutdown(prueth->txpru[slice]);
+ rproc_shutdown(prueth->rtu[slice]);
+ rproc_shutdown(prueth->pru[slice]);
+}
+
+static void prueth_cleanup_tx_ts(struct prueth_emac *emac)
+{
+ int i;
+
+ for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) {
+ if (emac->tx_ts_skb[i]) {
+ dev_kfree_skb_any(emac->tx_ts_skb[i]);
+ emac->tx_ts_skb[i] = NULL;
+ }
+ }
+}
+
+/* called back by PHY layer if there is change in link state of hw port*/
+static void emac_adjust_link(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+ struct prueth *prueth = emac->prueth;
+ bool new_state = false;
+ unsigned long flags;
+
+ if (phydev->link) {
+ /* check the mode of operation - full/half duplex */
+ if (phydev->duplex != emac->duplex) {
+ new_state = true;
+ emac->duplex = phydev->duplex;
+ }
+ if (phydev->speed != emac->speed) {
+ new_state = true;
+ emac->speed = phydev->speed;
+ }
+ if (!emac->link) {
+ new_state = true;
+ emac->link = 1;
+ }
+ } else if (emac->link) {
+ new_state = true;
+ emac->link = 0;
+
+ /* f/w should support 100 & 1000 */
+ emac->speed = SPEED_1000;
+
+ /* half duplex may not be supported by f/w */
+ emac->duplex = DUPLEX_FULL;
+ }
+
+ if (new_state) {
+ phy_print_status(phydev);
+
+ /* update RGMII and MII configuration based on PHY negotiated
+ * values
+ */
+ if (emac->link) {
+ /* Set the RGMII cfg for gig en and full duplex */
+ icssg_update_rgmii_cfg(prueth->miig_rt, emac);
+
+ /* update the Tx IPG based on 100M/1G speed */
+ spin_lock_irqsave(&emac->lock, flags);
+ icssg_config_ipg(emac);
+ spin_unlock_irqrestore(&emac->lock, flags);
+ icssg_config_set_speed(emac);
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD);
+
+ } else {
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
+ }
+ }
+
+ if (emac->link) {
+ /* reactivate the transmit queue */
+ netif_tx_wake_all_queues(ndev);
+ } else {
+ netif_tx_stop_all_queues(ndev);
+ prueth_cleanup_tx_ts(emac);
+ }
+}
+
+static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget)
+{
+ struct prueth_emac *emac = prueth_napi_to_emac(napi_rx);
+ int rx_flow = PRUETH_RX_FLOW_DATA;
+ int flow = PRUETH_MAX_RX_FLOWS;
+ int num_rx = 0;
+ int cur_budget;
+ int ret;
+
+ while (flow--) {
+ cur_budget = budget - num_rx;
+
+ while (cur_budget--) {
+ ret = emac_rx_packet(emac, flow);
+ if (ret)
+ break;
+ num_rx++;
+ }
+
+ if (num_rx >= budget)
+ break;
+ }
+
+ if (num_rx < budget && napi_complete_done(napi_rx, num_rx))
+ enable_irq(emac->rx_chns.irq[rx_flow]);
+
+ return num_rx;
+}
+
+static int prueth_prepare_rx_chan(struct prueth_emac *emac,
+ struct prueth_rx_chn *chn,
+ int buf_size)
+{
+ struct sk_buff *skb;
+ int i, ret;
+
+ for (i = 0; i < chn->descs_num; i++) {
+ skb = __netdev_alloc_skb_ip_align(NULL, buf_size, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ ret = prueth_dma_rx_push(emac, skb, chn);
+ if (ret < 0) {
+ netdev_err(emac->ndev,
+ "cannot submit skb for rx chan %s ret %d\n",
+ chn->name, ret);
+ kfree_skb(skb);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num,
+ bool free_skb)
+{
+ int i;
+
+ for (i = 0; i < ch_num; i++) {
+ if (free_skb)
+ k3_udma_glue_reset_tx_chn(emac->tx_chns[i].tx_chn,
+ &emac->tx_chns[i],
+ prueth_tx_cleanup);
+ k3_udma_glue_disable_tx_chn(emac->tx_chns[i].tx_chn);
+ }
+}
+
+static void prueth_reset_rx_chan(struct prueth_rx_chn *chn,
+ int num_flows, bool disable)
+{
+ int i;
+
+ for (i = 0; i < num_flows; i++)
+ k3_udma_glue_reset_rx_chn(chn->rx_chn, i, chn,
+ prueth_rx_cleanup, !!i);
+ if (disable)
+ k3_udma_glue_disable_rx_chn(chn->rx_chn);
+}
+
+static int emac_phy_connect(struct prueth_emac *emac)
+{
+ struct prueth *prueth = emac->prueth;
+ struct net_device *ndev = emac->ndev;
+ /* connect PHY */
+ ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node,
+ &emac_adjust_link, 0,
+ emac->phy_if);
+ if (!ndev->phydev) {
+ dev_err(prueth->dev, "couldn't connect to phy %s\n",
+ emac->phy_node->full_name);
+ return -ENODEV;
+ }
+
+ /* remove unsupported modes */
+ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
+ phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
+
+ if (emac->phy_if == PHY_INTERFACE_MODE_MII)
+ phy_set_max_speed(ndev->phydev, SPEED_100);
+
+ return 0;
+}
+
+static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts)
+{
+ u32 hi_rollover_count, hi_rollover_count_r;
+ struct prueth_emac *emac = clockops_data;
+ struct prueth *prueth = emac->prueth;
+ void __iomem *fw_hi_r_count_addr;
+ void __iomem *fw_count_hi_addr;
+ u32 iepcount_hi, iepcount_hi_r;
+ unsigned long flags;
+ u32 iepcount_lo;
+ u64 ts = 0;
+
+ fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET;
+ fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET;
+
+ local_irq_save(flags);
+ do {
+ iepcount_hi = icss_iep_get_count_hi(emac->iep);
+ iepcount_hi += readl(fw_count_hi_addr);
+ hi_rollover_count = readl(fw_hi_r_count_addr);
+ ptp_read_system_prets(sts);
+ iepcount_lo = icss_iep_get_count_low(emac->iep);
+ ptp_read_system_postts(sts);
+
+ iepcount_hi_r = icss_iep_get_count_hi(emac->iep);
+ iepcount_hi_r += readl(fw_count_hi_addr);
+ hi_rollover_count_r = readl(fw_hi_r_count_addr);
+ } while ((iepcount_hi_r != iepcount_hi) ||
+ (hi_rollover_count != hi_rollover_count_r));
+ local_irq_restore(flags);
+
+ ts = ((u64)hi_rollover_count) << 23 | iepcount_hi;
+ ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo;
+
+ return ts;
+}
+
+static void prueth_iep_settime(void *clockops_data, u64 ns)
+{
+ struct icssg_setclock_desc __iomem *sc_descp;
+ struct prueth_emac *emac = clockops_data;
+ struct icssg_setclock_desc sc_desc;
+ u64 cyclecount;
+ u32 cycletime;
+ int timeout;
+
+ if (!emac->fw_running)
+ return;
+
+ sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET;
+
+ cycletime = IEP_DEFAULT_CYCLE_TIME_NS;
+ cyclecount = ns / cycletime;
+
+ memset(&sc_desc, 0, sizeof(sc_desc));
+ sc_desc.margin = cycletime - 1000;
+ sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0);
+ sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32;
+ sc_desc.iepcount_set = ns % cycletime;
+ sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4
+
+ memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc));
+
+ writeb(1, &sc_descp->request);
+
+ timeout = 5; /* fw should take 2-3 ms */
+ while (timeout--) {
+ if (readb(&sc_descp->acknowledgment))
+ return;
+
+ usleep_range(500, 1000);
+ }
+
+ dev_err(emac->prueth->dev, "settime timeout\n");
+}
+
+static int prueth_perout_enable(void *clockops_data,
+ struct ptp_perout_request *req, int on,
+ u64 *cmp)
+{
+ struct prueth_emac *emac = clockops_data;
+ u32 reduction_factor = 0, offset = 0;
+ struct timespec64 ts;
+ u64 ns_period;
+
+ if (!on)
+ return 0;
+
+ /* Any firmware specific stuff for PPS/PEROUT handling */
+ ts.tv_sec = req->period.sec;
+ ts.tv_nsec = req->period.nsec;
+ ns_period = timespec64_to_ns(&ts);
+
+ /* f/w doesn't support period less than cycle time */
+ if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS)
+ return -ENXIO;
+
+ reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS;
+ offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS;
+
+ /* f/w requires at least 1uS within a cycle so CMP
+ * can trigger after SYNC is enabled
+ */
+ if (offset < 5 * NSEC_PER_USEC)
+ offset = 5 * NSEC_PER_USEC;
+
+ /* if offset is close to cycle time then we will miss
+ * the CMP event for last tick when IEP rolls over.
+ * In normal mode, IEP tick is 4ns.
+ * In slow compensation it could be 0ns or 8ns at
+ * every slow compensation cycle.
+ */
+ if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8)
+ offset = IEP_DEFAULT_CYCLE_TIME_NS - 8;
+
+ /* we're in shadow mode so need to set upper 32-bits */
+ *cmp = (u64)offset << 32;
+
+ 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);
+
+ return 0;
+}
+
+const struct icss_iep_clockops prueth_iep_clockops = {
+ .settime = prueth_iep_settime,
+ .gettime = prueth_iep_gettime,
+ .perout_enable = prueth_perout_enable,
+};
+
+/**
+ * emac_ndo_open - EMAC device open
+ * @ndev: network adapter device
+ *
+ * Called when system wants to start the interface.
+ *
+ * Return: 0 for a successful open, or appropriate error code
+ */
+static int emac_ndo_open(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ int ret, i, num_data_chn = emac->tx_ch_num;
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+ struct device *dev = prueth->dev;
+ int max_rx_flows;
+ int rx_flow;
+
+ /* clear SMEM and MSMC settings for all slices */
+ if (!prueth->emacs_initialized) {
+ memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);
+ memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);
+ }
+
+ /* set h/w MAC as user might have re-configured */
+ ether_addr_copy(emac->mac_addr, ndev->dev_addr);
+
+ icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
+ icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);
+
+ icssg_class_default(prueth->miig_rt, slice, 0);
+
+ /* Notify the stack of the actual queue counts. */
+ ret = netif_set_real_num_tx_queues(ndev, num_data_chn);
+ if (ret) {
+ dev_err(dev, "cannot set real number of tx queues\n");
+ return ret;
+ }
+
+ init_completion(&emac->cmd_complete);
+ ret = prueth_init_tx_chns(emac);
+ if (ret) {
+ dev_err(dev, "failed to init tx channel: %d\n", ret);
+ return ret;
+ }
+
+ max_rx_flows = PRUETH_MAX_RX_FLOWS;
+ ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx",
+ max_rx_flows, PRUETH_MAX_RX_DESC);
+ if (ret) {
+ dev_err(dev, "failed to init rx channel: %d\n", ret);
+ goto cleanup_tx;
+ }
+
+ ret = prueth_ndev_add_tx_napi(emac);
+ if (ret)
+ goto cleanup_rx;
+
+ /* we use only the highest priority flow for now i.e. @irq[3] */
+ rx_flow = PRUETH_RX_FLOW_DATA;
+ ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq,
+ IRQF_TRIGGER_HIGH, dev_name(dev), emac);
+ if (ret) {
+ dev_err(dev, "unable to request RX IRQ\n");
+ goto cleanup_napi;
+ }
+
+ /* reset and start PRU firmware */
+ ret = prueth_emac_start(prueth, emac);
+ if (ret)
+ goto free_rx_irq;
+
+ icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);
+
+ if (!prueth->emacs_initialized) {
+ ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
+ emac, IEP_DEFAULT_CYCLE_TIME_NS);
+ }
+
+ ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq,
+ IRQF_ONESHOT, dev_name(dev), emac);
+ if (ret)
+ goto stop;
+
+ /* Prepare RX */
+ ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE);
+ if (ret)
+ goto free_tx_ts_irq;
+
+ ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn);
+ if (ret)
+ goto reset_rx_chn;
+
+ for (i = 0; i < emac->tx_ch_num; i++) {
+ ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn);
+ if (ret)
+ goto reset_tx_chan;
+ }
+
+ /* Enable NAPI in Tx and Rx direction */
+ for (i = 0; i < emac->tx_ch_num; i++)
+ napi_enable(&emac->tx_chns[i].napi_tx);
+ napi_enable(&emac->napi_rx);
+
+ /* start PHY */
+ phy_start(ndev->phydev);
+
+ prueth->emacs_initialized++;
+
+ queue_work(system_long_wq, &emac->stats_work.work);
+
+ return 0;
+
+reset_tx_chan:
+ /* Since interface is not yet up, there is wouldn't be
+ * any SKB for completion. So set false to free_skb
+ */
+ prueth_reset_tx_chan(emac, i, false);
+reset_rx_chn:
+ prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false);
+free_tx_ts_irq:
+ free_irq(emac->tx_ts_irq, emac);
+stop:
+ prueth_emac_stop(emac);
+free_rx_irq:
+ free_irq(emac->rx_chns.irq[rx_flow], emac);
+cleanup_napi:
+ prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
+cleanup_rx:
+ prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
+cleanup_tx:
+ prueth_cleanup_tx_chns(emac);
+
+ return ret;
+}
+
+/**
+ * emac_ndo_stop - EMAC device stop
+ * @ndev: network adapter device
+ *
+ * Called when system wants to stop or down the interface.
+ *
+ * Return: Always 0 (Success)
+ */
+static int emac_ndo_stop(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth *prueth = emac->prueth;
+ int rx_flow = PRUETH_RX_FLOW_DATA;
+ int max_rx_flows;
+ int ret, i;
+
+ /* inform the upper layers. */
+ netif_tx_stop_all_queues(ndev);
+
+ /* block packets from wire */
+ if (ndev->phydev)
+ phy_stop(ndev->phydev);
+
+ icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac));
+
+ atomic_set(&emac->tdown_cnt, emac->tx_ch_num);
+ /* ensure new tdown_cnt value is visible */
+ smp_mb__after_atomic();
+ /* tear down and disable UDMA channels */
+ reinit_completion(&emac->tdown_complete);
+ for (i = 0; i < emac->tx_ch_num; i++)
+ k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false);
+
+ ret = wait_for_completion_timeout(&emac->tdown_complete,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ netdev_err(ndev, "tx teardown timeout\n");
+
+ prueth_reset_tx_chan(emac, emac->tx_ch_num, true);
+ for (i = 0; i < emac->tx_ch_num; i++)
+ napi_disable(&emac->tx_chns[i].napi_tx);
+
+ max_rx_flows = PRUETH_MAX_RX_FLOWS;
+ k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true);
+
+ prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true);
+
+ napi_disable(&emac->napi_rx);
+
+ cancel_work_sync(&emac->rx_mode_work);
+
+ /* Destroying the queued work in ndo_stop() */
+ cancel_delayed_work_sync(&emac->stats_work);
+
+ /* stop PRUs */
+ prueth_emac_stop(emac);
+
+ if (prueth->emacs_initialized == 1)
+ icss_iep_exit(emac->iep);
+
+ /* stop PRUs */
+ prueth_emac_stop(emac);
+
+ free_irq(emac->tx_ts_irq, emac);
+
+ free_irq(emac->rx_chns.irq[rx_flow], emac);
+ prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);
+ prueth_cleanup_tx_chns(emac);
+
+ prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);
+ prueth_cleanup_tx_chns(emac);
+
+ prueth->emacs_initialized--;
+
+ return 0;
+}
+
+static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue)
+{
+ ndev->stats.tx_errors++;
+}
+
+static void emac_ndo_set_rx_mode_work(struct work_struct *work)
+{
+ struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work);
+ struct net_device *ndev = emac->ndev;
+ bool promisc, allmulti;
+
+ if (!netif_running(ndev))
+ return;
+
+ promisc = ndev->flags & IFF_PROMISC;
+ allmulti = ndev->flags & IFF_ALLMULTI;
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_DISABLE);
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_DISABLE);
+
+ if (promisc) {
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_ENABLE);
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
+ return;
+ }
+
+ if (allmulti) {
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
+ return;
+ }
+
+ if (!netdev_mc_empty(ndev)) {
+ emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);
+ return;
+ }
+}
+
+/**
+ * emac_ndo_set_rx_mode - EMAC set receive mode function
+ * @ndev: The EMAC network adapter
+ *
+ * Called when system wants to set the receive mode of the device.
+ *
+ */
+static void emac_ndo_set_rx_mode(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ queue_work(emac->cmd_wq, &emac->rx_mode_work);
+}
+
+static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct hwtstamp_config config;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ emac->tx_ts_enabled = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ emac->tx_ts_enabled = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ emac->rx_ts_enabled = 0;
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ emac->rx_ts_enabled = 1;
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct hwtstamp_config config;
+
+ config.flags = 0;
+ config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGHWTSTAMP:
+ return emac_get_ts_config(ndev, ifr);
+ case SIOCSHWTSTAMP:
+ return emac_set_ts_config(ndev, ifr);
+ default:
+ break;
+ }
+
+ return phy_do_ioctl(ndev, ifr, cmd);
+}
+
+static void emac_ndo_get_stats64(struct net_device *ndev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ emac_update_hardware_stats(emac);
+
+ stats->rx_packets = emac_get_stat_by_name(emac, "rx_packets");
+ stats->rx_bytes = emac_get_stat_by_name(emac, "rx_bytes");
+ stats->tx_packets = emac_get_stat_by_name(emac, "tx_packets");
+ stats->tx_bytes = emac_get_stat_by_name(emac, "tx_bytes");
+ stats->rx_crc_errors = emac_get_stat_by_name(emac, "rx_crc_errors");
+ stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");
+ stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames");
+
+ stats->rx_errors = ndev->stats.rx_errors;
+ stats->rx_dropped = ndev->stats.rx_dropped;
+ stats->tx_errors = ndev->stats.tx_errors;
+ stats->tx_dropped = ndev->stats.tx_dropped;
+}
+
+static const struct net_device_ops emac_netdev_ops = {
+ .ndo_open = emac_ndo_open,
+ .ndo_stop = emac_ndo_stop,
+ .ndo_start_xmit = emac_ndo_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_tx_timeout = emac_ndo_tx_timeout,
+ .ndo_set_rx_mode = emac_ndo_set_rx_mode,
+ .ndo_eth_ioctl = emac_ndo_ioctl,
+ .ndo_get_stats64 = emac_ndo_get_stats64,
+};
+
+/* get emac_port corresponding to eth_node name */
+static int prueth_node_port(struct device_node *eth_node)
+{
+ u32 port_id;
+ int ret;
+
+ ret = of_property_read_u32(eth_node, "reg", &port_id);
+ if (ret)
+ return ret;
+
+ if (port_id == 0)
+ return PRUETH_PORT_MII0;
+ else if (port_id == 1)
+ return PRUETH_PORT_MII1;
+ else
+ return PRUETH_PORT_INVALID;
+}
+
+/* get MAC instance corresponding to eth_node name */
+static int prueth_node_mac(struct device_node *eth_node)
+{
+ u32 port_id;
+ int ret;
+
+ ret = of_property_read_u32(eth_node, "reg", &port_id);
+ if (ret)
+ return ret;
+
+ if (port_id == 0)
+ return PRUETH_MAC0;
+ else if (port_id == 1)
+ return PRUETH_MAC1;
+ else
+ return PRUETH_MAC_INVALID;
+}
+
+static int prueth_netdev_init(struct prueth *prueth,
+ struct device_node *eth_node)
+{
+ int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES;
+ struct prueth_emac *emac;
+ struct net_device *ndev;
+ enum prueth_port port;
+ const char *irq_name;
+ enum prueth_mac mac;
+
+ port = prueth_node_port(eth_node);
+ if (port == PRUETH_PORT_INVALID)
+ return -EINVAL;
+
+ mac = prueth_node_mac(eth_node);
+ if (mac == PRUETH_MAC_INVALID)
+ return -EINVAL;
+
+ ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn);
+ if (!ndev)
+ return -ENOMEM;
+
+ emac = netdev_priv(ndev);
+ emac->prueth = prueth;
+ emac->ndev = ndev;
+ emac->port_id = port;
+ emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq");
+ if (!emac->cmd_wq) {
+ ret = -ENOMEM;
+ goto free_ndev;
+ }
+ INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work);
+
+ INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler);
+
+ ret = pruss_request_mem_region(prueth->pruss,
+ port == PRUETH_PORT_MII0 ?
+ PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,
+ &emac->dram);
+ if (ret) {
+ dev_err(prueth->dev, "unable to get DRAM: %d\n", ret);
+ ret = -ENOMEM;
+ goto free_wq;
+ }
+
+ emac->tx_ch_num = 1;
+
+ irq_name = "tx_ts0";
+ if (emac->port_id == PRUETH_PORT_MII1)
+ irq_name = "tx_ts1";
+ emac->tx_ts_irq = platform_get_irq_byname_optional(prueth->pdev, irq_name);
+ if (emac->tx_ts_irq < 0) {
+ ret = dev_err_probe(prueth->dev, emac->tx_ts_irq, "could not get tx_ts_irq\n");
+ goto free;
+ }
+
+ SET_NETDEV_DEV(ndev, prueth->dev);
+ spin_lock_init(&emac->lock);
+ mutex_init(&emac->cmd_lock);
+
+ emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0);
+ if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) {
+ dev_err(prueth->dev, "couldn't find phy-handle\n");
+ ret = -ENODEV;
+ goto free;
+ } else if (of_phy_is_fixed_link(eth_node)) {
+ ret = of_phy_register_fixed_link(eth_node);
+ if (ret) {
+ ret = dev_err_probe(prueth->dev, ret,
+ "failed to register fixed-link phy\n");
+ goto free;
+ }
+
+ emac->phy_node = eth_node;
+ }
+
+ ret = of_get_phy_mode(eth_node, &emac->phy_if);
+ if (ret) {
+ dev_err(prueth->dev, "could not get phy-mode property\n");
+ goto free;
+ }
+
+ if (emac->phy_if != PHY_INTERFACE_MODE_MII &&
+ !phy_interface_mode_is_rgmii(emac->phy_if)) {
+ dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if));
+ ret = -EINVAL;
+ goto free;
+ }
+
+ /* AM65 SR2.0 has TX Internal delay always enabled by hardware
+ * and it is not possible to disable TX Internal delay. The below
+ * switch case block describes how we handle different phy modes
+ * based on hardware restriction.
+ */
+ switch (emac->phy_if) {
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ emac->phy_if = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ dev_err(prueth->dev, "RGMII mode without TX delay is not supported");
+ ret = -EINVAL;
+ goto free;
+ default:
+ break;
+ }
+
+ /* get mac address from DT and set private and netdev addr */
+ ret = of_get_ethdev_address(eth_node, ndev);
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ eth_hw_addr_random(ndev);
+ dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
+ port, ndev->dev_addr);
+ }
+ ether_addr_copy(emac->mac_addr, ndev->dev_addr);
+
+ ndev->min_mtu = PRUETH_MIN_PKT_SIZE;
+ ndev->max_mtu = PRUETH_MAX_MTU;
+ ndev->netdev_ops = &emac_netdev_ops;
+ ndev->ethtool_ops = &icssg_ethtool_ops;
+ ndev->hw_features = NETIF_F_SG;
+ ndev->features = ndev->hw_features;
+
+ netif_napi_add(ndev, &emac->napi_rx, emac_napi_rx_poll);
+ prueth->emac[mac] = emac;
+
+ return 0;
+
+free:
+ pruss_release_mem_region(prueth->pruss, &emac->dram);
+free_wq:
+ destroy_workqueue(emac->cmd_wq);
+free_ndev:
+ emac->ndev = NULL;
+ prueth->emac[mac] = NULL;
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static void prueth_netdev_exit(struct prueth *prueth,
+ struct device_node *eth_node)
+{
+ struct prueth_emac *emac;
+ enum prueth_mac mac;
+
+ mac = prueth_node_mac(eth_node);
+ if (mac == PRUETH_MAC_INVALID)
+ return;
+
+ emac = prueth->emac[mac];
+ if (!emac)
+ return;
+
+ if (of_phy_is_fixed_link(emac->phy_node))
+ of_phy_deregister_fixed_link(emac->phy_node);
+
+ netif_napi_del(&emac->napi_rx);
+
+ pruss_release_mem_region(prueth->pruss, &emac->dram);
+ destroy_workqueue(emac->cmd_wq);
+ free_netdev(emac->ndev);
+ prueth->emac[mac] = NULL;
+}
+
+static int prueth_get_cores(struct prueth *prueth, int slice)
+{
+ struct device *dev = prueth->dev;
+ enum pruss_pru_id pruss_id;
+ struct device_node *np;
+ int idx = -1, ret;
+
+ np = dev->of_node;
+
+ switch (slice) {
+ case ICSS_SLICE0:
+ idx = 0;
+ break;
+ case ICSS_SLICE1:
+ idx = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ prueth->pru[slice] = pru_rproc_get(np, idx, &pruss_id);
+ if (IS_ERR(prueth->pru[slice])) {
+ ret = PTR_ERR(prueth->pru[slice]);
+ prueth->pru[slice] = NULL;
+ return dev_err_probe(dev, ret, "unable to get PRU%d\n", slice);
+ }
+ prueth->pru_id[slice] = pruss_id;
+
+ idx++;
+ prueth->rtu[slice] = pru_rproc_get(np, idx, NULL);
+ if (IS_ERR(prueth->rtu[slice])) {
+ ret = PTR_ERR(prueth->rtu[slice]);
+ prueth->rtu[slice] = NULL;
+ return dev_err_probe(dev, ret, "unable to get RTU%d\n", slice);
+ }
+
+ idx++;
+ prueth->txpru[slice] = pru_rproc_get(np, idx, NULL);
+ if (IS_ERR(prueth->txpru[slice])) {
+ ret = PTR_ERR(prueth->txpru[slice]);
+ prueth->txpru[slice] = NULL;
+ return dev_err_probe(dev, ret, "unable to get TX_PRU%d\n", slice);
+ }
+
+ return 0;
+}
+
+static void prueth_put_cores(struct prueth *prueth, int slice)
+{
+ if (prueth->txpru[slice])
+ pru_rproc_put(prueth->txpru[slice]);
+
+ if (prueth->rtu[slice])
+ pru_rproc_put(prueth->rtu[slice]);
+
+ if (prueth->pru[slice])
+ pru_rproc_put(prueth->pru[slice]);
+}
+
+static const struct of_device_id prueth_dt_match[];
+
+static int prueth_probe(struct platform_device *pdev)
+{
+ struct device_node *eth_node, *eth_ports_node;
+ struct device_node *eth0_node = NULL;
+ struct device_node *eth1_node = NULL;
+ struct genpool_data_align gp_data = {
+ .align = SZ_64K,
+ };
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct device_node *np;
+ struct prueth *prueth;
+ struct pruss *pruss;
+ u32 msmc_ram_size;
+ int i, ret;
+
+ np = dev->of_node;
+
+ match = of_match_device(prueth_dt_match, dev);
+ if (!match)
+ return -ENODEV;
+
+ prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);
+ if (!prueth)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, prueth);
+ prueth->pdev = pdev;
+ prueth->pdata = *(const struct prueth_pdata *)match->data;
+
+ prueth->dev = dev;
+ eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
+ if (!eth_ports_node)
+ return -ENOENT;
+
+ for_each_child_of_node(eth_ports_node, eth_node) {
+ u32 reg;
+
+ if (strcmp(eth_node->name, "port"))
+ continue;
+ ret = of_property_read_u32(eth_node, "reg", &reg);
+ if (ret < 0) {
+ dev_err(dev, "%pOF error reading port_id %d\n",
+ eth_node, ret);
+ }
+
+ of_node_get(eth_node);
+
+ if (reg == 0) {
+ eth0_node = eth_node;
+ if (!of_device_is_available(eth0_node)) {
+ of_node_put(eth0_node);
+ eth0_node = NULL;
+ }
+ } else if (reg == 1) {
+ eth1_node = eth_node;
+ if (!of_device_is_available(eth1_node)) {
+ of_node_put(eth1_node);
+ eth1_node = NULL;
+ }
+ } else {
+ dev_err(dev, "port reg should be 0 or 1\n");
+ }
+ }
+
+ of_node_put(eth_ports_node);
+
+ /* At least one node must be present and available else we fail */
+ if (!eth0_node && !eth1_node) {
+ dev_err(dev, "neither port0 nor port1 node available\n");
+ return -ENODEV;
+ }
+
+ if (eth0_node == eth1_node) {
+ dev_err(dev, "port0 and port1 can't have same reg\n");
+ of_node_put(eth0_node);
+ return -ENODEV;
+ }
+
+ prueth->eth_node[PRUETH_MAC0] = eth0_node;
+ prueth->eth_node[PRUETH_MAC1] = eth1_node;
+
+ prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt");
+ if (IS_ERR(prueth->miig_rt)) {
+ dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n");
+ return -ENODEV;
+ }
+
+ prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");
+ if (IS_ERR(prueth->mii_rt)) {
+ dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n");
+ return -ENODEV;
+ }
+
+ if (eth0_node) {
+ ret = prueth_get_cores(prueth, ICSS_SLICE0);
+ if (ret)
+ goto put_cores;
+ }
+
+ if (eth1_node) {
+ ret = prueth_get_cores(prueth, ICSS_SLICE1);
+ if (ret)
+ goto put_cores;
+ }
+
+ pruss = pruss_get(eth0_node ?
+ prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]);
+ if (IS_ERR(pruss)) {
+ ret = PTR_ERR(pruss);
+ dev_err(dev, "unable to get pruss handle\n");
+ goto put_cores;
+ }
+
+ prueth->pruss = pruss;
+
+ ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2,
+ &prueth->shram);
+ if (ret) {
+ dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret);
+ pruss_put(prueth->pruss);
+ }
+
+ prueth->sram_pool = of_gen_pool_get(np, "sram", 0);
+ if (!prueth->sram_pool) {
+ dev_err(dev, "unable to get SRAM pool\n");
+ ret = -ENODEV;
+
+ goto put_mem;
+ }
+
+ msmc_ram_size = MSMC_RAM_SIZE;
+
+ /* NOTE: FW bug needs buffer base to be 64KB aligned */
+ prueth->msmcram.va =
+ (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool,
+ msmc_ram_size,
+ gen_pool_first_fit_align,
+ &gp_data);
+
+ if (!prueth->msmcram.va) {
+ ret = -ENOMEM;
+ dev_err(dev, "unable to allocate MSMC resource\n");
+ goto put_mem;
+ }
+ prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool,
+ (unsigned long)prueth->msmcram.va);
+ prueth->msmcram.size = msmc_ram_size;
+ memset_io(prueth->msmcram.va, 0, msmc_ram_size);
+ dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa,
+ prueth->msmcram.va, prueth->msmcram.size);
+
+ prueth->iep0 = icss_iep_get_idx(np, 0);
+ if (IS_ERR(prueth->iep0)) {
+ ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n");
+ prueth->iep0 = NULL;
+ goto free_pool;
+ }
+
+ prueth->iep1 = icss_iep_get_idx(np, 1);
+ if (IS_ERR(prueth->iep1)) {
+ ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n");
+ icss_iep_put(prueth->iep0);
+ prueth->iep0 = NULL;
+ prueth->iep1 = NULL;
+ goto free_pool;
+ }
+
+ if (prueth->pdata.quirk_10m_link_issue) {
+ /* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX
+ * traffic.
+ */
+ icss_iep_init_fw(prueth->iep1);
+ }
+
+ /* setup netdev interfaces */
+ if (eth0_node) {
+ ret = prueth_netdev_init(prueth, eth0_node);
+ if (ret) {
+ dev_err_probe(dev, ret, "netdev init %s failed\n",
+ eth0_node->name);
+ goto exit_iep;
+ }
+ prueth->emac[PRUETH_MAC0]->iep = prueth->iep0;
+ }
+
+ if (eth1_node) {
+ ret = prueth_netdev_init(prueth, eth1_node);
+ if (ret) {
+ dev_err_probe(dev, ret, "netdev init %s failed\n",
+ eth1_node->name);
+ goto netdev_exit;
+ }
+
+ prueth->emac[PRUETH_MAC1]->iep = prueth->iep0;
+ }
+
+ /* register the network devices */
+ if (eth0_node) {
+ ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);
+ if (ret) {
+ dev_err(dev, "can't register netdev for port MII0");
+ goto netdev_exit;
+ }
+
+ prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev;
+
+ emac_phy_connect(prueth->emac[PRUETH_MAC0]);
+ phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev);
+ }
+
+ if (eth1_node) {
+ ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);
+ if (ret) {
+ dev_err(dev, "can't register netdev for port MII1");
+ goto netdev_unregister;
+ }
+
+ prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev;
+ emac_phy_connect(prueth->emac[PRUETH_MAC1]);
+ phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);
+ }
+
+ dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
+ (!eth0_node || !eth1_node) ? "single" : "dual");
+
+ if (eth1_node)
+ of_node_put(eth1_node);
+ if (eth0_node)
+ of_node_put(eth0_node);
+ return 0;
+
+netdev_unregister:
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ if (!prueth->registered_netdevs[i])
+ continue;
+ if (prueth->emac[i]->ndev->phydev) {
+ phy_disconnect(prueth->emac[i]->ndev->phydev);
+ prueth->emac[i]->ndev->phydev = NULL;
+ }
+ unregister_netdev(prueth->registered_netdevs[i]);
+ }
+
+netdev_exit:
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ eth_node = prueth->eth_node[i];
+ if (!eth_node)
+ continue;
+
+ prueth_netdev_exit(prueth, eth_node);
+ }
+
+exit_iep:
+ if (prueth->pdata.quirk_10m_link_issue)
+ icss_iep_exit_fw(prueth->iep1);
+
+free_pool:
+ gen_pool_free(prueth->sram_pool,
+ (unsigned long)prueth->msmcram.va, msmc_ram_size);
+
+put_mem:
+ pruss_release_mem_region(prueth->pruss, &prueth->shram);
+ pruss_put(prueth->pruss);
+
+put_cores:
+ if (eth1_node) {
+ prueth_put_cores(prueth, ICSS_SLICE1);
+ of_node_put(eth1_node);
+ }
+
+ if (eth0_node) {
+ prueth_put_cores(prueth, ICSS_SLICE0);
+ of_node_put(eth0_node);
+ }
+
+ return ret;
+}
+
+static void prueth_remove(struct platform_device *pdev)
+{
+ struct prueth *prueth = platform_get_drvdata(pdev);
+ struct device_node *eth_node;
+ int i;
+
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ if (!prueth->registered_netdevs[i])
+ continue;
+ phy_stop(prueth->emac[i]->ndev->phydev);
+ phy_disconnect(prueth->emac[i]->ndev->phydev);
+ prueth->emac[i]->ndev->phydev = NULL;
+ unregister_netdev(prueth->registered_netdevs[i]);
+ }
+
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ eth_node = prueth->eth_node[i];
+ if (!eth_node)
+ continue;
+
+ prueth_netdev_exit(prueth, eth_node);
+ }
+
+ if (prueth->pdata.quirk_10m_link_issue)
+ icss_iep_exit_fw(prueth->iep1);
+
+ icss_iep_put(prueth->iep1);
+ icss_iep_put(prueth->iep0);
+
+ gen_pool_free(prueth->sram_pool,
+ (unsigned long)prueth->msmcram.va,
+ MSMC_RAM_SIZE);
+
+ pruss_release_mem_region(prueth->pruss, &prueth->shram);
+
+ pruss_put(prueth->pruss);
+
+ if (prueth->eth_node[PRUETH_MAC1])
+ prueth_put_cores(prueth, ICSS_SLICE1);
+
+ if (prueth->eth_node[PRUETH_MAC0])
+ prueth_put_cores(prueth, ICSS_SLICE0);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int prueth_suspend(struct device *dev)
+{
+ struct prueth *prueth = dev_get_drvdata(dev);
+ struct net_device *ndev;
+ int i, ret;
+
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ ndev = prueth->registered_netdevs[i];
+
+ if (!ndev)
+ continue;
+
+ if (netif_running(ndev)) {
+ netif_device_detach(ndev);
+ ret = emac_ndo_stop(ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "failed to stop: %d", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int prueth_resume(struct device *dev)
+{
+ struct prueth *prueth = dev_get_drvdata(dev);
+ struct net_device *ndev;
+ int i, ret;
+
+ for (i = 0; i < PRUETH_NUM_MACS; i++) {
+ ndev = prueth->registered_netdevs[i];
+
+ if (!ndev)
+ continue;
+
+ if (netif_running(ndev)) {
+ ret = emac_ndo_open(ndev);
+ if (ret < 0) {
+ netdev_err(ndev, "failed to start: %d", ret);
+ return ret;
+ }
+ netif_device_attach(ndev);
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops prueth_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume)
+};
+
+static const struct prueth_pdata am654_icssg_pdata = {
+ .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
+ .quirk_10m_link_issue = 1,
+};
+
+static const struct of_device_id prueth_dt_match[] = {
+ { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, prueth_dt_match);
+
+static struct platform_driver prueth_driver = {
+ .probe = prueth_probe,
+ .remove_new = prueth_remove,
+ .driver = {
+ .name = "icssg-prueth",
+ .of_match_table = prueth_dt_match,
+ .pm = &prueth_dev_pm_ops,
+ },
+};
+module_platform_driver(prueth_driver);
+
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
+MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");
+MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
new file mode 100644
index 000000000000..3fe80a8758d3
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -0,0 +1,286 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_PRUETH_H
+#define __NET_TI_ICSSG_PRUETH_H
+
+#include <linux/etherdevice.h>
+#include <linux/genalloc.h>
+#include <linux/if_vlan.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/net_tstamp.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/remoteproc/pruss.h>
+#include <linux/pruss_driver.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/remoteproc.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/dma/ti-cppi5.h>
+#include <linux/dma/k3-udma-glue.h>
+
+#include <net/devlink.h>
+
+#include "icssg_config.h"
+#include "icss_iep.h"
+#include "icssg_switch_map.h"
+
+#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN)
+#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN)
+#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN)
+
+#define ICSS_SLICE0 0
+#define ICSS_SLICE1 1
+
+#define ICSS_FW_PRU 0
+#define ICSS_FW_RTU 1
+
+#define ICSSG_MAX_RFLOWS 8 /* per slice */
+
+/* Number of ICSSG related stats */
+#define ICSSG_NUM_STATS 60
+#define ICSSG_NUM_STANDARD_STATS 31
+#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
+
+/* Firmware status codes */
+#define ICSS_HS_FW_READY 0x55555555
+#define ICSS_HS_FW_DEAD 0xDEAD0000 /* lower 16 bits contain error code */
+
+/* Firmware command codes */
+#define ICSS_HS_CMD_BUSY 0x40000000
+#define ICSS_HS_CMD_DONE 0x80000000
+#define ICSS_HS_CMD_CANCEL 0x10000000
+
+/* Firmware commands */
+#define ICSS_CMD_SPAD 0x20
+#define ICSS_CMD_RXTX 0x10
+#define ICSS_CMD_ADD_FDB 0x1
+#define ICSS_CMD_DEL_FDB 0x2
+#define ICSS_CMD_SET_RUN 0x4
+#define ICSS_CMD_GET_FDB_SLOT 0x5
+#define ICSS_CMD_ENABLE_VLAN 0x5
+#define ICSS_CMD_DISABLE_VLAN 0x6
+#define ICSS_CMD_ADD_FILTER 0x7
+#define ICSS_CMD_ADD_MAC 0x8
+
+/* In switch mode there are 3 real ports i.e. 3 mac addrs.
+ * however Linux sees only the host side port. The other 2 ports
+ * are the switch ports.
+ * In emac mode there are 2 real ports i.e. 2 mac addrs.
+ * Linux sees both the ports.
+ */
+enum prueth_port {
+ PRUETH_PORT_HOST = 0, /* host side port */
+ PRUETH_PORT_MII0, /* physical port RG/SG MII 0 */
+ PRUETH_PORT_MII1, /* physical port RG/SG MII 1 */
+ PRUETH_PORT_INVALID, /* Invalid prueth port */
+};
+
+enum prueth_mac {
+ PRUETH_MAC0 = 0,
+ PRUETH_MAC1,
+ PRUETH_NUM_MACS,
+ PRUETH_MAC_INVALID,
+};
+
+struct prueth_tx_chn {
+ struct device *dma_dev;
+ struct napi_struct napi_tx;
+ struct k3_cppi_desc_pool *desc_pool;
+ struct k3_udma_glue_tx_channel *tx_chn;
+ struct prueth_emac *emac;
+ u32 id;
+ u32 descs_num;
+ unsigned int irq;
+ char name[32];
+};
+
+struct prueth_rx_chn {
+ struct device *dev;
+ struct device *dma_dev;
+ struct k3_cppi_desc_pool *desc_pool;
+ struct k3_udma_glue_rx_channel *rx_chn;
+ u32 descs_num;
+ unsigned int irq[ICSSG_MAX_RFLOWS]; /* separate irq per flow */
+ char name[32];
+};
+
+/* There are 4 Tx DMA channels, but the highest priority is CH3 (thread 3)
+ * and lower three are lower priority channels or threads.
+ */
+#define PRUETH_MAX_TX_QUEUES 4
+
+#define PRUETH_MAX_TX_TS_REQUESTS 50 /* Max simultaneous TX_TS requests */
+
+/* data for each emac port */
+struct prueth_emac {
+ bool fw_running;
+ struct prueth *prueth;
+ struct net_device *ndev;
+ u8 mac_addr[6];
+ struct napi_struct napi_rx;
+ u32 msg_enable;
+
+ int link;
+ int speed;
+ int duplex;
+
+ const char *phy_id;
+ struct device_node *phy_node;
+ phy_interface_t phy_if;
+ enum prueth_port port_id;
+ struct icss_iep *iep;
+ unsigned int rx_ts_enabled : 1;
+ unsigned int tx_ts_enabled : 1;
+
+ /* DMA related */
+ struct prueth_tx_chn tx_chns[PRUETH_MAX_TX_QUEUES];
+ struct completion tdown_complete;
+ atomic_t tdown_cnt;
+ struct prueth_rx_chn rx_chns;
+ int rx_flow_id_base;
+ int tx_ch_num;
+
+ spinlock_t lock; /* serialize access */
+
+ /* TX HW Timestamping */
+ /* TX TS cookie will be index to the tx_ts_skb array */
+ struct sk_buff *tx_ts_skb[PRUETH_MAX_TX_TS_REQUESTS];
+ atomic_t tx_ts_pending;
+ int tx_ts_irq;
+
+ u8 cmd_seq;
+ /* shutdown related */
+ u32 cmd_data[4];
+ struct completion cmd_complete;
+ /* Mutex to serialize access to firmware command interface */
+ struct mutex cmd_lock;
+ struct work_struct rx_mode_work;
+ struct workqueue_struct *cmd_wq;
+
+ struct pruss_mem_region dram;
+
+ struct delayed_work stats_work;
+ u64 stats[ICSSG_NUM_STATS];
+};
+
+/**
+ * struct prueth_pdata - PRUeth platform data
+ * @fdqring_mode: Free desc queue mode
+ * @quirk_10m_link_issue: 10M link detect errata
+ */
+struct prueth_pdata {
+ enum k3_ring_mode fdqring_mode;
+ u32 quirk_10m_link_issue:1;
+};
+
+/**
+ * struct prueth - PRUeth structure
+ * @dev: device
+ * @pruss: pruss handle
+ * @pru: rproc instances of PRUs
+ * @rtu: rproc instances of RTUs
+ * @txpru: rproc instances of TX_PRUs
+ * @shram: PRUSS shared RAM region
+ * @sram_pool: MSMC RAM pool for buffers
+ * @msmcram: MSMC RAM region
+ * @eth_node: DT node for the port
+ * @emac: private EMAC data structure
+ * @registered_netdevs: list of registered netdevs
+ * @miig_rt: regmap to mii_g_rt block
+ * @mii_rt: regmap to mii_rt block
+ * @pru_id: ID for each of the PRUs
+ * @pdev: pointer to ICSSG platform device
+ * @pdata: pointer to platform data for ICSSG driver
+ * @icssg_hwcmdseq: seq counter or HWQ messages
+ * @emacs_initialized: num of EMACs/ext ports that are up/running
+ * @iep0: pointer to IEP0 device
+ * @iep1: pointer to IEP1 device
+ */
+struct prueth {
+ struct device *dev;
+ struct pruss *pruss;
+ struct rproc *pru[PRUSS_NUM_PRUS];
+ struct rproc *rtu[PRUSS_NUM_PRUS];
+ struct rproc *txpru[PRUSS_NUM_PRUS];
+ struct pruss_mem_region shram;
+ struct gen_pool *sram_pool;
+ struct pruss_mem_region msmcram;
+
+ struct device_node *eth_node[PRUETH_NUM_MACS];
+ struct prueth_emac *emac[PRUETH_NUM_MACS];
+ struct net_device *registered_netdevs[PRUETH_NUM_MACS];
+ struct regmap *miig_rt;
+ struct regmap *mii_rt;
+
+ enum pruss_pru_id pru_id[PRUSS_NUM_PRUS];
+ struct platform_device *pdev;
+ struct prueth_pdata pdata;
+ u8 icssg_hwcmdseq;
+ int emacs_initialized;
+ struct icss_iep *iep0;
+ struct icss_iep *iep1;
+};
+
+struct emac_tx_ts_response {
+ u32 reserved[2];
+ u32 cookie;
+ u32 lo_ts;
+ u32 hi_ts;
+};
+
+/* get PRUSS SLICE number from prueth_emac */
+static inline int prueth_emac_slice(struct prueth_emac *emac)
+{
+ switch (emac->port_id) {
+ case PRUETH_PORT_MII0:
+ return ICSS_SLICE0;
+ case PRUETH_PORT_MII1:
+ return ICSS_SLICE1;
+ default:
+ return -EINVAL;
+ }
+}
+
+extern const struct ethtool_ops icssg_ethtool_ops;
+
+/* 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);
+void icssg_class_disable(struct regmap *miig_rt, int slice);
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti);
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr);
+
+/* config helpers */
+void icssg_config_ipg(struct prueth_emac *emac);
+int icssg_config(struct prueth *prueth, struct prueth_emac *emac,
+ int slice);
+int emac_set_port_state(struct prueth_emac *emac,
+ enum icssg_port_state_cmd state);
+void icssg_config_set_speed(struct prueth_emac *emac);
+
+/* Buffer queue helpers */
+int icssg_queue_pop(struct prueth *prueth, u8 queue);
+void icssg_queue_push(struct prueth *prueth, int queue, u16 addr);
+u32 icssg_queue_level(struct prueth *prueth, int queue);
+
+#define prueth_napi_to_tx_chn(pnapi) \
+ container_of(pnapi, struct prueth_tx_chn, napi_tx)
+
+void emac_stats_work_handler(struct work_struct *work);
+void emac_update_hardware_stats(struct prueth_emac *emac);
+int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);
+#endif /* __NET_TI_ICSSG_PRUETH_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_queues.c b/drivers/net/ethernet/ti/icssg/icssg_queues.c
new file mode 100644
index 000000000000..3c34f61ad40b
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_queues.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Buffer queue helpers
+ *
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/regmap.h>
+#include "icssg_prueth.h"
+
+#define ICSSG_QUEUES_MAX 64
+#define ICSSG_QUEUE_OFFSET 0xd00
+#define ICSSG_QUEUE_PEEK_OFFSET 0xe00
+#define ICSSG_QUEUE_CNT_OFFSET 0xe40
+#define ICSSG_QUEUE_RESET_OFFSET 0xf40
+
+int icssg_queue_pop(struct prueth *prueth, u8 queue)
+{
+ u32 val, cnt;
+
+ if (queue >= ICSSG_QUEUES_MAX)
+ return -EINVAL;
+
+ regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, &cnt);
+ if (!cnt)
+ return -EINVAL;
+
+ regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val);
+
+ return val;
+}
+
+void icssg_queue_push(struct prueth *prueth, int queue, u16 addr)
+{
+ if (queue >= ICSSG_QUEUES_MAX)
+ return;
+
+ regmap_write(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, addr);
+}
+
+u32 icssg_queue_level(struct prueth *prueth, int queue)
+{
+ u32 reg;
+
+ if (queue >= ICSSG_QUEUES_MAX)
+ return 0;
+
+ regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, &reg);
+
+ return reg;
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
new file mode 100644
index 000000000000..bb0b33927e3b
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2021 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include "icssg_prueth.h"
+#include "icssg_stats.h"
+#include <linux/regmap.h>
+
+static u32 stats_base[] = { 0x54c, /* Slice 0 stats start */
+ 0xb18, /* Slice 1 stats start */
+};
+
+void emac_update_hardware_stats(struct prueth_emac *emac)
+{
+ struct prueth *prueth = emac->prueth;
+ int slice = prueth_emac_slice(emac);
+ u32 base = stats_base[slice];
+ u32 val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
+ regmap_read(prueth->miig_rt,
+ base + icssg_all_stats[i].offset,
+ &val);
+ regmap_write(prueth->miig_rt,
+ base + icssg_all_stats[i].offset,
+ val);
+
+ emac->stats[i] += val;
+ }
+}
+
+void emac_stats_work_handler(struct work_struct *work)
+{
+ struct prueth_emac *emac = container_of(work, struct prueth_emac,
+ stats_work.work);
+ emac_update_hardware_stats(emac);
+
+ queue_delayed_work(system_long_wq, &emac->stats_work,
+ msecs_to_jiffies((STATS_TIME_LIMIT_1G_MS * 1000) / emac->speed));
+}
+
+int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
+ if (!strcmp(icssg_all_stats[i].name, stat_name))
+ return emac->stats[icssg_all_stats[i].offset / sizeof(u32)];
+ }
+
+ netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
+ return -EINVAL;
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
new file mode 100644
index 000000000000..999a4a91276c
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_STATS_H
+#define __NET_TI_ICSSG_STATS_H
+
+#include "icssg_prueth.h"
+
+#define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */
+
+struct miig_stats_regs {
+ /* Rx */
+ u32 rx_packets;
+ u32 rx_broadcast_frames;
+ u32 rx_multicast_frames;
+ u32 rx_crc_errors;
+ u32 rx_mii_error_frames;
+ u32 rx_odd_nibble_frames;
+ u32 rx_frame_max_size;
+ u32 rx_max_size_error_frames;
+ u32 rx_frame_min_size;
+ u32 rx_min_size_error_frames;
+ u32 rx_over_errors;
+ u32 rx_class0_hits;
+ u32 rx_class1_hits;
+ u32 rx_class2_hits;
+ u32 rx_class3_hits;
+ u32 rx_class4_hits;
+ u32 rx_class5_hits;
+ u32 rx_class6_hits;
+ u32 rx_class7_hits;
+ u32 rx_class8_hits;
+ u32 rx_class9_hits;
+ u32 rx_class10_hits;
+ u32 rx_class11_hits;
+ u32 rx_class12_hits;
+ u32 rx_class13_hits;
+ u32 rx_class14_hits;
+ u32 rx_class15_hits;
+ u32 rx_smd_frags;
+ u32 rx_bucket1_size;
+ u32 rx_bucket2_size;
+ u32 rx_bucket3_size;
+ u32 rx_bucket4_size;
+ u32 rx_64B_frames;
+ u32 rx_bucket1_frames;
+ u32 rx_bucket2_frames;
+ u32 rx_bucket3_frames;
+ u32 rx_bucket4_frames;
+ u32 rx_bucket5_frames;
+ u32 rx_bytes;
+ u32 rx_tx_total_bytes;
+ /* Tx */
+ u32 tx_packets;
+ u32 tx_broadcast_frames;
+ u32 tx_multicast_frames;
+ u32 tx_odd_nibble_frames;
+ u32 tx_underflow_errors;
+ u32 tx_frame_max_size;
+ u32 tx_max_size_error_frames;
+ u32 tx_frame_min_size;
+ u32 tx_min_size_error_frames;
+ u32 tx_bucket1_size;
+ u32 tx_bucket2_size;
+ u32 tx_bucket3_size;
+ u32 tx_bucket4_size;
+ u32 tx_64B_frames;
+ u32 tx_bucket1_frames;
+ u32 tx_bucket2_frames;
+ u32 tx_bucket3_frames;
+ u32 tx_bucket4_frames;
+ u32 tx_bucket5_frames;
+ u32 tx_bytes;
+};
+
+#define ICSSG_STATS(field, stats_type) \
+{ \
+ #field, \
+ offsetof(struct miig_stats_regs, field), \
+ stats_type \
+}
+
+struct icssg_stats {
+ char name[ETH_GSTRING_LEN];
+ u32 offset;
+ bool standard_stats;
+};
+
+static const struct icssg_stats icssg_all_stats[] = {
+ /* Rx */
+ ICSSG_STATS(rx_packets, true),
+ ICSSG_STATS(rx_broadcast_frames, false),
+ ICSSG_STATS(rx_multicast_frames, true),
+ ICSSG_STATS(rx_crc_errors, true),
+ ICSSG_STATS(rx_mii_error_frames, false),
+ ICSSG_STATS(rx_odd_nibble_frames, false),
+ ICSSG_STATS(rx_frame_max_size, true),
+ ICSSG_STATS(rx_max_size_error_frames, false),
+ ICSSG_STATS(rx_frame_min_size, true),
+ ICSSG_STATS(rx_min_size_error_frames, false),
+ ICSSG_STATS(rx_over_errors, true),
+ ICSSG_STATS(rx_class0_hits, false),
+ ICSSG_STATS(rx_class1_hits, false),
+ ICSSG_STATS(rx_class2_hits, false),
+ ICSSG_STATS(rx_class3_hits, false),
+ ICSSG_STATS(rx_class4_hits, false),
+ ICSSG_STATS(rx_class5_hits, false),
+ ICSSG_STATS(rx_class6_hits, false),
+ ICSSG_STATS(rx_class7_hits, false),
+ ICSSG_STATS(rx_class8_hits, false),
+ ICSSG_STATS(rx_class9_hits, false),
+ ICSSG_STATS(rx_class10_hits, false),
+ ICSSG_STATS(rx_class11_hits, false),
+ ICSSG_STATS(rx_class12_hits, false),
+ ICSSG_STATS(rx_class13_hits, false),
+ ICSSG_STATS(rx_class14_hits, false),
+ ICSSG_STATS(rx_class15_hits, false),
+ ICSSG_STATS(rx_smd_frags, false),
+ ICSSG_STATS(rx_bucket1_size, true),
+ ICSSG_STATS(rx_bucket2_size, true),
+ ICSSG_STATS(rx_bucket3_size, true),
+ ICSSG_STATS(rx_bucket4_size, true),
+ ICSSG_STATS(rx_64B_frames, true),
+ ICSSG_STATS(rx_bucket1_frames, true),
+ ICSSG_STATS(rx_bucket2_frames, true),
+ ICSSG_STATS(rx_bucket3_frames, true),
+ ICSSG_STATS(rx_bucket4_frames, true),
+ ICSSG_STATS(rx_bucket5_frames, true),
+ ICSSG_STATS(rx_bytes, true),
+ ICSSG_STATS(rx_tx_total_bytes, false),
+ /* Tx */
+ ICSSG_STATS(tx_packets, true),
+ ICSSG_STATS(tx_broadcast_frames, false),
+ ICSSG_STATS(tx_multicast_frames, false),
+ ICSSG_STATS(tx_odd_nibble_frames, false),
+ ICSSG_STATS(tx_underflow_errors, false),
+ ICSSG_STATS(tx_frame_max_size, true),
+ ICSSG_STATS(tx_max_size_error_frames, false),
+ ICSSG_STATS(tx_frame_min_size, true),
+ ICSSG_STATS(tx_min_size_error_frames, false),
+ ICSSG_STATS(tx_bucket1_size, true),
+ ICSSG_STATS(tx_bucket2_size, true),
+ ICSSG_STATS(tx_bucket3_size, true),
+ ICSSG_STATS(tx_bucket4_size, true),
+ ICSSG_STATS(tx_64B_frames, true),
+ ICSSG_STATS(tx_bucket1_frames, true),
+ ICSSG_STATS(tx_bucket2_frames, true),
+ ICSSG_STATS(tx_bucket3_frames, true),
+ ICSSG_STATS(tx_bucket4_frames, true),
+ ICSSG_STATS(tx_bucket5_frames, true),
+ ICSSG_STATS(tx_bytes, true),
+};
+
+#endif /* __NET_TI_ICSSG_STATS_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
new file mode 100644
index 000000000000..424a7e945ea8
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_SWITCH_MAP_H
+#define __NET_TI_ICSSG_SWITCH_MAP_H
+
+/************************* Ethernet Switch Constants *********************/
+
+/* if bucket size is changed in firmware then this too should be changed
+ * because it directly impacts FDB ageing calculation
+ */
+#define NUMBER_OF_FDB_BUCKET_ENTRIES (4)
+
+/* This is fixed in ICSSG */
+#define SIZE_OF_FDB (2048)
+
+#define FW_LINK_SPEED_1G (0x00)
+#define FW_LINK_SPEED_100M (0x01)
+#define FW_LINK_SPEED_10M (0x02)
+#define FW_LINK_SPEED_HD (0x80)
+
+/* Time after which FDB entries are checked for aged out values.
+ * Values are in nanoseconds
+ */
+#define FDB_AGEING_TIMEOUT_OFFSET 0x0014
+
+/* Default VLAN tag for Host Port */
+#define HOST_PORT_DF_VLAN_OFFSET 0x001C
+
+/* Same as HOST_PORT_DF_VLAN_OFFSET */
+#define EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET HOST_PORT_DF_VLAN_OFFSET
+
+/* Default VLAN tag for P1 Port */
+#define P1_PORT_DF_VLAN_OFFSET 0x0020
+
+/* Same as P1_PORT_DF_VLAN_OFFSET */
+#define EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET P1_PORT_DF_VLAN_OFFSET
+
+/* default VLAN tag for P2 Port */
+#define P2_PORT_DF_VLAN_OFFSET 0x0024
+
+/* Same as P2_PORT_DF_VLAN_OFFSET */
+#define EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET P2_PORT_DF_VLAN_OFFSET
+
+/* VLAN-FID Table offset. 4096 VIDs. 2B per VID = 8KB = 0x2000 */
+#define VLAN_STATIC_REG_TABLE_OFFSET 0x0100
+
+/* VLAN-FID Table offset for EMAC */
+#define EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET VLAN_STATIC_REG_TABLE_OFFSET
+
+/* Packet descriptor Q reserved memory */
+#define PORT_DESC0_HI 0x2104
+
+/* Packet descriptor Q reserved memory */
+#define PORT_DESC0_LO 0x2F6C
+
+/* Packet descriptor Q reserved memory */
+#define PORT_DESC1_HI 0x3DD4
+
+/* Packet descriptor Q reserved memory */
+#define PORT_DESC1_LO 0x4C3C
+
+/* Packet descriptor Q reserved memory */
+#define HOST_DESC0_HI 0x5AA4
+
+/* Packet descriptor Q reserved memory */
+#define HOST_DESC0_LO 0x5F0C
+
+/* Packet descriptor Q reserved memory */
+#define HOST_DESC1_HI 0x6374
+
+/* Packet descriptor Q reserved memory */
+#define HOST_DESC1_LO 0x67DC
+
+/* Special packet descriptor Q reserved memory */
+#define HOST_SPPD0 0x7AAC
+
+/* Special acket descriptor Q reserved memory */
+#define HOST_SPPD1 0x7EAC
+
+/* IEP count cycle counter*/
+#define TIMESYNC_FW_WC_CYCLECOUNT_OFFSET 0x83EC
+
+/* IEP count hi roll over count */
+#define TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET 0x83F4
+
+/* IEP count hi sw counter */
+#define TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET 0x83F8
+
+/* Set clock descriptor */
+#define TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET 0x83FC
+
+/* IEP count syncout reduction factor */
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET 0x843C
+
+/* IEP count syncout reduction counter */
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_COUNT_OFFSET 0x8440
+
+/* IEP count syncout start time cycle counter */
+#define TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET 0x8444
+
+/* Control variable to generate SYNC1 */
+#define TIMESYNC_FW_WC_ISOM_PIN_SIGNAL_EN_OFFSET 0x844C
+
+/* SystemTime Sync0 periodicity */
+#define TIMESYNC_FW_ST_SYNCOUT_PERIOD_OFFSET 0x8450
+
+/* pktTxDelay for P1 = link speed dependent p1 mac delay + p1 phy delay */
+#define TIMESYNC_FW_WC_PKTTXDELAY_P1_OFFSET 0x8454
+
+/* pktTxDelay for P2 = link speed dependent p2 mac delay + p2 phy delay */
+#define TIMESYNC_FW_WC_PKTTXDELAY_P2_OFFSET 0x8458
+
+/* Set clock operation done signal for next task */
+#define TIMESYNC_FW_SIG_PNFW_OFFSET 0x845C
+
+/* Set clock operation done signal for next task */
+#define TIMESYNC_FW_SIG_TIMESYNCFW_OFFSET 0x8460
+
+/* New list is copied at this time */
+#define TAS_CONFIG_CHANGE_TIME 0x000C
+
+/* config change error counter */
+#define TAS_CONFIG_CHANGE_ERROR_COUNTER 0x0014
+
+/* TAS List update pending flag */
+#define TAS_CONFIG_PENDING 0x0018
+
+/* TAS list update trigger flag */
+#define TAS_CONFIG_CHANGE 0x0019
+
+/* List length for new TAS schedule */
+#define TAS_ADMIN_LIST_LENGTH 0x001A
+
+/* Currently active TAS list index */
+#define TAS_ACTIVE_LIST_INDEX 0x001B
+
+/* Cycle time for the new TAS schedule */
+#define TAS_ADMIN_CYCLE_TIME 0x001C
+
+/* Cycle counts remaining till the TAS list update */
+#define TAS_CONFIG_CHANGE_CYCLE_COUNT 0x0020
+
+/* Base Flow ID for sending Packets to Host for Slice0 */
+#define PSI_L_REGULAR_FLOW_ID_BASE_OFFSET 0x0024
+
+/* Same as PSI_L_REGULAR_FLOW_ID_BASE_OFFSET */
+#define EMAC_ICSSG_SWITCH_PSI_L_REGULAR_FLOW_ID_BASE_OFFSET PSI_L_REGULAR_FLOW_ID_BASE_OFFSET
+
+/* Base Flow ID for sending mgmt and Tx TS to Host for Slice0 */
+#define PSI_L_MGMT_FLOW_ID_OFFSET 0x0026
+
+/* Same as PSI_L_MGMT_FLOW_ID_OFFSET */
+#define EMAC_ICSSG_SWITCH_PSI_L_MGMT_FLOW_ID_BASE_OFFSET PSI_L_MGMT_FLOW_ID_OFFSET
+
+/* Queue number for Special Packets written here */
+#define SPL_PKT_DEFAULT_PRIORITY 0x0028
+
+/* Express Preemptible Queue Mask */
+#define EXPRESS_PRE_EMPTIVE_Q_MASK 0x0029
+
+/* Port1/Port2 Default Queue number for untagged Packets, only 1B is used */
+#define QUEUE_NUM_UNTAGGED 0x002A
+
+/* Stores the table used for priority regeneration. 1B per PCP/Queue */
+#define PORT_Q_PRIORITY_REGEN_OFFSET 0x002C
+
+/* For marking Packet as priority/express (this feature is disabled) or
+ * cut-through/S&F.
+ */
+#define EXPRESS_PRE_EMPTIVE_Q_MAP 0x0034
+
+/* Stores the table used for priority mapping. 1B per PCP/Queue */
+#define PORT_Q_PRIORITY_MAPPING_OFFSET 0x003C
+
+/* Used to notify the FW of the current link speed */
+#define PORT_LINK_SPEED_OFFSET 0x00A8
+
+/* TAS gate mask for windows list0 */
+#define TAS_GATE_MASK_LIST0 0x0100
+
+/* TAS gate mask for windows list1 */
+#define TAS_GATE_MASK_LIST1 0x0350
+
+/* Memory to Enable/Disable Preemption on TX side */
+#define PRE_EMPTION_ENABLE_TX 0x05A0
+
+/* Active State of Preemption on TX side */
+#define PRE_EMPTION_ACTIVE_TX 0x05A1
+
+/* Memory to Enable/Disable Verify State Machine Preemption */
+#define PRE_EMPTION_ENABLE_VERIFY 0x05A2
+
+/* Verify Status of State Machine */
+#define PRE_EMPTION_VERIFY_STATUS 0x05A3
+
+/* Non Final Fragment Size supported by Link Partner */
+#define PRE_EMPTION_ADD_FRAG_SIZE_REMOTE 0x05A4
+
+/* Non Final Fragment Size supported by Firmware */
+#define PRE_EMPTION_ADD_FRAG_SIZE_LOCAL 0x05A6
+
+/* Time in ms the State machine waits for respond Packet */
+#define PRE_EMPTION_VERIFY_TIME 0x05A8
+
+/* Memory used for R30 related management commands */
+#define MGR_R30_CMD_OFFSET 0x05AC
+
+/* HW Buffer Pool0 base address */
+#define BUFFER_POOL_0_ADDR_OFFSET 0x05BC
+
+/* 16B for Host Egress MSMC Q (Pre-emptible) context */
+#define HOST_RX_Q_PRE_CONTEXT_OFFSET 0x0684
+
+/* Buffer for 8 FDB entries to be added by 'Add Multiple FDB entries IOCTL' */
+#define FDB_CMD_BUFFER 0x0894
+
+/* TAS queue max sdu length list */
+#define TAS_QUEUE_MAX_SDU_LIST 0x08FA
+
+/* Used by FW to generate random number with the SEED value */
+#define HD_RAND_SEED_OFFSET 0x0934
+
+/* 16B for Host Egress MSMC Q (Express) context */
+#define HOST_RX_Q_EXP_CONTEXT_OFFSET 0x0940
+
+/* Start of 32 bits PA_STAT counters */
+#define PA_STAT_32b_START_OFFSET 0x0080
+
+#endif /* __NET_TI_ICSSG_SWITCH_MAP_H */
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
index 43d5cd59b56b..7007eb8bed36 100644
--- a/drivers/net/ethernet/ti/netcp.h
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -233,8 +233,6 @@ int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order,
netcp_hook_rtn *hook_rtn, void *hook_data);
int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
netcp_hook_rtn *hook_rtn, void *hook_data);
-void *netcp_device_find_module(struct netcp_device *netcp_device,
- const char *name);
/* SGMII functions */
int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port);
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index b50be67b398b..14cf6ecf6d0d 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -667,8 +667,7 @@ static int tc_mii_init(struct net_device *dev)
lp->mii_bus->name = "tc35815_mii_bus";
lp->mii_bus->read = tc_mdio_read;
lp->mii_bus->write = tc_mdio_write;
- snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x",
- (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn);
+ snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(lp->pci_dev));
lp->mii_bus->priv = dev;
lp->mii_bus->parent = &lp->pci_dev->dev;
err = mdiobus_register(lp->mii_bus);
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index d716e6fe26e1..3e09e5036490 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -94,7 +94,7 @@ static const int multicast_filter_limit = 32;
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index 86f7843b4591..731f689412e6 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -57,8 +57,8 @@
#include <linux/if.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/inetdevice.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 39596cd13539..23cd610bd376 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -41,6 +41,7 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
depends on COMMON_CLK
+ select MARVELL_10G_PHY
select REGMAP
select I2C
select I2C_DESIGNWARE_PLATFORM
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 6321178fc814..85dc16faca54 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -432,71 +432,6 @@ out:
EXPORT_SYMBOL(wx_read_ee_hostif_buffer);
/**
- * wx_calculate_checksum - Calculate checksum for buffer
- * @buffer: pointer to EEPROM
- * @length: size of EEPROM to calculate a checksum for
- * Calculates the checksum for some buffer on a specified length. The
- * checksum calculated is returned.
- **/
-static u8 wx_calculate_checksum(u8 *buffer, u32 length)
-{
- u8 sum = 0;
- u32 i;
-
- if (!buffer)
- return 0;
-
- for (i = 0; i < length; i++)
- sum += buffer[i];
-
- return (u8)(0 - sum);
-}
-
-/**
- * wx_reset_hostif - send reset cmd to fw
- * @wx: pointer to hardware structure
- *
- * Sends reset cmd to firmware through the manageability
- * block.
- **/
-int wx_reset_hostif(struct wx *wx)
-{
- struct wx_hic_reset reset_cmd;
- int ret_val = 0;
- int i;
-
- reset_cmd.hdr.cmd = FW_RESET_CMD;
- reset_cmd.hdr.buf_len = FW_RESET_LEN;
- reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
- reset_cmd.lan_id = wx->bus.func;
- reset_cmd.reset_type = (u16)wx->reset_type;
- reset_cmd.hdr.checksum = 0;
- reset_cmd.hdr.checksum = wx_calculate_checksum((u8 *)&reset_cmd,
- (FW_CEM_HDR_LEN +
- reset_cmd.hdr.buf_len));
-
- for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) {
- ret_val = wx_host_interface_command(wx, (u32 *)&reset_cmd,
- sizeof(reset_cmd),
- WX_HI_COMMAND_TIMEOUT,
- true);
- if (ret_val != 0)
- continue;
-
- if (reset_cmd.hdr.cmd_or_resp.ret_status ==
- FW_CEM_RESP_STATUS_SUCCESS)
- ret_val = 0;
- else
- ret_val = -EFAULT;
-
- break;
- }
-
- return ret_val;
-}
-EXPORT_SYMBOL(wx_reset_hostif);
-
-/**
* wx_init_eeprom_params - Initialize EEPROM params
* @wx: pointer to hardware structure
*
@@ -1501,7 +1436,7 @@ static void wx_restore_vlan(struct wx *wx)
*
* Configure the Rx unit of the MAC after a reset.
**/
-static void wx_configure_rx(struct wx *wx)
+void wx_configure_rx(struct wx *wx)
{
u32 psrtype, i;
int ret;
@@ -1544,6 +1479,7 @@ static void wx_configure_rx(struct wx *wx)
wx_enable_rx(wx);
wx_enable_sec_rx_path(wx);
}
+EXPORT_SYMBOL(wx_configure_rx);
static void wx_configure_isb(struct wx *wx)
{
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index 1f93ca32c921..0b3447bc6f2f 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -14,7 +14,6 @@ int wx_host_interface_command(struct wx *wx, u32 *buffer,
int wx_read_ee_hostif(struct wx *wx, u16 offset, u16 *data);
int wx_read_ee_hostif_buffer(struct wx *wx,
u16 offset, u16 words, u16 *data);
-int wx_reset_hostif(struct wx *wx);
void wx_init_eeprom_params(struct wx *wx);
void wx_get_mac_addr(struct wx *wx, u8 *mac_addr);
void wx_init_rx_addrs(struct wx *wx);
@@ -25,6 +24,7 @@ void wx_disable_rx(struct wx *wx);
void wx_set_rx_mode(struct net_device *netdev);
int wx_change_mtu(struct net_device *netdev, int new_mtu);
void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
+void wx_configure_rx(struct wx *wx);
void wx_configure(struct wx *wx);
void wx_start_hw(struct wx *wx);
int wx_disable_pcie_master(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 2c3f08be8c37..e04d4a5eed7b 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -3,7 +3,7 @@
#include <linux/etherdevice.h>
#include <net/ip6_checksum.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#include <net/inet_ecn.h>
#include <linux/iopoll.h>
#include <linux/sctp.h>
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 29dfb561887d..c5cbd177ef62 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -160,6 +160,10 @@
#define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16))
#define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16))
+#define WX_PSR_WKUP_CTL 0x15B80
+/* Wake Up Filter Control Bit */
+#define WX_PSR_WKUP_CTL_MAG BIT(1) /* Magic Packet Wakeup Enable */
+
/* vlan tbl */
#define WX_PSR_VLAN_TBL(_i) (0x16000 + ((_i) * 4))
@@ -201,6 +205,8 @@
#define WX_TSC_CTL 0x1D000
#define WX_TSC_CTL_TX_DIS BIT(1)
#define WX_TSC_CTL_TSEC_DIS BIT(0)
+#define WX_TSC_ST 0x1D004
+#define WX_TSC_ST_SECTX_RDY BIT(0)
#define WX_TSC_BUF_AE 0x1D00C
#define WX_TSC_BUF_AE_THR GENMASK(9, 0)
@@ -227,6 +233,24 @@
#define WX_MAC_WDG_TIMEOUT 0x1100C
#define WX_MAC_RX_FLOW_CTRL 0x11090
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
+/* MDIO Registers */
+#define WX_MSCA 0x11200
+#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
+#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
+#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
+#define WX_MSCC 0x11204
+#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
+
+enum WX_MSCA_CMD_value {
+ WX_MSCA_CMD_RSV = 0,
+ WX_MSCA_CMD_WRITE,
+ WX_MSCA_CMD_POST_READ,
+ WX_MSCA_CMD_READ,
+};
+
+#define WX_MSCC_SADDR BIT(18)
+#define WX_MSCC_BUSY BIT(22)
+#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
#define WX_MMC_CONTROL 0x11800
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
@@ -576,6 +600,13 @@ enum wx_mac_type {
wx_mac_em
};
+enum sp_media_type {
+ sp_media_unknown = 0,
+ sp_media_fiber,
+ sp_media_copper,
+ sp_media_backplane
+};
+
enum em_mac_type {
em_mac_type_unknown = 0,
em_mac_type_mdi,
@@ -823,6 +854,7 @@ struct wx {
struct wx_bus_info bus;
struct wx_mac_info mac;
enum em_mac_type mac_type;
+ enum sp_media_type media_type;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
struct wx_mac_addr *mac_table;
@@ -846,7 +878,7 @@ struct wx {
int duplex;
struct phy_device *phydev;
- bool wol_enabled;
+ bool wol_hw_supported;
bool ncsi_enabled;
bool gpio_ctrl;
raw_spinlock_t gpio_lock;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index 5b25834baf38..ec0e869e9aac 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -6,14 +6,49 @@
#include <linux/netdevice.h>
#include "../libwx/wx_ethtool.h"
+#include "../libwx/wx_type.h"
#include "ngbe_ethtool.h"
+static void ngbe_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ if (!wx->wol_hw_supported)
+ return;
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (wx->wol & WX_PSR_WKUP_CTL_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+static int ngbe_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct wx *wx = netdev_priv(netdev);
+ struct pci_dev *pdev = wx->pdev;
+
+ if (!wx->wol_hw_supported)
+ return -EOPNOTSUPP;
+
+ wx->wol = 0;
+ if (wol->wolopts & WAKE_MAGIC)
+ wx->wol = WX_PSR_WKUP_CTL_MAG;
+ netdev->wol_enabled = !!(wx->wol);
+ wr32(wx, WX_PSR_WKUP_CTL, wx->wol);
+ device_set_wakeup_enable(&pdev->dev, netdev->wol_enabled);
+
+ return 0;
+}
+
static const struct ethtool_ops ngbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.nway_reset = phy_ethtool_nway_reset,
+ .get_wol = ngbe_get_wol,
+ .set_wol = ngbe_set_wol,
};
void ngbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index c99a5d3de72e..2b431db6085a 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -62,7 +62,7 @@ static void ngbe_init_type_code(struct wx *wx)
em_mac_type_rgmii :
em_mac_type_mdi;
- wx->wol_enabled = (wol_mask == NGBE_WOL_SUP) ? 1 : 0;
+ wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0;
wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK ||
type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0;
@@ -440,14 +440,26 @@ static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct wx *wx = pci_get_drvdata(pdev);
struct net_device *netdev;
+ u32 wufc = wx->wol;
netdev = wx->netdev;
+ rtnl_lock();
netif_device_detach(netdev);
- rtnl_lock();
if (netif_running(netdev))
- ngbe_down(wx);
+ ngbe_close(netdev);
+ wx_clear_interrupt_scheme(wx);
rtnl_unlock();
+
+ if (wufc) {
+ wx_set_rx_mode(netdev);
+ wx_configure_rx(wx);
+ wr32(wx, NGBE_PSR_WKUP_CTL, wufc);
+ } else {
+ wr32(wx, NGBE_PSR_WKUP_CTL, 0);
+ }
+ pci_wake_from_d3(pdev, !!wufc);
+ *enable_wake = !!wufc;
wx_control_hw(wx, false);
pci_disable_device(pdev);
@@ -621,12 +633,11 @@ static int ngbe_probe(struct pci_dev *pdev,
}
wx->wol = 0;
- if (wx->wol_enabled)
+ if (wx->wol_hw_supported)
wx->wol = NGBE_PSR_WKUP_CTL_MAG;
- wx->wol_enabled = !!(wx->wol);
+ netdev->wol_enabled = !!(wx->wol);
wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol);
-
device_set_wakeup_enable(&pdev->dev, wx->wol);
/* Save off EEPROM version number and Option Rom version which
@@ -712,11 +723,52 @@ static void ngbe_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
+static int ngbe_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ bool wake;
+
+ ngbe_dev_shutdown(pdev, &wake);
+ device_set_wakeup_enable(&pdev->dev, wake);
+
+ return 0;
+}
+
+static int ngbe_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev;
+ struct wx *wx;
+ u32 err;
+
+ wx = pci_get_drvdata(pdev);
+ netdev = wx->netdev;
+
+ err = pci_enable_device_mem(pdev);
+ if (err) {
+ wx_err(wx, "Cannot enable PCI device from suspend\n");
+ return err;
+ }
+ pci_set_master(pdev);
+ device_wakeup_disable(&pdev->dev);
+
+ ngbe_reset_hw(wx);
+ rtnl_lock();
+ err = wx_init_interrupt_scheme(wx);
+ if (!err && netif_running(netdev))
+ err = ngbe_open(netdev);
+ if (!err)
+ netif_device_attach(netdev);
+ rtnl_unlock();
+
+ return 0;
+}
+
static struct pci_driver ngbe_driver = {
.name = ngbe_driver_name,
.id_table = ngbe_pci_tbl,
.probe = ngbe_probe,
.remove = ngbe_remove,
+ .suspend = ngbe_suspend,
+ .resume = ngbe_resume,
.shutdown = ngbe_shutdown,
};
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
index c9ddbbc3fa4f..591f5b7b6da6 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
@@ -37,24 +37,24 @@ static int ngbe_phy_read_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(device_type);
- wr32(wx, NGBE_MSCA, command);
- command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(device_type);
+ wr32(wx, WX_MSCA, command);
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c22 command did not complete.\n");
return ret;
}
- return (u16)rd32(wx, NGBE_MSCC);
+ return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
@@ -65,19 +65,19 @@ static int ngbe_phy_write_reg_mdi_c22(struct mii_bus *bus, int phy_addr, int reg
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0xF);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(device_type);
- wr32(wx, NGBE_MSCA, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(device_type);
+ wr32(wx, WX_MSCA, command);
command = value |
- NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c22 command did not complete.\n");
@@ -92,24 +92,24 @@ static int ngbe_phy_read_reg_mdi_c45(struct mii_bus *bus, int phy_addr, int devn
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(devnum);
- wr32(wx, NGBE_MSCA, command);
- command = NGBE_MSCC_CMD(NGBE_MSCA_CMD_READ) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret) {
wx_err(wx, "Mdio read c45 command did not complete.\n");
return ret;
}
- return (u16)rd32(wx, NGBE_MSCC);
+ return (u16)rd32(wx, WX_MSCC);
}
static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
@@ -121,19 +121,19 @@ static int ngbe_phy_write_reg_mdi_c45(struct mii_bus *bus, int phy_addr,
wr32(wx, NGBE_MDIO_CLAUSE_SELECT, 0x0);
/* setup and write the address cycle command */
- command = NGBE_MSCA_RA(regnum) |
- NGBE_MSCA_PA(phy_addr) |
- NGBE_MSCA_DA(devnum);
- wr32(wx, NGBE_MSCA, command);
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
command = value |
- NGBE_MSCC_CMD(NGBE_MSCA_CMD_WRITE) |
- NGBE_MSCC_BUSY |
- NGBE_MDIO_CLK(6);
- wr32(wx, NGBE_MSCC, command);
+ WX_MSCC_CMD(WX_MSCA_CMD_WRITE) |
+ WX_MSCC_BUSY |
+ WX_MDIO_CLK(6);
+ wr32(wx, WX_MSCC, command);
/* wait to complete */
- ret = read_poll_timeout(rd32, val, !(val & NGBE_MSCC_BUSY), 1000,
- 100000, false, wx, NGBE_MSCC);
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
if (ret)
wx_err(wx, "Mdio write c45 command did not complete.\n");
@@ -236,6 +236,7 @@ static void ngbe_phy_fixup(struct wx *wx)
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phydev->mac_managed_pm = true;
if (wx->mac_type != em_mac_type_mdi)
return;
/* disable EEE, internal phy does not support eee */
@@ -265,8 +266,7 @@ int ngbe_mdio_init(struct wx *wx)
mii_bus->write_c45 = ngbe_phy_write_reg_mdi_c45;
}
- snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x",
- (pdev->bus->number << 8) | pdev->devfn);
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev));
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
if (ret)
return ret;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index b70eca397b67..72c8cd2d5575 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -59,25 +59,6 @@
#define NGBE_EEPROM_VERSION_L 0x1D
#define NGBE_EEPROM_VERSION_H 0x1E
-/* mdio access */
-#define NGBE_MSCA 0x11200
-#define NGBE_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
-#define NGBE_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
-#define NGBE_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
-#define NGBE_MSCC 0x11204
-#define NGBE_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
-
-enum NGBE_MSCA_CMD_value {
- NGBE_MSCA_CMD_RSV = 0,
- NGBE_MSCA_CMD_WRITE,
- NGBE_MSCA_CMD_POST_READ,
- NGBE_MSCA_CMD_READ,
-};
-
-#define NGBE_MSCC_SADDR BIT(18)
-#define NGBE_MSCC_BUSY BIT(22)
-#define NGBE_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
-
/* Media-dependent registers. */
#define NGBE_MDIO_CLAUSE_SELECT 0x11220
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
index 0772eb14eabf..372745250270 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c
@@ -14,6 +14,34 @@
#include "txgbe_hw.h"
/**
+ * txgbe_disable_sec_tx_path - Stops the transmit data path
+ * @wx: pointer to hardware structure
+ *
+ * Stops the transmit data path and waits for the HW to internally empty
+ * the tx security block
+ **/
+int txgbe_disable_sec_tx_path(struct wx *wx)
+{
+ int val;
+
+ wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, WX_TSC_CTL_TX_DIS);
+ return read_poll_timeout(rd32, val, val & WX_TSC_ST_SECTX_RDY,
+ 1000, 20000, false, wx, WX_TSC_ST);
+}
+
+/**
+ * txgbe_enable_sec_tx_path - Enables the transmit data path
+ * @wx: pointer to hardware structure
+ *
+ * Enables the transmit data path.
+ **/
+void txgbe_enable_sec_tx_path(struct wx *wx)
+{
+ wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS, 0);
+ WX_WRITE_FLUSH(wx);
+}
+
+/**
* txgbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds
* @wx: pointer to hardware structure
*
@@ -263,11 +291,14 @@ int txgbe_reset_hw(struct wx *wx)
if (status != 0)
return status;
- if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
- ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP)))
- wx_reset_hostif(wx);
+ if (wx->media_type != sp_media_copper) {
+ u32 val;
- usleep_range(10, 100);
+ val = WX_MIS_RST_LAN_RST(wx->bus.func);
+ wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
+ WX_WRITE_FLUSH(wx);
+ usleep_range(10, 100);
+ }
status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
if (status != 0)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
index e82f65dff8a6..abc729eb187a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.h
@@ -4,6 +4,8 @@
#ifndef _TXGBE_HW_H_
#define _TXGBE_HW_H_
+int txgbe_disable_sec_tx_path(struct wx *wx);
+void txgbe_enable_sec_tx_path(struct wx *wx);
int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size);
int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val);
int txgbe_reset_hw(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 46eba6d6188b..5c3aed516ac2 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -301,6 +301,49 @@ static void txgbe_down(struct wx *wx)
}
/**
+ * txgbe_init_type_code - Initialize the shared code
+ * @wx: pointer to hardware structure
+ **/
+static void txgbe_init_type_code(struct wx *wx)
+{
+ u8 device_type = wx->subsystem_device_id & 0xF0;
+
+ switch (wx->device_id) {
+ case TXGBE_DEV_ID_SP1000:
+ case TXGBE_DEV_ID_WX1820:
+ wx->mac.type = wx_mac_sp;
+ break;
+ default:
+ wx->mac.type = wx_mac_unknown;
+ break;
+ }
+
+ switch (device_type) {
+ case TXGBE_ID_SFP:
+ wx->media_type = sp_media_fiber;
+ break;
+ case TXGBE_ID_XAUI:
+ case TXGBE_ID_SGMII:
+ wx->media_type = sp_media_copper;
+ break;
+ case TXGBE_ID_KR_KX_KX4:
+ case TXGBE_ID_MAC_XAUI:
+ case TXGBE_ID_MAC_SGMII:
+ wx->media_type = sp_media_backplane;
+ break;
+ case TXGBE_ID_SFI_XAUI:
+ if (wx->bus.func == 0)
+ wx->media_type = sp_media_fiber;
+ else
+ wx->media_type = sp_media_copper;
+ break;
+ default:
+ wx->media_type = sp_media_unknown;
+ break;
+ }
+}
+
+/**
* txgbe_sw_init - Initialize general software structures (struct wx)
* @wx: board private structure to initialize
**/
@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
return err;
}
- switch (wx->device_id) {
- case TXGBE_DEV_ID_SP1000:
- case TXGBE_DEV_ID_WX1820:
- wx->mac.type = wx_mac_sp;
- break;
- default:
- wx->mac.type = wx_mac_unknown;
- break;
- }
+ txgbe_init_type_code(wx);
/* Set common capability flags and settings */
wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
@@ -663,6 +698,9 @@ static int txgbe_probe(struct pci_dev *pdev,
"0x%08x", etrack_id);
}
+ if (etrack_id < 0x20010)
+ dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
+
txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
if (!txgbe) {
err = -ENOMEM;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 8779645a54be..4159c84035fd 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -18,6 +18,7 @@
#include "../libwx/wx_hw.h"
#include "txgbe_type.h"
#include "txgbe_phy.h"
+#include "txgbe_hw.h"
static int txgbe_swnodes_register(struct txgbe *txgbe)
{
@@ -26,7 +27,7 @@ static int txgbe_swnodes_register(struct txgbe *txgbe)
struct software_node *swnodes;
u32 id;
- id = (pdev->bus->number << 8) | pdev->devfn;
+ id = pci_dev_id(pdev);
snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id);
snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id);
@@ -140,7 +141,7 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
mii_bus->phy_mask = ~0;
mii_bus->priv = wx;
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x",
- (pdev->bus->number << 8) | pdev->devfn);
+ pci_dev_id(pdev));
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
if (ret)
@@ -160,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
{
struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
- return &txgbe->xpcs->pcs;
+ if (interface == PHY_INTERFACE_MODE_10GBASER)
+ return &txgbe->xpcs->pcs;
+
+ return NULL;
}
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
@@ -210,8 +214,32 @@ static void txgbe_mac_link_up(struct phylink_config *config,
wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
}
+static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct wx *wx = netdev_priv(to_net_dev(config->dev));
+
+ wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
+ wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
+
+ return txgbe_disable_sec_tx_path(wx);
+}
+
+static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct wx *wx = netdev_priv(to_net_dev(config->dev));
+
+ txgbe_enable_sec_tx_path(wx);
+ wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
+
+ return 0;
+}
+
static const struct phylink_mac_ops txgbe_mac_ops = {
.mac_select_pcs = txgbe_phylink_mac_select,
+ .mac_prepare = txgbe_mac_prepare,
+ .mac_finish = txgbe_mac_finish,
.mac_config = txgbe_mac_config,
.mac_link_down = txgbe_mac_link_down,
.mac_link_up = txgbe_mac_link_up,
@@ -219,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
static int txgbe_phylink_init(struct txgbe *txgbe)
{
+ struct fwnode_handle *fwnode = NULL;
struct phylink_config *config;
- struct fwnode_handle *fwnode;
struct wx *wx = txgbe->wx;
phy_interface_t phy_mode;
struct phylink *phylink;
@@ -231,14 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
config->dev = &wx->netdev->dev;
config->type = PHYLINK_NETDEV;
- config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
- phy_mode = PHY_INTERFACE_MODE_10GBASER;
- __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
- fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
+ config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
+ MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+
+ if (wx->media_type == sp_media_copper) {
+ phy_mode = PHY_INTERFACE_MODE_XAUI;
+ __set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
+ } else {
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
+ }
+
phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
if (IS_ERR(phylink))
return PTR_ERR(phylink);
+ if (wx->phydev) {
+ int ret;
+
+ ret = phylink_connect_phy(phylink, wx->phydev);
+ if (ret) {
+ phylink_destroy(phylink);
+ return ret;
+ }
+ }
+
txgbe->phylink = phylink;
return 0;
@@ -431,7 +479,8 @@ static void txgbe_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
- if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) {
+ if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN |
+ TXGBE_PX_MISC_ETH_AN)) {
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
@@ -459,7 +508,7 @@ static int txgbe_gpio_init(struct txgbe *txgbe)
return -ENOMEM;
gc->label = devm_kasprintf(dev, GFP_KERNEL, "txgbe_gpio-%x",
- (wx->pdev->bus->number << 8) | wx->pdev->devfn);
+ pci_dev_id(wx->pdev));
if (!gc->label)
return -ENOMEM;
@@ -503,7 +552,7 @@ static int txgbe_clock_register(struct txgbe *txgbe)
struct clk *clk;
snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d",
- (pdev->bus->number << 8) | pdev->devfn);
+ pci_dev_id(pdev));
clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000);
if (IS_ERR(clk))
@@ -566,7 +615,7 @@ static int txgbe_i2c_register(struct txgbe *txgbe)
info.parent = &pdev->dev;
info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]);
info.name = "i2c_designware";
- info.id = (pdev->bus->number << 8) | pdev->devfn;
+ info.id = pci_dev_id(pdev);
info.res = &DEFINE_RES_IRQ(pdev->irq);
info.num_res = 1;
@@ -588,7 +637,7 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
info.parent = &pdev->dev;
info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]);
info.name = "sfp";
- info.id = (pdev->bus->number << 8) | pdev->devfn;
+ info.id = pci_dev_id(pdev);
sfp_dev = platform_device_register_full(&info);
if (IS_ERR(sfp_dev))
return PTR_ERR(sfp_dev);
@@ -598,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
return 0;
}
+static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
+ int devnum, int regnum)
+{
+ struct wx *wx = bus->priv;
+ u32 val, command;
+ int ret;
+
+ /* setup and write the address cycle command */
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+
+ command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
+ wr32(wx, WX_MSCC, command);
+
+ /* wait to complete */
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
+ if (ret) {
+ wx_err(wx, "Mdio read c45 command did not complete.\n");
+ return ret;
+ }
+
+ return (u16)rd32(wx, WX_MSCC);
+}
+
+static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
+ int devnum, int regnum, u16 value)
+{
+ struct wx *wx = bus->priv;
+ int ret, command;
+ u16 val;
+
+ /* setup and write the address cycle command */
+ command = WX_MSCA_RA(regnum) |
+ WX_MSCA_PA(phy_addr) |
+ WX_MSCA_DA(devnum);
+ wr32(wx, WX_MSCA, command);
+
+ command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
+ wr32(wx, WX_MSCC, command);
+
+ /* wait to complete */
+ ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
+ 100000, false, wx, WX_MSCC);
+ if (ret)
+ wx_err(wx, "Mdio write c45 command did not complete.\n");
+
+ return ret;
+}
+
+static int txgbe_ext_phy_init(struct txgbe *txgbe)
+{
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
+ struct pci_dev *pdev;
+ struct wx *wx;
+ int ret = 0;
+
+ wx = txgbe->wx;
+ pdev = wx->pdev;
+
+ mii_bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!mii_bus)
+ return -ENOMEM;
+
+ mii_bus->name = "txgbe_mii_bus";
+ mii_bus->read_c45 = &txgbe_phy_read;
+ mii_bus->write_c45 = &txgbe_phy_write;
+ mii_bus->parent = &pdev->dev;
+ mii_bus->phy_mask = GENMASK(31, 1);
+ mii_bus->priv = wx;
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
+ (pdev->bus->number << 8) | pdev->devfn);
+
+ ret = devm_mdiobus_register(&pdev->dev, mii_bus);
+ if (ret) {
+ wx_err(wx, "failed to register MDIO bus: %d\n", ret);
+ return ret;
+ }
+
+ phydev = phy_find_first(mii_bus);
+ if (!phydev) {
+ wx_err(wx, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phy_attached_info(phydev);
+
+ wx->link = 0;
+ wx->speed = 0;
+ wx->duplex = 0;
+ wx->phydev = phydev;
+
+ ret = txgbe_phylink_init(txgbe);
+ if (ret) {
+ wx_err(wx, "failed to init phylink: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
int txgbe_init_phy(struct txgbe *txgbe)
{
int ret;
+ if (txgbe->wx->media_type == sp_media_copper)
+ return txgbe_ext_phy_init(txgbe);
+
ret = txgbe_swnodes_register(txgbe);
if (ret) {
wx_err(txgbe->wx, "failed to register software nodes\n");
@@ -663,6 +819,12 @@ err_unregister_swnode:
void txgbe_remove_phy(struct txgbe *txgbe)
{
+ if (txgbe->wx->media_type == sp_media_copper) {
+ phylink_disconnect_phy(txgbe->phylink);
+ phylink_destroy(txgbe->phylink);
+ return;
+ }
+
platform_device_unregister(txgbe->sfp_dev);
platform_device_unregister(txgbe->i2c_dev);
clkdev_drop(txgbe->clock);
diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 6668d1b760d8..90d122d5475c 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -5,6 +5,7 @@
#include <linux/netdevice.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#ifdef CONFIG_PPC_DCR
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 49f303353ecb..1444b855e7aa 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -35,12 +35,10 @@
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/tcp.h> /* needed for sizeof(tcphdr) */
diff --git a/drivers/net/ethernet/xilinx/ll_temac_mdio.c b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
index 2371c072b53f..07a9fb49eda1 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_mdio.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_mdio.c
@@ -10,8 +10,8 @@
#include <linux/mutex.h>
#include <linux/phy.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of_mdio.h>
#include <linux/platform_data/xilinx-ll-temac.h>
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 8e32dc50a408..b7ec4dafae90 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -27,11 +27,12 @@
#include <linux/etherdevice.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include <linux/math64.h>
#include <linux/phy.h>
diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index ad2c30d9a482..b358ecc67227 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -8,6 +8,7 @@
*/
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -15,9 +16,8 @@
#include <linux/ethtool.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/phy.h>
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index acb20ad4e37e..144ec626230d 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -243,7 +243,8 @@ static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
fl4->flowi4_oif = sk->sk_bound_dev_if;
fl4->daddr = daddr;
fl4->saddr = saddr;
- fl4->flowi4_tos = RT_CONN_FLAGS(sk);
+ fl4->flowi4_tos = ip_sock_rt_tos(sk);
+ fl4->flowi4_scope = ip_sock_rt_scope(sk);
fl4->flowi4_proto = sk->sk_protocol;
return ip_route_output_key(sock_net(sk), fl4);
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index c9dd69dbe1b8..810977952f95 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -16,6 +16,7 @@
#include <linux/hyperv.h>
#include <linux/rndis.h>
#include <linux/jhash.h>
+#include <net/xdp.h>
/* RSS related */
#define OID_GEN_RECEIVE_SCALE_CAPABILITIES 0x00010203 /* query only */
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index f9b10e84de06..aebb19f1b3a4 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -57,7 +57,6 @@
#include <linux/io.h>
#include <linux/kfifo.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
#include <linux/mutex.h>
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 6a2f2fc2f501..da853353a5c7 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -13,8 +13,8 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index b15dd9a3ad54..1b55928e89b8 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -748,7 +748,8 @@ static int ipvlan_device_event(struct notifier_block *unused,
write_pnet(&port->pnet, newnet);
- ipvlan_migrate_l3s_hook(oldnet, newnet);
+ if (port->mode == IPVLAN_MODE_L3S)
+ ipvlan_migrate_l3s_hook(oldnet, newnet);
break;
}
case NETDEV_UNREGISTER:
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 144ec756c796..c3f30663070f 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -518,14 +518,8 @@ static void macsec_count_tx(struct sk_buff *skb, struct macsec_tx_sc *tx_sc,
static void count_tx(struct net_device *dev, int ret, int len)
{
- if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
- struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
-
- u64_stats_update_begin(&stats->syncp);
- u64_stats_inc(&stats->tx_packets);
- u64_stats_add(&stats->tx_bytes, len);
- u64_stats_update_end(&stats->syncp);
- }
+ if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN))
+ dev_sw_netstats_tx_add(dev, 1, len);
}
static void macsec_encrypt_done(void *data, int err)
@@ -827,12 +821,7 @@ static void macsec_finalize_skb(struct sk_buff *skb, u8 icv_len, u8 hdr_len)
static void count_rx(struct net_device *dev, int len)
{
- struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
-
- u64_stats_update_begin(&stats->syncp);
- u64_stats_inc(&stats->rx_packets);
- u64_stats_add(&stats->rx_bytes, len);
- u64_stats_update_end(&stats->syncp);
+ dev_sw_netstats_rx_add(dev, len);
}
static void macsec_decrypt_done(void *data, int err)
@@ -4240,6 +4229,18 @@ static struct net *macsec_get_link_net(const struct net_device *dev)
return dev_net(macsec_priv(dev)->real_dev);
}
+struct net_device *macsec_get_real_dev(const struct net_device *dev)
+{
+ return macsec_priv(dev)->real_dev;
+}
+EXPORT_SYMBOL_GPL(macsec_get_real_dev);
+
+bool macsec_netdev_is_offloaded(struct net_device *dev)
+{
+ return macsec_is_offloaded(macsec_priv(dev));
+}
+EXPORT_SYMBOL_GPL(macsec_netdev_is_offloaded);
+
static size_t macsec_get_size(const struct net_device *dev)
{
return nla_total_size_64bit(8) + /* IFLA_MACSEC_SCI */
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index ed908165a8b4..02bd201bc7e5 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -868,31 +868,24 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static int macvlan_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int macvlan_hwtstamp_get(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg)
{
struct net_device *real_dev = macvlan_dev_real_dev(dev);
- const struct net_device_ops *ops = real_dev->netdev_ops;
- struct ifreq ifrr;
- int err = -EOPNOTSUPP;
- strscpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ);
- ifrr.ifr_ifru = ifr->ifr_ifru;
+ return generic_hwtstamp_get_lower(real_dev, cfg);
+}
- switch (cmd) {
- case SIOCSHWTSTAMP:
- if (!net_eq(dev_net(dev), &init_net))
- break;
- fallthrough;
- case SIOCGHWTSTAMP:
- if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
- err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
- break;
- }
+static int macvlan_hwtstamp_set(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *real_dev = macvlan_dev_real_dev(dev);
- if (!err)
- ifr->ifr_ifru = ifrr.ifr_ifru;
+ if (!net_eq(dev_net(dev), &init_net))
+ return -EOPNOTSUPP;
- return err;
+ return generic_hwtstamp_set_lower(real_dev, cfg, extack);
}
/*
@@ -1193,7 +1186,6 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_stop = macvlan_stop,
.ndo_start_xmit = macvlan_start_xmit,
.ndo_change_mtu = macvlan_change_mtu,
- .ndo_eth_ioctl = macvlan_eth_ioctl,
.ndo_fix_features = macvlan_fix_features,
.ndo_change_rx_flags = macvlan_change_rx_flags,
.ndo_set_mac_address = macvlan_set_mac_address,
@@ -1212,6 +1204,8 @@ static const struct net_device_ops macvlan_netdev_ops = {
#endif
.ndo_get_iflink = macvlan_dev_get_iflink,
.ndo_features_check = passthru_features_check,
+ .ndo_hwtstamp_get = macvlan_hwtstamp_get,
+ .ndo_hwtstamp_set = macvlan_hwtstamp_set,
};
static void macvlan_dev_free(struct net_device *dev)
diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c
index bfc9be23c973..6b26a0803696 100644
--- a/drivers/net/mdio/mdio-bcm-unimac.c
+++ b/drivers/net/mdio/mdio-bcm-unimac.c
@@ -334,6 +334,8 @@ static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops,
unimac_mdio_suspend, unimac_mdio_resume);
static const struct of_device_id unimac_mdio_ids[] = {
+ { .compatible = "brcm,asp-v2.1-mdio", },
+ { .compatible = "brcm,asp-v2.0-mdio", },
{ .compatible = "brcm,genet-mdio-v5", },
{ .compatible = "brcm,genet-mdio-v4", },
{ .compatible = "brcm,genet-mdio-v3", },
diff --git a/drivers/net/mdio/mdio-bitbang.c b/drivers/net/mdio/mdio-bitbang.c
index b83932562be2..81b7748c10ce 100644
--- a/drivers/net/mdio/mdio-bitbang.c
+++ b/drivers/net/mdio/mdio-bitbang.c
@@ -186,7 +186,7 @@ int mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, int reg)
struct mdiobb_ctrl *ctrl = bus->priv;
mdiobb_cmd_addr(ctrl, phy, devad, reg);
- mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+ mdiobb_cmd(ctrl, MDIO_C45_READ, phy, devad);
return mdiobb_read_common(bus, phy);
}
@@ -222,7 +222,7 @@ int mdiobb_write_c45(struct mii_bus *bus, int phy, int devad, int reg, u16 val)
struct mdiobb_ctrl *ctrl = bus->priv;
mdiobb_cmd_addr(ctrl, phy, devad, reg);
- mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+ mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, devad);
return mdiobb_write_common(bus, val);
}
diff --git a/drivers/net/mdio/mdio-xgene.c b/drivers/net/mdio/mdio-xgene.c
index 7aafc221b5cf..1190a793555a 100644
--- a/drivers/net/mdio/mdio-xgene.c
+++ b/drivers/net/mdio/mdio-xgene.c
@@ -20,8 +20,6 @@
#include <linux/prefetch.h>
#include <net/ip.h>
-static bool xgene_mdio_status;
-
u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr)
{
void __iomem *addr, *rd, *cmd, *cmd_done;
@@ -79,7 +77,7 @@ EXPORT_SYMBOL(xgene_mdio_wr_mac);
int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg)
{
- struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv;
+ struct xgene_mdio_pdata *pdata = bus->priv;
u32 data, done;
u8 wait = 10;
@@ -105,7 +103,7 @@ EXPORT_SYMBOL(xgene_mdio_rgmii_read);
int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
{
- struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv;
+ struct xgene_mdio_pdata *pdata = bus->priv;
u32 val, done;
u8 wait = 10;
@@ -335,7 +333,7 @@ static int xgene_mdio_probe(struct platform_device *pdev)
of_id = of_match_device(xgene_mdio_of_match, &pdev->dev);
if (of_id) {
- mdio_id = (enum xgene_mdio_id)of_id->data;
+ mdio_id = (uintptr_t)of_id->data;
} else {
#ifdef CONFIG_ACPI
const struct acpi_device_id *acpi_id;
@@ -421,7 +419,6 @@ static int xgene_mdio_probe(struct platform_device *pdev)
goto out_mdiobus;
pdata->mdio_bus = mdio_bus;
- xgene_mdio_status = true;
return 0;
diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c
index 3d322ac4f6a5..ae169929a9d8 100644
--- a/drivers/net/mhi_net.c
+++ b/drivers/net/mhi_net.c
@@ -403,7 +403,6 @@ static struct mhi_driver mhi_net_driver = {
.id_table = mhi_net_id_table,
.driver = {
.name = "mhi_net",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 4f4f79532c6c..3111e1648592 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -36,6 +36,7 @@
#include <linux/inet.h>
#include <linux/configfs.h>
#include <linux/etherdevice.h>
+#include <linux/utsname.h>
MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
MODULE_DESCRIPTION("Console driver for network interfaces");
@@ -84,6 +85,8 @@ static struct console netconsole_ext;
* Also, other parameters of a target may be modified at
* runtime only when it is disabled (enabled == 0).
* @extended: Denotes whether console is extended or not.
+ * @release: Denotes whether kernel release version should be prepended
+ * to the message. Depends on extended console.
* @np: The netpoll structure for this target.
* Contains the other userspace visible parameters:
* dev_name (read-write)
@@ -101,6 +104,7 @@ struct netconsole_target {
#endif
bool enabled;
bool extended;
+ bool release;
struct netpoll np;
};
@@ -163,19 +167,21 @@ static void netconsole_target_put(struct netconsole_target *nt)
#endif /* CONFIG_NETCONSOLE_DYNAMIC */
-/* Allocate new target (from boot/module param) and setup netpoll for it */
-static struct netconsole_target *alloc_param_target(char *target_config)
+/* Allocate and initialize with defaults.
+ * Note that these targets get their config_item fields zeroed-out.
+ */
+static struct netconsole_target *alloc_and_init(void)
{
- int err = -ENOMEM;
struct netconsole_target *nt;
- /*
- * Allocate and initialize with defaults.
- * Note that these targets get their config_item fields zeroed-out.
- */
nt = kzalloc(sizeof(*nt), GFP_KERNEL);
if (!nt)
- goto fail;
+ return nt;
+
+ if (IS_ENABLED(CONFIG_NETCONSOLE_EXTENDED_LOG))
+ nt->extended = true;
+ if (IS_ENABLED(CONFIG_NETCONSOLE_PREPEND_RELEASE))
+ nt->release = true;
nt->np.name = "netconsole";
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
@@ -183,11 +189,36 @@ static struct netconsole_target *alloc_param_target(char *target_config)
nt->np.remote_port = 6666;
eth_broadcast_addr(nt->np.remote_mac);
+ return nt;
+}
+
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config)
+{
+ struct netconsole_target *nt;
+ int err;
+
+ nt = alloc_and_init();
+ if (!nt) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
if (*target_config == '+') {
nt->extended = true;
target_config++;
}
+ if (*target_config == 'r') {
+ if (!nt->extended) {
+ pr_err("Netconsole configuration error. Release feature requires extended log message");
+ err = -EINVAL;
+ goto fail;
+ }
+ nt->release = true;
+ target_config++;
+ }
+
/* Parse parameters and setup netpoll */
err = netpoll_parse_options(&nt->np, target_config);
if (err)
@@ -222,6 +253,7 @@ static void free_param_target(struct netconsole_target *nt)
* |
* <target>/
* | enabled
+ * | release
* | dev_name
* | local_port
* | remote_port
@@ -246,27 +278,32 @@ static struct netconsole_target *to_target(struct config_item *item)
static ssize_t enabled_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled);
+ return sysfs_emit(buf, "%d\n", to_target(item)->enabled);
}
static ssize_t extended_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended);
+ return sysfs_emit(buf, "%d\n", to_target(item)->extended);
+}
+
+static ssize_t release_show(struct config_item *item, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", to_target(item)->release);
}
static ssize_t dev_name_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name);
+ return sysfs_emit(buf, "%s\n", to_target(item)->np.dev_name);
}
static ssize_t local_port_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);
}
static ssize_t remote_port_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);
}
static ssize_t local_ip_show(struct config_item *item, char *buf)
@@ -274,9 +311,9 @@ static ssize_t local_ip_show(struct config_item *item, char *buf)
struct netconsole_target *nt = to_target(item);
if (nt->np.ipv6)
- return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+ return sysfs_emit(buf, "%pI6c\n", &nt->np.local_ip.in6);
else
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+ return sysfs_emit(buf, "%pI4\n", &nt->np.local_ip);
}
static ssize_t remote_ip_show(struct config_item *item, char *buf)
@@ -284,9 +321,9 @@ static ssize_t remote_ip_show(struct config_item *item, char *buf)
struct netconsole_target *nt = to_target(item);
if (nt->np.ipv6)
- return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+ return sysfs_emit(buf, "%pI6c\n", &nt->np.remote_ip.in6);
else
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+ return sysfs_emit(buf, "%pI4\n", &nt->np.remote_ip);
}
static ssize_t local_mac_show(struct config_item *item, char *buf)
@@ -294,12 +331,12 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)
struct net_device *dev = to_target(item)->np.dev;
static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
+ return sysfs_emit(buf, "%pM\n", dev ? dev->dev_addr : bcast);
}
static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac);
+ return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
}
/*
@@ -314,17 +351,15 @@ static ssize_t enabled_store(struct config_item *item,
{
struct netconsole_target *nt = to_target(item);
unsigned long flags;
- int enabled;
+ bool enabled;
int err;
mutex_lock(&dynamic_netconsole_mutex);
- err = kstrtoint(buf, 10, &enabled);
- if (err < 0)
+ err = kstrtobool(buf, &enabled);
+ if (err)
goto out_unlock;
err = -EINVAL;
- if (enabled < 0 || enabled > 1)
- goto out_unlock;
if ((bool)enabled == nt->enabled) {
pr_info("network logging has already %s\n",
nt->enabled ? "started" : "stopped");
@@ -332,6 +367,11 @@ static ssize_t enabled_store(struct config_item *item,
}
if (enabled) { /* true */
+ if (nt->release && !nt->extended) {
+ pr_err("Not enabling netconsole. Release feature requires extended log message");
+ goto out_unlock;
+ }
+
if (nt->extended && !console_is_registered(&netconsole_ext))
register_console(&netconsole_ext);
@@ -366,11 +406,11 @@ out_unlock:
return err;
}
-static ssize_t extended_store(struct config_item *item, const char *buf,
- size_t count)
+static ssize_t release_store(struct config_item *item, const char *buf,
+ size_t count)
{
struct netconsole_target *nt = to_target(item);
- int extended;
+ bool release;
int err;
mutex_lock(&dynamic_netconsole_mutex);
@@ -381,14 +421,38 @@ static ssize_t extended_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- err = kstrtoint(buf, 10, &extended);
- if (err < 0)
+ err = kstrtobool(buf, &release);
+ if (err)
goto out_unlock;
- if (extended < 0 || extended > 1) {
+
+ nt->release = release;
+
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return err;
+}
+
+static ssize_t extended_store(struct config_item *item, const char *buf,
+ size_t count)
+{
+ struct netconsole_target *nt = to_target(item);
+ bool extended;
+ int err;
+
+ mutex_lock(&dynamic_netconsole_mutex);
+ if (nt->enabled) {
+ pr_err("target (%s) is enabled, disable to update parameters\n",
+ config_item_name(&nt->item));
err = -EINVAL;
goto out_unlock;
}
+ err = kstrtobool(buf, &extended);
+ if (err)
+ goto out_unlock;
+
nt->extended = extended;
mutex_unlock(&dynamic_netconsole_mutex);
@@ -576,10 +640,12 @@ CONFIGFS_ATTR(, local_ip);
CONFIGFS_ATTR(, remote_ip);
CONFIGFS_ATTR_RO(, local_mac);
CONFIGFS_ATTR(, remote_mac);
+CONFIGFS_ATTR(, release);
static struct configfs_attribute *netconsole_target_attrs[] = {
&attr_enabled,
&attr_extended,
+ &attr_release,
&attr_dev_name,
&attr_local_port,
&attr_remote_port,
@@ -616,23 +682,13 @@ static const struct config_item_type netconsole_target_type = {
static struct config_item *make_netconsole_target(struct config_group *group,
const char *name)
{
- unsigned long flags;
struct netconsole_target *nt;
+ unsigned long flags;
- /*
- * Allocate and initialize with defaults.
- * Target is disabled at creation (!enabled).
- */
- nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+ nt = alloc_and_init();
if (!nt)
return ERR_PTR(-ENOMEM);
- nt->np.name = "netconsole";
- strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
- nt->np.local_port = 6665;
- nt->np.remote_port = 6666;
- eth_broadcast_addr(nt->np.remote_mac);
-
/* Initialize the config_item member */
config_item_init_type_name(&nt->item, name, &netconsole_target_type);
@@ -772,9 +828,23 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
const char *header, *body;
int offset = 0;
int header_len, body_len;
+ const char *msg_ready = msg;
+ const char *release;
+ int release_len = 0;
+
+ if (nt->release) {
+ release = init_utsname()->release;
+ release_len = strlen(release) + 1;
+ }
- if (msg_len <= MAX_PRINT_CHUNK) {
- netpoll_send_udp(&nt->np, msg, msg_len);
+ if (msg_len + release_len <= MAX_PRINT_CHUNK) {
+ /* No fragmentation needed */
+ if (nt->release) {
+ scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg);
+ msg_len += release_len;
+ msg_ready = buf;
+ }
+ netpoll_send_udp(&nt->np, msg_ready, msg_len);
return;
}
@@ -792,7 +862,10 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
* Transfer multiple chunks with the following extra header.
* "ncfrag=<byte-offset>/<total-bytes>"
*/
- memcpy(buf, header, header_len);
+ if (nt->release)
+ scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release);
+ memcpy(buf + release_len, header, header_len);
+ header_len += release_len;
while (offset < body_len) {
int this_header = header_len;
diff --git a/drivers/net/netdevsim/Makefile b/drivers/net/netdevsim/Makefile
index 5735e5b1a2cb..f8de93bc5f5b 100644
--- a/drivers/net/netdevsim/Makefile
+++ b/drivers/net/netdevsim/Makefile
@@ -17,3 +17,7 @@ endif
ifneq ($(CONFIG_PSAMPLE),)
netdevsim-objs += psample.o
endif
+
+ifneq ($(CONFIG_MACSEC),)
+netdevsim-objs += macsec.o
+endif
diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
index ffd9f84b6644..bd546d4d26c6 100644
--- a/drivers/net/netdevsim/ethtool.c
+++ b/drivers/net/netdevsim/ethtool.c
@@ -140,6 +140,16 @@ nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
return 0;
}
+static int nsim_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct netdevsim *ns = netdev_priv(dev);
+
+ info->phc_index = mock_phc_index(ns->phc);
+
+ return 0;
+}
+
static const struct ethtool_ops nsim_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS,
.get_pause_stats = nsim_get_pause_stats,
@@ -153,6 +163,7 @@ static const struct ethtool_ops nsim_ethtool_ops = {
.set_channels = nsim_set_channels,
.get_fecparam = nsim_get_fecparam,
.set_fecparam = nsim_set_fecparam,
+ .get_ts_info = nsim_get_ts_info,
};
static void nsim_ethtool_ring_init(struct netdevsim *ns)
diff --git a/drivers/net/netdevsim/macsec.c b/drivers/net/netdevsim/macsec.c
new file mode 100644
index 000000000000..0d5f50430dd3
--- /dev/null
+++ b/drivers/net/netdevsim/macsec.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <net/macsec.h>
+#include "netdevsim.h"
+
+static inline u64 sci_to_cpu(sci_t sci)
+{
+ return be64_to_cpu((__force __be64)sci);
+}
+
+static int nsim_macsec_find_secy(struct netdevsim *ns, sci_t sci)
+{
+ int i;
+
+ for (i = 0; i < NSIM_MACSEC_MAX_SECY_COUNT; i++) {
+ if (ns->macsec.nsim_secy[i].sci == sci)
+ return i;
+ }
+
+ return -1;
+}
+
+static int nsim_macsec_find_rxsc(struct nsim_secy *ns_secy, sci_t sci)
+{
+ int i;
+
+ for (i = 0; i < NSIM_MACSEC_MAX_RXSC_COUNT; i++) {
+ if (ns_secy->nsim_rxsc[i].sci == sci)
+ return i;
+ }
+
+ return -1;
+}
+
+static int nsim_macsec_add_secy(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ if (ns->macsec.nsim_secy_count == NSIM_MACSEC_MAX_SECY_COUNT)
+ return -ENOSPC;
+
+ for (idx = 0; idx < NSIM_MACSEC_MAX_SECY_COUNT; idx++) {
+ if (!ns->macsec.nsim_secy[idx].used)
+ break;
+ }
+
+ if (idx == NSIM_MACSEC_MAX_SECY_COUNT) {
+ netdev_err(ctx->netdev, "%s: nsim_secy_count not full but all SecYs used\n",
+ __func__);
+ return -ENOSPC;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: adding new secy with sci %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->secy->sci), idx);
+ ns->macsec.nsim_secy[idx].used = true;
+ ns->macsec.nsim_secy[idx].nsim_rxsc_count = 0;
+ ns->macsec.nsim_secy[idx].sci = ctx->secy->sci;
+ ns->macsec.nsim_secy_count++;
+
+ return 0;
+}
+
+static int nsim_macsec_upd_secy(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: updating secy with sci %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->secy->sci), idx);
+
+ return 0;
+}
+
+static int nsim_macsec_del_secy(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: removing SecY with SCI %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->secy->sci), idx);
+
+ ns->macsec.nsim_secy[idx].used = false;
+ memset(&ns->macsec.nsim_secy[idx], 0, sizeof(ns->macsec.nsim_secy[idx]));
+ ns->macsec.nsim_secy_count--;
+
+ return 0;
+}
+
+static int nsim_macsec_add_rxsc(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ if (secy->nsim_rxsc_count == NSIM_MACSEC_MAX_RXSC_COUNT)
+ return -ENOSPC;
+
+ for (idx = 0; idx < NSIM_MACSEC_MAX_RXSC_COUNT; idx++) {
+ if (!secy->nsim_rxsc[idx].used)
+ break;
+ }
+
+ if (idx == NSIM_MACSEC_MAX_RXSC_COUNT)
+ netdev_err(ctx->netdev, "%s: nsim_rxsc_count not full but all RXSCs used\n",
+ __func__);
+
+ netdev_dbg(ctx->netdev, "%s: adding new rxsc with sci %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
+ secy->nsim_rxsc[idx].used = true;
+ secy->nsim_rxsc[idx].sci = ctx->rx_sc->sci;
+ secy->nsim_rxsc_count++;
+
+ return 0;
+}
+
+static int nsim_macsec_upd_rxsc(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
+ __func__, sci_to_cpu(ctx->rx_sc->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: updating RXSC with sci %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
+
+ return 0;
+}
+
+static int nsim_macsec_del_rxsc(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
+ __func__, sci_to_cpu(ctx->rx_sc->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: removing RXSC with sci %08llx at index %d\n",
+ __func__, sci_to_cpu(ctx->rx_sc->sci), idx);
+
+ secy->nsim_rxsc[idx].used = false;
+ memset(&secy->nsim_rxsc[idx], 0, sizeof(secy->nsim_rxsc[idx]));
+ secy->nsim_rxsc_count--;
+
+ return 0;
+}
+
+static int nsim_macsec_add_rxsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static int nsim_macsec_upd_rxsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static int nsim_macsec_del_rxsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ struct nsim_secy *secy;
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+ secy = &ns->macsec.nsim_secy[idx];
+
+ idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static int nsim_macsec_add_txsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static int nsim_macsec_upd_txsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static int nsim_macsec_del_txsa(struct macsec_context *ctx)
+{
+ struct netdevsim *ns = netdev_priv(ctx->netdev);
+ int idx;
+
+ idx = nsim_macsec_find_secy(ns, ctx->secy->sci);
+ if (idx < 0) {
+ netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n",
+ __func__, sci_to_cpu(ctx->secy->sci));
+ return -ENOENT;
+ }
+
+ netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n",
+ __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num);
+
+ return 0;
+}
+
+static const struct macsec_ops nsim_macsec_ops = {
+ .mdo_add_secy = nsim_macsec_add_secy,
+ .mdo_upd_secy = nsim_macsec_upd_secy,
+ .mdo_del_secy = nsim_macsec_del_secy,
+ .mdo_add_rxsc = nsim_macsec_add_rxsc,
+ .mdo_upd_rxsc = nsim_macsec_upd_rxsc,
+ .mdo_del_rxsc = nsim_macsec_del_rxsc,
+ .mdo_add_rxsa = nsim_macsec_add_rxsa,
+ .mdo_upd_rxsa = nsim_macsec_upd_rxsa,
+ .mdo_del_rxsa = nsim_macsec_del_rxsa,
+ .mdo_add_txsa = nsim_macsec_add_txsa,
+ .mdo_upd_txsa = nsim_macsec_upd_txsa,
+ .mdo_del_txsa = nsim_macsec_del_txsa,
+};
+
+void nsim_macsec_init(struct netdevsim *ns)
+{
+ ns->netdev->macsec_ops = &nsim_macsec_ops;
+ ns->netdev->features |= NETIF_F_HW_MACSEC;
+ memset(&ns->macsec, 0, sizeof(ns->macsec));
+}
+
+void nsim_macsec_teardown(struct netdevsim *ns)
+{
+}
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 35fa1ca98671..2eac92f49631 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -209,6 +209,31 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
return 0;
}
+static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats)
+{
+ stats->window_drops = 0;
+ stats->tx_overruns = 0;
+}
+
+static int nsim_setup_tc_taprio(struct net_device *dev,
+ struct tc_taprio_qopt_offload *offload)
+{
+ int err = 0;
+
+ switch (offload->cmd) {
+ case TAPRIO_CMD_REPLACE:
+ case TAPRIO_CMD_DESTROY:
+ break;
+ case TAPRIO_CMD_STATS:
+ nsim_taprio_stats(&offload->stats);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
static LIST_HEAD(nsim_block_cb_list);
static int
@@ -217,6 +242,8 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
struct netdevsim *ns = netdev_priv(dev);
switch (type) {
+ case TC_SETUP_QDISC_TAPRIO:
+ return nsim_setup_tc_taprio(dev, type_data);
case TC_SETUP_BLOCK:
return flow_block_cb_setup_simple(type_data,
&nsim_block_cb_list,
@@ -291,19 +318,26 @@ static void nsim_setup(struct net_device *dev)
static int nsim_init_netdevsim(struct netdevsim *ns)
{
+ struct mock_phc *phc;
int err;
+ phc = mock_phc_create(&ns->nsim_bus_dev->dev);
+ if (IS_ERR(phc))
+ return PTR_ERR(phc);
+
+ ns->phc = phc;
ns->netdev->netdev_ops = &nsim_netdev_ops;
err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
if (err)
- return err;
+ goto err_phc_destroy;
rtnl_lock();
err = nsim_bpf_init(ns);
if (err)
goto err_utn_destroy;
+ nsim_macsec_init(ns);
nsim_ipsec_init(ns);
err = register_netdevice(ns->netdev);
@@ -314,10 +348,13 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
err_ipsec_teardown:
nsim_ipsec_teardown(ns);
+ nsim_macsec_teardown(ns);
nsim_bpf_uninit(ns);
err_utn_destroy:
rtnl_unlock();
nsim_udp_tunnels_info_destroy(ns->netdev);
+err_phc_destroy:
+ mock_phc_destroy(ns->phc);
return err;
}
@@ -374,12 +411,14 @@ void nsim_destroy(struct netdevsim *ns)
rtnl_lock();
unregister_netdevice(dev);
if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {
+ nsim_macsec_teardown(ns);
nsim_ipsec_teardown(ns);
nsim_bpf_uninit(ns);
}
rtnl_unlock();
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
nsim_udp_tunnels_info_destroy(dev);
+ mock_phc_destroy(ns->phc);
free_netdev(dev);
}
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 7d8ed8d8df5c..028c825b86db 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -19,10 +19,12 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netdevice.h>
+#include <linux/ptp_mock.h>
#include <linux/u64_stats_sync.h>
#include <net/devlink.h>
#include <net/udp_tunnel.h>
#include <net/xdp.h>
+#include <net/macsec.h>
#define DRV_NAME "netdevsim"
@@ -52,6 +54,25 @@ struct nsim_ipsec {
u32 ok;
};
+#define NSIM_MACSEC_MAX_SECY_COUNT 3
+#define NSIM_MACSEC_MAX_RXSC_COUNT 1
+struct nsim_rxsc {
+ sci_t sci;
+ bool used;
+};
+
+struct nsim_secy {
+ sci_t sci;
+ struct nsim_rxsc nsim_rxsc[NSIM_MACSEC_MAX_RXSC_COUNT];
+ u8 nsim_rxsc_count;
+ bool used;
+};
+
+struct nsim_macsec {
+ struct nsim_secy nsim_secy[NSIM_MACSEC_MAX_SECY_COUNT];
+ u8 nsim_secy_count;
+};
+
struct nsim_ethtool_pauseparam {
bool rx;
bool tx;
@@ -73,6 +94,7 @@ struct netdevsim {
struct net_device *netdev;
struct nsim_dev *nsim_dev;
struct nsim_dev_port *nsim_dev_port;
+ struct mock_phc *phc;
u64 tx_packets;
u64 tx_bytes;
@@ -93,6 +115,7 @@ struct netdevsim {
bool bpf_map_accept;
struct nsim_ipsec ipsec;
+ struct nsim_macsec macsec;
struct {
u32 inject_error;
u32 sleep;
@@ -366,6 +389,19 @@ static inline bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
}
#endif
+#if IS_ENABLED(CONFIG_MACSEC)
+void nsim_macsec_init(struct netdevsim *ns);
+void nsim_macsec_teardown(struct netdevsim *ns);
+#else
+static inline void nsim_macsec_init(struct netdevsim *ns)
+{
+}
+
+static inline void nsim_macsec_teardown(struct netdevsim *ns)
+{
+}
+#endif
+
struct nsim_bus_dev {
struct device dev;
struct list_head list;
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index ea662a7989b2..fb1694192ae6 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers
-pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
+pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c
index 9021b96d4f9d..dc3962b2aa6b 100644
--- a/drivers/net/pcs/pcs-lynx.c
+++ b/drivers/net/pcs/pcs-lynx.c
@@ -216,7 +216,7 @@ static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs,
/* The PCS needs to be configured manually only
* when not operating on in-band mode
*/
- if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED)
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
return;
if (duplex == DUPLEX_HALF)
diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
index b0f3ede945d9..8501dd365279 100644
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -233,11 +233,19 @@ static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs,
}
}
+static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs)
+{
+ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
+
+ mpcs->interface = PHY_INTERFACE_MODE_NA;
+}
+
static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
.pcs_get_state = mtk_pcs_lynxi_get_state,
.pcs_config = mtk_pcs_lynxi_config,
.pcs_an_restart = mtk_pcs_lynxi_restart_an,
.pcs_link_up = mtk_pcs_lynxi_link_up,
+ .pcs_disable = mtk_pcs_lynxi_disable,
};
struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c
index 356099169003..97139c07130f 100644
--- a/drivers/net/pcs/pcs-rzn1-miic.c
+++ b/drivers/net/pcs/pcs-rzn1-miic.c
@@ -12,6 +12,7 @@
#include <linux/of_platform.h>
#include <linux/pcs-rzn1-miic.h>
#include <linux/phylink.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <dt-bindings/net/pcs-rzn1-miic.h>
diff --git a/drivers/net/pcs/pcs-xpcs-wx.c b/drivers/net/pcs/pcs-xpcs-wx.c
new file mode 100644
index 000000000000..19c75886f070
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-wx.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/mdio.h>
+#include "pcs-xpcs.h"
+
+/* VR_XS_PMA_MMD */
+#define TXGBE_PMA_MMD 0x8020
+#define TXGBE_TX_GENCTL1 0x11
+#define TXGBE_TX_GENCTL1_VBOOST_LVL GENMASK(10, 8)
+#define TXGBE_TX_GENCTL1_VBOOST_EN0 BIT(4)
+#define TXGBE_TX_GEN_CTL2 0x12
+#define TXGBE_TX_GEN_CTL2_TX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
+#define TXGBE_TX_RATE_CTL 0x14
+#define TXGBE_TX_RATE_CTL_TX0_RATE(v) FIELD_PREP(GENMASK(2, 0), v)
+#define TXGBE_RX_GEN_CTL2 0x32
+#define TXGBE_RX_GEN_CTL2_RX0_WIDTH(v) FIELD_PREP(GENMASK(9, 8), v)
+#define TXGBE_RX_GEN_CTL3 0x33
+#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0)
+#define TXGBE_RX_RATE_CTL 0x34
+#define TXGBE_RX_RATE_CTL_RX0_RATE(v) FIELD_PREP(GENMASK(1, 0), v)
+#define TXGBE_RX_EQ_ATTN_CTL 0x37
+#define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0)
+#define TXGBE_RX_EQ_CTL0 0x38
+#define TXGBE_RX_EQ_CTL0_VGA1_GAIN(v) FIELD_PREP(GENMASK(15, 12), v)
+#define TXGBE_RX_EQ_CTL0_VGA2_GAIN(v) FIELD_PREP(GENMASK(11, 8), v)
+#define TXGBE_RX_EQ_CTL0_CTLE_POLE(v) FIELD_PREP(GENMASK(7, 5), v)
+#define TXGBE_RX_EQ_CTL0_CTLE_BOOST(v) FIELD_PREP(GENMASK(4, 0), v)
+#define TXGBE_RX_EQ_CTL4 0x3C
+#define TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0 BIT(4)
+#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0)
+#define TXGBE_AFE_DFE_ENABLE 0x3D
+#define TXGBE_DFE_EN_0 BIT(4)
+#define TXGBE_AFE_EN_0 BIT(0)
+#define TXGBE_DFE_TAP_CTL0 0x3E
+#define TXGBE_MPLLA_CTL0 0x51
+#define TXGBE_MPLLA_CTL2 0x53
+#define TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN BIT(10)
+#define TXGBE_MPLLA_CTL2_DIV10_CLK_EN BIT(9)
+#define TXGBE_MPLLA_CTL3 0x57
+#define TXGBE_MISC_CTL0 0x70
+#define TXGBE_MISC_CTL0_PLL BIT(15)
+#define TXGBE_MISC_CTL0_CR_PARA_SEL BIT(14)
+#define TXGBE_MISC_CTL0_RX_VREF(v) FIELD_PREP(GENMASK(12, 8), v)
+#define TXGBE_VCO_CAL_LD0 0x72
+#define TXGBE_VCO_CAL_REF0 0x76
+
+static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg)
+{
+ return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg);
+}
+
+static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)
+{
+ return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);
+}
+
+static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)
+{
+ int val;
+
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);
+ val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
+ val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
+ txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
+ txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
+ TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);
+ txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);
+ txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);
+ txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));
+ txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |
+ TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
+
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |
+ TXGBE_RX_EQ_CTL0_CTLE_BOOST(5));
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
+ val &= ~TXGBE_RX_EQ_ATTN_LVL0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+ txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);
+ val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE);
+ val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0);
+ txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val);
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4);
+ val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val);
+}
+
+static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)
+{
+ int val;
+
+ val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1);
+ val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL);
+ val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0;
+ txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val);
+ txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |
+ TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));
+
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |
+ TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));
+ val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL);
+ val &= ~TXGBE_RX_EQ_ATTN_LVL0;
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+ txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);
+ val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3);
+ val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0);
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val);
+
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);
+ txgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);
+ txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);
+ txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);
+ txgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));
+ txgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));
+ txgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));
+ txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));
+ txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);
+}
+
+static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ /* Wait xpcs power-up good */
+ ret = read_poll_timeout(xpcs_read_vpcs, val,
+ (val & DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,
+ 10000, 1000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_STS);
+ if (ret < 0)
+ dev_err(&xpcs->mdiodev->dev, "xpcs power-up timeout\n");
+
+ return ret;
+}
+
+static int txgbe_pma_init_done(struct dw_xpcs *xpcs)
+{
+ int val, ret;
+
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);
+
+ /* wait pma initialization done */
+ ret = read_poll_timeout(xpcs_read_vpcs, val, !(val & DW_VR_RST),
+ 100000, 10000000, false,
+ xpcs, DW_VR_XS_PCS_DIG_CTRL1);
+ if (ret < 0)
+ dev_err(&xpcs->mdiodev->dev, "xpcs pma initialization timeout\n");
+
+ return ret;
+}
+
+static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)
+{
+ int ret;
+
+ /* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */
+ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);
+ ret &= MDIO_PCS_CTRL2_TYPE;
+ if ((ret == MDIO_PCS_CTRL2_10GBR &&
+ xpcs->interface != PHY_INTERFACE_MODE_10GBASER) ||
+ xpcs->interface == PHY_INTERFACE_MODE_SGMII)
+ return true;
+
+ return false;
+}
+
+int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
+{
+ int val, ret;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ break;
+ default:
+ return 0;
+ }
+
+ if (xpcs->interface == interface && !txgbe_xpcs_mode_quirk(xpcs))
+ return 0;
+
+ xpcs->interface = interface;
+
+ ret = txgbe_pcs_poll_power_up(xpcs);
+ if (ret < 0)
+ return ret;
+
+ if (interface == PHY_INTERFACE_MODE_10GBASER) {
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);
+ val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1);
+ val |= MDIO_CTRL1_SPEED10G;
+ xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val);
+ txgbe_pma_config_10gbaser(xpcs);
+ } else {
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);
+ xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);
+ xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);
+ txgbe_pma_config_1g(xpcs);
+ }
+
+ return txgbe_pma_init_done(xpcs);
+}
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 44b037646865..4dbc21f604f2 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -228,16 +228,39 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
}
-static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
+int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
{
return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
}
-static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
+int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
{
return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
}
+static int xpcs_dev_flag(struct dw_xpcs *xpcs)
+{
+ int ret, oui;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
+ if (ret < 0)
+ return ret;
+
+ oui = ret;
+
+ ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
+ if (ret < 0)
+ return ret;
+
+ ret = (ret >> 10) & 0x3F;
+ oui |= ret << 16;
+
+ if (oui == DW_OUI_WX)
+ xpcs->dev_flag = DW_DEV_TXGBE;
+
+ return 0;
+}
+
static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
{
/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
@@ -660,7 +683,10 @@ EXPORT_SYMBOL_GPL(xpcs_config_eee);
static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
unsigned int neg_mode)
{
- int ret, mdio_ctrl;
+ int ret, mdio_ctrl, tx_conf;
+
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
/* For AN for C37 SGMII mode, the settings are :-
* 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
@@ -697,9 +723,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
DW_VR_MII_PCS_MODE_MASK);
- ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
- DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
- DW_VR_MII_TX_CONFIG_MASK);
+ if (xpcs->dev_flag == DW_DEV_TXGBE) {
+ ret |= DW_VR_MII_AN_CTRL_8BIT;
+ /* Hardware requires it to be PHY side SGMII */
+ tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
+ } else {
+ tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
+ }
+ ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
+ DW_VR_MII_TX_CONFIG_MASK;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
@@ -713,6 +745,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
else
ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
+
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
if (ret < 0)
return ret;
@@ -732,6 +767,9 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
int ret, mdio_ctrl, adv;
bool changed = 0;
+ if (xpcs->dev_flag == DW_DEV_TXGBE)
+ xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1);
+
/* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
* be disabled first:-
* 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
@@ -753,6 +791,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
return ret;
ret &= ~DW_VR_MII_PCS_MODE_MASK;
+ if (!xpcs->pcs.poll)
+ ret |= DW_VR_MII_AN_INTR_EN;
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
if (ret < 0)
return ret;
@@ -818,6 +858,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
if (!compat)
return -ENODEV;
+ if (xpcs->dev_flag == DW_DEV_TXGBE) {
+ ret = txgbe_xpcs_switch_mode(xpcs, interface);
+ if (ret)
+ return ret;
+ }
+
switch (compat->an_mode) {
case DW_10GBASER:
break;
@@ -977,6 +1023,33 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
+ } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+ int speed, duplex;
+
+ state->link = true;
+
+ speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+ if (speed < 0)
+ return speed;
+
+ speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+ if (speed == SGMII_SPEED_SS6)
+ state->speed = SPEED_1000;
+ else if (speed == SGMII_SPEED_SS13)
+ state->speed = SPEED_100;
+ else if (speed == 0)
+ state->speed = SPEED_10;
+
+ duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+ if (duplex < 0)
+ return duplex;
+
+ if (duplex & DW_FULL_DUPLEX)
+ state->duplex = DUPLEX_FULL;
+ else if (duplex & DW_HALF_DUPLEX)
+ state->duplex = DUPLEX_HALF;
+
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
}
return 0;
@@ -1000,6 +1073,17 @@ static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
if (bmsr < 0)
return bmsr;
+ /* Clear AN complete interrupt */
+ if (!xpcs->pcs.poll) {
+ int an_intr;
+
+ an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
+ if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+ an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
+ xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
+ }
+ }
+
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
}
@@ -1284,16 +1368,20 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
goto out;
}
+ ret = xpcs_dev_flag(xpcs);
+ if (ret)
+ goto out;
+
xpcs->pcs.ops = &xpcs_phylink_ops;
xpcs->pcs.neg_mode = true;
- if (compat->an_mode == DW_10GBASER)
- return xpcs;
- xpcs->pcs.poll = true;
+ if (xpcs->dev_flag != DW_DEV_TXGBE) {
+ xpcs->pcs.poll = true;
- ret = xpcs_soft_reset(xpcs, compat);
- if (ret)
- goto out;
+ ret = xpcs_soft_reset(xpcs, compat);
+ if (ret)
+ goto out;
+ }
return xpcs;
}
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 68c6b5a62088..39a90417e535 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -15,8 +15,14 @@
/* VR_XS_PCS */
#define DW_USXGMII_RST BIT(10)
#define DW_USXGMII_EN BIT(9)
+#define DW_VR_XS_PCS_DIG_CTRL1 0x0000
+#define DW_VR_RST BIT(15)
+#define DW_EN_VSMMD1 BIT(13)
+#define DW_CL37_BP BIT(12)
#define DW_VR_XS_PCS_DIG_STS 0x0010
#define DW_RXFIFO_ERR GENMASK(6, 5)
+#define DW_PSEQ_ST GENMASK(4, 2)
+#define DW_PSEQ_ST_GOOD FIELD_PREP(GENMASK(4, 2), 0x4)
/* SR_MII */
#define DW_USXGMII_FULL BIT(8)
@@ -61,12 +67,14 @@
/* VR_MII_DIG_CTRL1 */
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
+#define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL BIT(0)
/* VR_MII_DIG_CTRL2 */
#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_8BIT BIT(8)
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1
@@ -75,8 +83,10 @@
#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
#define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0
#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
+#define DW_VR_MII_AN_INTR_EN BIT(0)
/* VR_MII_AN_INTR_STS */
+#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0)
#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2
#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
@@ -90,6 +100,10 @@
#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */
#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */
+/* SR MII MMD AN Advertisement defines */
+#define DW_HALF_DUPLEX BIT(6)
+#define DW_FULL_DUPLEX BIT(5)
+
/* VR MII EEE Control 0 defines */
#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
@@ -106,6 +120,9 @@
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
+int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg);
+int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val);
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
+int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 78e6981650d9..107880d13d21 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -217,6 +217,12 @@ config MARVELL_10G_PHY
help
Support for the Marvell Alaska MV88X3310 and compatible PHYs.
+config MARVELL_88Q2XXX_PHY
+ tristate "Marvell 88Q2XXX PHY"
+ help
+ Support for the Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet
+ PHYs.
+
config MARVELL_88X2222_PHY
tristate "Marvell 88X2222 PHY"
help
@@ -300,7 +306,7 @@ config NXP_C45_TJA11XX_PHY
depends on PTP_1588_CLOCK_OPTIONAL
help
Enable support for NXP C45 TJA11XX PHYs.
- Currently supports only the TJA1103 PHY.
+ Currently supports the TJA1103 and TJA1120 PHYs.
config NXP_TJA11XX_PHY
tristate "NXP TJA11xx PHYs support"
@@ -344,6 +350,7 @@ config ROCKCHIP_PHY
config SMSC_PHY
tristate "SMSC PHYs"
+ select CRC16
help
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 2fe51ea83bab..c945ed9bd14b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -14,6 +14,8 @@ endif
# dedicated loadable module, so we bundle them all together into libphy.ko
ifdef CONFIG_PHYLIB
libphy-y += $(mdio-bus-y)
+# the stubs are built-in whenever PHYLIB is built-in or module
+obj-y += stubs.o
else
obj-$(CONFIG_MDIO_DEVICE) += mdio-bus.o
endif
@@ -66,6 +68,7 @@ obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o
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
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 8a77ec33b417..37fb033e1c29 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -272,6 +272,13 @@
#define QCA808X_CDT_STATUS_STAT_OPEN 2
#define QCA808X_CDT_STATUS_STAT_SHORT 3
+/* QCA808X 1G chip type */
+#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
+#define QCA808X_PHY_CHIP_TYPE_1G BIT(0)
+
+#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072
+#define QCA8081_PHY_FIFO_RSTN BIT(11)
+
MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
@@ -902,15 +909,6 @@ static int at803x_get_features(struct phy_device *phydev)
if (err)
return err;
- if (phydev->drv->phy_id == QCA8081_PHY_ID) {
- err = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_NG_EXTABLE);
- if (err < 0)
- return err;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported,
- err & MDIO_PMA_NG_EXTABLE_2_5GBT);
- }
-
if (phydev->drv->phy_id != ATH8031_PHY_ID)
return 0;
@@ -1739,24 +1737,30 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
return 0;
}
-static int qca808x_phy_ms_random_seed_set(struct phy_device *phydev)
+static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
{
- u16 seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
+ u16 seed_value;
+
+ if (!enable)
+ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
+ QCA808X_MASTER_SLAVE_SEED_ENABLE, 0);
+ seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE);
return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
- QCA808X_MASTER_SLAVE_SEED_CFG,
- FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value));
+ QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE,
+ FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) |
+ QCA808X_MASTER_SLAVE_SEED_ENABLE);
}
-static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable)
+static bool qca808x_is_prefer_master(struct phy_device *phydev)
{
- u16 seed_enable = 0;
-
- if (enable)
- seed_enable = QCA808X_MASTER_SLAVE_SEED_ENABLE;
+ return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) ||
+ (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED);
+}
- return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED,
- QCA808X_MASTER_SLAVE_SEED_ENABLE, seed_enable);
+static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev)
+{
+ return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
}
static int qca808x_config_init(struct phy_device *phydev)
@@ -1775,20 +1779,25 @@ static int qca808x_config_init(struct phy_device *phydev)
if (ret)
return ret;
- /* Config the fast retrain for the link 2500M */
- ret = qca808x_phy_fast_retrain_config(phydev);
- if (ret)
- return ret;
+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
+ /* Config the fast retrain for the link 2500M */
+ ret = qca808x_phy_fast_retrain_config(phydev);
+ if (ret)
+ return ret;
- /* Configure lower ramdom seed to make phy linked as slave mode */
- ret = qca808x_phy_ms_random_seed_set(phydev);
- if (ret)
- return ret;
+ ret = genphy_read_master_slave(phydev);
+ if (ret < 0)
+ return ret;
- /* Enable seed */
- ret = qca808x_phy_ms_seed_enable(phydev, true);
- if (ret)
- return ret;
+ if (!qca808x_is_prefer_master(phydev)) {
+ /* Enable seed and configure lower ramdom seed to make phy
+ * linked as slave mode.
+ */
+ ret = qca808x_phy_ms_seed_enable(phydev, true);
+ if (ret)
+ return ret;
+ }
+ }
/* Configure adc threshold as 100mv for the link 10M */
return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
@@ -1821,17 +1830,21 @@ static int qca808x_read_status(struct phy_device *phydev)
phydev->interface = PHY_INTERFACE_MODE_SGMII;
} else {
/* generate seed as a lower random value to make PHY linked as SLAVE easily,
- * except for master/slave configuration fault detected.
+ * except for master/slave configuration fault detected or the master mode
+ * preferred.
+ *
* the reason for not putting this code into the function link_change_notify is
* the corner case where the link partner is also the qca8081 PHY and the seed
* value is configured as the same value, the link can't be up and no link change
* occurs.
*/
- if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) {
- qca808x_phy_ms_seed_enable(phydev, false);
- } else {
- qca808x_phy_ms_random_seed_set(phydev);
- qca808x_phy_ms_seed_enable(phydev, true);
+ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
+ if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
+ qca808x_is_prefer_master(phydev)) {
+ qca808x_phy_ms_seed_enable(phydev, false);
+ } else {
+ qca808x_phy_ms_seed_enable(phydev, true);
+ }
}
}
@@ -1846,7 +1859,10 @@ static int qca808x_soft_reset(struct phy_device *phydev)
if (ret < 0)
return ret;
- return qca808x_phy_ms_seed_enable(phydev, true);
+ if (qca808x_has_fast_retrain_or_slave_seed(phydev))
+ ret = qca808x_phy_ms_seed_enable(phydev, true);
+
+ return ret;
}
static bool qca808x_cdt_fault_length_valid(int cdt_code)
@@ -1996,6 +2012,44 @@ static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finish
return 0;
}
+static int qca808x_get_features(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_c45_pma_read_abilities(phydev);
+ if (ret)
+ return ret;
+
+ /* The autoneg ability is not existed in bit3 of MMD7.1,
+ * but it is supported by qca808x PHY, so we add it here
+ * manually.
+ */
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
+
+ /* As for the qca8081 1G version chip, the 2500baseT ability is also
+ * existed in the bit0 of MMD1.21, we need to remove it manually if
+ * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
+ */
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE);
+ if (ret < 0)
+ return ret;
+
+ if (QCA808X_PHY_CHIP_TYPE_1G & ret)
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
+
+ return 0;
+}
+
+static void qca808x_link_change_notify(struct phy_device *phydev)
+{
+ /* Assert interface sgmii fifo on link down, deassert it on link up,
+ * the interface device address is always phy address added by 1.
+ */
+ mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
+ QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
+}
+
static struct phy_driver at803x_driver[] = {
{
/* Qualcomm Atheros AR8035 */
@@ -2163,7 +2217,7 @@ static struct phy_driver at803x_driver[] = {
.set_tunable = at803x_set_tunable,
.set_wol = at803x_set_wol,
.get_wol = at803x_get_wol,
- .get_features = at803x_get_features,
+ .get_features = qca808x_get_features,
.config_aneg = at803x_config_aneg,
.suspend = genphy_suspend,
.resume = genphy_resume,
@@ -2172,6 +2226,7 @@ static struct phy_driver at803x_driver[] = {
.soft_reset = qca808x_soft_reset,
.cable_test_start = qca808x_cable_test_start,
.cable_test_get_status = qca808x_cable_test_get_status,
+ .link_change_notify = qca808x_link_change_notify,
}, };
module_phy_driver(at803x_driver);
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index f8c17a253f8b..8478b081c058 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -913,6 +913,7 @@ static struct phy_driver bcm7xxx_driver[] = {
BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
+ BCM7XXX_16NM_EPHY(PHY_ID_BCM74165, "Broadcom BCM74165"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM74371, "Broadcom BCM74371"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index ef8b14135133..2657be7cc049 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -631,7 +631,6 @@ static void recalibrate(struct dp83640_clock *clock)
s64 now, diff;
struct phy_txts event_ts;
struct timespec64 ts;
- struct list_head *this;
struct dp83640_private *tmp;
struct phy_device *master = clock->chosen->phydev;
u16 cal_gpio, cfg0, evnt, ptp_trig, trigger, val;
@@ -648,8 +647,7 @@ static void recalibrate(struct dp83640_clock *clock)
/*
* enable broadcast, disable status frames, enable ptp clock
*/
- list_for_each(this, &clock->phylist) {
- tmp = list_entry(this, struct dp83640_private, list);
+ list_for_each_entry(tmp, &clock->phylist, list) {
enable_broadcast(tmp->phydev, clock->page, 1);
tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0);
ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0);
@@ -667,10 +665,8 @@ static void recalibrate(struct dp83640_clock *clock)
evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
- list_for_each(this, &clock->phylist) {
- tmp = list_entry(this, struct dp83640_private, list);
+ list_for_each_entry(tmp, &clock->phylist, list)
ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt);
- }
ext_write(0, master, PAGE5, PTP_EVNT, evnt);
/*
@@ -709,8 +705,7 @@ static void recalibrate(struct dp83640_clock *clock)
event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA);
now = phy2txts(&event_ts);
- list_for_each(this, &clock->phylist) {
- tmp = list_entry(this, struct dp83640_private, list);
+ list_for_each_entry(tmp, &clock->phylist, list) {
val = ext_read(tmp->phydev, PAGE4, PTP_STS);
phydev_info(tmp->phydev, "slave PTP_STS 0x%04hx\n", val);
val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
@@ -730,10 +725,8 @@ static void recalibrate(struct dp83640_clock *clock)
/*
* restore status frames
*/
- list_for_each(this, &clock->phylist) {
- tmp = list_entry(this, struct dp83640_private, list);
+ list_for_each_entry(tmp, &clock->phylist, list)
ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0);
- }
ext_write(0, master, PAGE5, PSF_CFG0, cfg0);
mutex_unlock(&clock->extreg_lock);
diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c
new file mode 100644
index 000000000000..1c3ff77de56b
--- /dev/null
+++ b/drivers/net/phy/marvell-88q2xxx.c
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
+ */
+#include <linux/ethtool_netlink.h>
+#include <linux/marvell_phy.h>
+#include <linux/phy.h>
+
+#define MDIO_MMD_AN_MV_STAT 32769
+#define MDIO_MMD_AN_MV_STAT_ANEG 0x0100
+#define MDIO_MMD_AN_MV_STAT_LOCAL_RX 0x1000
+#define MDIO_MMD_AN_MV_STAT_REMOTE_RX 0x2000
+#define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER 0x4000
+#define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000
+
+#define MDIO_MMD_PCS_MV_100BT1_STAT1 33032
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00FF
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK 0x0200
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX 0x1000
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX 0x2000
+#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER 0x4000
+
+#define MDIO_MMD_PCS_MV_100BT1_STAT2 33033
+#define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER 0x0001
+#define MDIO_MMD_PCS_MV_100BT1_STAT2_POL 0x0002
+#define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004
+#define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008
+
+static int mv88q2xxx_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+ int val;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
+ MDIO_PCS_1000BT1_CTRL, MDIO_PCS_1000BT1_CTRL_RESET);
+ if (ret < 0)
+ return ret;
+
+ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
+ MDIO_PCS_1000BT1_CTRL, val,
+ !(val & MDIO_PCS_1000BT1_CTRL_RESET),
+ 50000, 600000, true);
+}
+
+static int mv88q2xxx_read_link_gbit(struct phy_device *phydev)
+{
+ int ret;
+ bool link = false;
+
+ /* Read vendor specific Auto-Negotiation status register to get local
+ * and remote receiver status according to software initialization
+ * guide.
+ */
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_MMD_AN_MV_STAT);
+ if (ret < 0) {
+ return ret;
+ } else if ((ret & MDIO_MMD_AN_MV_STAT_LOCAL_RX) &&
+ (ret & MDIO_MMD_AN_MV_STAT_REMOTE_RX)) {
+ /* The link state is latched low so that momentary link
+ * drops can be detected. Do not double-read the status
+ * in polling mode to detect such short link drops except
+ * the link was already down.
+ */
+ if (!phy_polling_mode(phydev) || !phydev->link) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT);
+ if (ret < 0)
+ return ret;
+ else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
+ link = true;
+ }
+
+ if (!link) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_STAT);
+ if (ret < 0)
+ return ret;
+ else if (ret & MDIO_PCS_1000BT1_STAT_LINK)
+ link = true;
+ }
+ }
+
+ phydev->link = link;
+
+ return 0;
+}
+
+static int mv88q2xxx_read_link_100m(struct phy_device *phydev)
+{
+ int ret;
+
+ /* The link state is latched low so that momentary link
+ * drops can be detected. Do not double-read the status
+ * in polling mode to detect such short link drops except
+ * the link was already down. In case we are not polling,
+ * we always read the realtime status.
+ */
+ if (!phy_polling_mode(phydev) || !phydev->link) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
+ if (ret < 0)
+ return ret;
+ else if (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK)
+ goto out;
+ }
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_MMD_PCS_MV_100BT1_STAT1);
+ if (ret < 0)
+ return ret;
+
+out:
+ /* Check if we have link and if the remote and local receiver are ok */
+ if ((ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LINK) &&
+ (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX) &&
+ (ret & MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX))
+ phydev->link = true;
+ else
+ phydev->link = false;
+
+ return 0;
+}
+
+static int mv88q2xxx_read_link(struct phy_device *phydev)
+{
+ int ret;
+
+ /* The 88Q2XXX PHYs do not have the PMA/PMD status register available,
+ * therefore we need to read the link status from the vendor specific
+ * registers depending on the speed.
+ */
+ if (phydev->speed == SPEED_1000)
+ ret = mv88q2xxx_read_link_gbit(phydev);
+ else
+ ret = mv88q2xxx_read_link_100m(phydev);
+
+ return ret;
+}
+
+static int mv88q2xxx_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = mv88q2xxx_read_link(phydev);
+ if (ret < 0)
+ return ret;
+
+ return genphy_c45_read_pma(phydev);
+}
+
+static int mv88q2xxx_get_features(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_c45_pma_read_abilities(phydev);
+ if (ret)
+ return ret;
+
+ /* We need to read the baset1 extended abilities manually because the
+ * PHY does not signalize it has the extended abilities register
+ * available.
+ */
+ ret = genphy_c45_pma_baset1_read_abilities(phydev);
+ if (ret)
+ return ret;
+
+ /* The PHY signalizes it supports autonegotiation. Unfortunately, so
+ * far it was not possible to get a link even when following the init
+ * sequence provided by Marvell. Disable it for now until a proper
+ * workaround is found or a new PHY revision is released.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
+
+ return 0;
+}
+
+static int mv88q2xxx_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_c45_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ return mv88q2xxx_soft_reset(phydev);
+}
+
+static int mv88q2xxx_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ /* The 88Q2XXX PHYs do have the extended ability register available, but
+ * register MDIO_PMA_EXTABLE where they should signalize it does not
+ * work according to specification. Therefore, we force it here.
+ */
+ phydev->pma_extable = MDIO_PMA_EXTABLE_BT1;
+
+ /* Read the current PHY configuration */
+ ret = genphy_c45_read_pma(phydev);
+ if (ret)
+ return ret;
+
+ return mv88q2xxx_config_aneg(phydev);
+}
+
+static int mv88q2xxxx_get_sqi(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->speed == SPEED_100) {
+ /* Read the SQI from the vendor specific receiver status
+ * register
+ */
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x8230);
+ if (ret < 0)
+ return ret;
+
+ ret = ret >> 12;
+ } else {
+ /* Read from vendor specific registers, they are not documented
+ * but can be found in the Software Initialization Guide. Only
+ * revisions >= A0 are supported.
+ */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 0xFC5D, 0x00FF, 0x00AC);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, 0xfc88);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret & 0x0F;
+}
+
+static int mv88q2xxxx_get_sqi_max(struct phy_device *phydev)
+{
+ return 15;
+}
+
+static struct phy_driver mv88q2xxx_driver[] = {
+ {
+ .phy_id = MARVELL_PHY_ID_88Q2110,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "mv88q2110",
+ .get_features = mv88q2xxx_get_features,
+ .config_aneg = mv88q2xxx_config_aneg,
+ .config_init = mv88q2xxx_config_init,
+ .read_status = mv88q2xxx_read_status,
+ .soft_reset = mv88q2xxx_soft_reset,
+ .set_loopback = genphy_c45_loopback,
+ .get_sqi = mv88q2xxxx_get_sqi,
+ .get_sqi_max = mv88q2xxxx_get_sqi_max,
+ },
+};
+
+module_phy_driver(mv88q2xxx_driver);
+
+static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = {
+ { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK },
+ { /*sentinel*/ }
+};
+MODULE_DEVICE_TABLE(mdio, mv88q2xxx_tbl);
+
+MODULE_DESCRIPTION("Marvell 88Q2XXX 100/1000BASE-T1 Automotive Ethernet PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c
index f83cae64585d..e3aa30dad2e6 100644
--- a/drivers/net/phy/marvell-88x2222.c
+++ b/drivers/net/phy/marvell-88x2222.c
@@ -14,7 +14,6 @@
#include <linux/mdio.h>
#include <linux/marvell_phy.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/sfp.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 43b6cb725551..eba652a4c1d8 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2893,6 +2893,272 @@ static int m88e1318_led_blink_set(struct phy_device *phydev, u8 index,
MII_88E1318S_PHY_LED_FUNC, reg);
}
+struct marvell_led_rules {
+ int mode;
+ unsigned long rules;
+};
+
+static const struct marvell_led_rules marvell_led0[] = {
+ {
+ .mode = 0,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 5,
+ .rules = BIT(TRIGGER_NETDEV_TX),
+ },
+ {
+ .mode = 6,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_1000),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static const struct marvell_led_rules marvell_led1[] = {
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 2,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 6,
+ .rules = (BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000)),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_100),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static const struct marvell_led_rules marvell_led2[] = {
+ {
+ .mode = 0,
+ .rules = BIT(TRIGGER_NETDEV_LINK),
+ },
+ {
+ .mode = 1,
+ .rules = (BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 3,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 4,
+ .rules = (BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX)),
+ },
+ {
+ .mode = 5,
+ .rules = BIT(TRIGGER_NETDEV_TX),
+ },
+ {
+ .mode = 6,
+ .rules = (BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_1000)),
+ },
+ {
+ .mode = 7,
+ .rules = BIT(TRIGGER_NETDEV_LINK_10),
+ },
+ {
+ .mode = 8,
+ .rules = 0,
+ },
+};
+
+static int marvell_find_led_mode(unsigned long rules,
+ const struct marvell_led_rules *marvell_rules,
+ int count,
+ int *mode)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (marvell_rules[i].rules == rules) {
+ *mode = marvell_rules[i].mode;
+ return 0;
+ }
+ }
+ return -EOPNOTSUPP;
+}
+
+static int marvell_get_led_mode(u8 index, unsigned long rules, int *mode)
+{
+ int ret;
+
+ switch (index) {
+ case 0:
+ ret = marvell_find_led_mode(rules, marvell_led0,
+ ARRAY_SIZE(marvell_led0), mode);
+ break;
+ case 1:
+ ret = marvell_find_led_mode(rules, marvell_led1,
+ ARRAY_SIZE(marvell_led1), mode);
+ break;
+ case 2:
+ ret = marvell_find_led_mode(rules, marvell_led2,
+ ARRAY_SIZE(marvell_led2), mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int marvell_find_led_rules(unsigned long *rules,
+ const struct marvell_led_rules *marvell_rules,
+ int count,
+ int mode)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (marvell_rules[i].mode == mode) {
+ *rules = marvell_rules[i].rules;
+ return 0;
+ }
+ }
+ return -EOPNOTSUPP;
+}
+
+static int marvell_get_led_rules(u8 index, unsigned long *rules, int mode)
+{
+ int ret;
+
+ switch (index) {
+ case 0:
+ ret = marvell_find_led_rules(rules, marvell_led0,
+ ARRAY_SIZE(marvell_led0), mode);
+ break;
+ case 1:
+ ret = marvell_find_led_rules(rules, marvell_led1,
+ ARRAY_SIZE(marvell_led1), mode);
+ break;
+ case 2:
+ ret = marvell_find_led_rules(rules, marvell_led2,
+ ARRAY_SIZE(marvell_led2), mode);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int m88e1318_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int mode, ret;
+
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ ret = marvell_get_led_mode(index, rules, &mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int m88e1318_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ int mode, ret, reg;
+
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ ret = marvell_get_led_mode(index, rules, &mode);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC);
+ if (reg < 0)
+ return reg;
+
+ reg &= ~(0xf << (4 * index));
+ reg |= mode << (4 * index);
+ return phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC, reg);
+}
+
+static int m88e1318_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ int mode, reg;
+
+ if (index > 2)
+ return -EINVAL;
+
+ reg = phy_read_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_FUNC);
+ if (reg < 0)
+ return reg;
+
+ mode = (reg >> (4 * index)) & 0xf;
+
+ return marvell_get_led_rules(index, rules, mode);
+}
+
static int marvell_probe(struct phy_device *phydev)
{
struct marvell_priv *priv;
@@ -3144,6 +3410,9 @@ static struct phy_driver marvell_drivers[] = {
.get_stats = marvell_get_stats,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1145,
@@ -3252,6 +3521,9 @@ static struct phy_driver marvell_drivers[] = {
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1540,
@@ -3280,6 +3552,9 @@ static struct phy_driver marvell_drivers[] = {
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E1545,
@@ -3308,6 +3583,9 @@ static struct phy_driver marvell_drivers[] = {
.cable_test_get_status = marvell_vct7_cable_test_get_status,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
{
.phy_id = MARVELL_PHY_ID_88E3016,
@@ -3451,6 +3729,9 @@ static struct phy_driver marvell_drivers[] = {
.set_tunable = m88e1540_set_tunable,
.led_brightness_set = m88e1318_led_brightness_set,
.led_blink_set = m88e1318_led_blink_set,
+ .led_hw_is_supported = m88e1318_led_hw_is_supported,
+ .led_hw_control_set = m88e1318_led_hw_control_set,
+ .led_hw_control_get = m88e1318_led_hw_control_get,
},
};
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 8b3618d3da4a..25dcaa49ab8b 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -107,16 +107,21 @@ int mdiobus_unregister_device(struct mdio_device *mdiodev)
}
EXPORT_SYMBOL(mdiobus_unregister_device);
-struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
+static struct mdio_device *mdiobus_find_device(struct mii_bus *bus, int addr)
{
bool addr_valid = addr >= 0 && addr < ARRAY_SIZE(bus->mdio_map);
- struct mdio_device *mdiodev;
if (WARN_ONCE(!addr_valid, "addr %d out of range\n", addr))
return NULL;
- mdiodev = bus->mdio_map[addr];
+ return bus->mdio_map[addr];
+}
+
+struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
+{
+ struct mdio_device *mdiodev;
+ mdiodev = mdiobus_find_device(bus, addr);
if (!mdiodev)
return NULL;
@@ -129,7 +134,7 @@ EXPORT_SYMBOL(mdiobus_get_phy);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
{
- return bus->mdio_map[addr];
+ return mdiobus_find_device(bus, addr) != NULL;
}
EXPORT_SYMBOL(mdiobus_is_registered_device);
@@ -1210,6 +1215,26 @@ int mdiobus_c45_write_nested(struct mii_bus *bus, int addr, int devad,
}
EXPORT_SYMBOL(mdiobus_c45_write_nested);
+/*
+ * __mdiobus_modify - Convenience function for modifying a given mdio device
+ * register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @mask: bit mask of bits to clear
+ * @set: bit mask of bits to set
+ */
+int __mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
+ u16 set)
+{
+ int err;
+
+ err = __mdiobus_modify_changed(bus, addr, regnum, mask, set);
+
+ return err < 0 ? err : 0;
+}
+EXPORT_SYMBOL_GPL(__mdiobus_modify);
+
/**
* mdiobus_modify - Convenience function for modifying a given mdio device
* register
@@ -1224,10 +1249,10 @@ int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set)
int err;
mutex_lock(&bus->mdio_lock);
- err = __mdiobus_modify_changed(bus, addr, regnum, mask, set);
+ err = __mdiobus_modify(bus, addr, regnum, mask, set);
mutex_unlock(&bus->mdio_lock);
- return err < 0 ? err : 0;
+ return err;
}
EXPORT_SYMBOL_GPL(mdiobus_modify);
diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c
index 95369171a7ba..8a20d9889f10 100644
--- a/drivers/net/phy/mediatek-ge-soc.c
+++ b/drivers/net/phy/mediatek-ge-soc.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/phy.h>
+#include <linux/regmap.h>
#define MTK_GPHY_ID_MT7981 0x03a29461
#define MTK_GPHY_ID_MT7988 0x03a29481
@@ -208,9 +209,42 @@
#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f
#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_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_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
#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0)
+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
+#define RG_GPIO_MISC_TPBANK0 0x6f0
+#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8)
+
/* These macro privides efuse parsing for internal phy. */
#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0))
#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0))
@@ -238,13 +272,6 @@ enum {
PAIR_D,
};
-enum {
- GPHY_PORT0,
- GPHY_PORT1,
- GPHY_PORT2,
- GPHY_PORT3,
-};
-
enum calibration_mode {
EFUSE_K,
SW_K
@@ -263,6 +290,19 @@ 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);
@@ -1073,6 +1113,371 @@ 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;
+
+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+ blinking = true;
+ *delay_on = 50;
+ *delay_off = 50;
+ }
+
+ err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+ if (err)
+ return err;
+
+ return mt798x_phy_hw_led_on_set(phydev, index, false);
+}
+
+static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+ u8 index, enum led_brightness value)
+{
+ int err;
+
+ err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+ if (err)
+ return err;
+
+ return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+}
+
+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+ BIT(TRIGGER_NETDEV_LINK) |
+ BIT(TRIGGER_NETDEV_LINK_10) |
+ BIT(TRIGGER_NETDEV_LINK_100) |
+ BIT(TRIGGER_NETDEV_LINK_1000) |
+ BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX));
+
+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;
+};
+
+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_LINK1000 | MTK_PHY_LED_ON_LINK100 |
+ MTK_PHY_LED_ON_LINK10)) ||
+ (blink & (MTK_PHY_LED_BLINK_1000RX | MTK_PHY_LED_BLINK_100RX |
+ MTK_PHY_LED_BLINK_10RX | MTK_PHY_LED_BLINK_1000TX |
+ MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_10TX)))
+ 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_LINK1000 | MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK10))
+ *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_1000RX | MTK_PHY_LED_BLINK_100RX | MTK_PHY_LED_BLINK_10RX))
+ *rules |= BIT(TRIGGER_NETDEV_RX);
+
+ if (blink & (MTK_PHY_LED_BLINK_1000TX | MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_10TX))
+ *rules |= BIT(TRIGGER_NETDEV_TX);
+
+ return 0;
+};
+
+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 |= MTK_PHY_LED_BLINK_10RX |
+ MTK_PHY_LED_BLINK_100RX |
+ MTK_PHY_LED_BLINK_1000RX;
+ }
+
+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
+ blink |= MTK_PHY_LED_BLINK_10TX |
+ MTK_PHY_LED_BLINK_100TX |
+ MTK_PHY_LED_BLINK_1000TX;
+ }
+
+ 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_LINK10 |
+ MTK_PHY_LED_ON_LINK100 |
+ MTK_PHY_LED_ON_LINK1000,
+ 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);
+};
+
+static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
+{
+ struct mtk_socphy_shared *priv = phydev->shared->priv;
+ u32 polarities;
+
+ if (led_num == 0)
+ polarities = ~(priv->boottrap);
+ else
+ polarities = MTK_PHY_LED1_DEFAULT_POLARITIES;
+
+ if (polarities & BIT(phydev->mdio.addr))
+ return true;
+
+ return false;
+}
+
+static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev)
+{
+ struct pinctrl *pinctrl;
+ int index;
+
+ /* Setup LED polarity according to bootstrap use of LED pins */
+ for (index = 0; index < 2; ++index)
+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_POLARITY,
+ mt7988_phy_led_get_polarity(phydev, index) ?
+ MTK_PHY_LED_ON_POLARITY : 0);
+
+ /* Only now setup pinctrl to avoid bogus blinking */
+ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+ if (IS_ERR(pinctrl))
+ dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n");
+
+ return 0;
+}
+
+static int mt7988_phy_probe_shared(struct phy_device *phydev)
+{
+ struct device_node *np = dev_of_node(&phydev->mdio.bus->dev);
+ struct mtk_socphy_shared *shared = phydev->shared->priv;
+ struct regmap *regmap;
+ u32 reg;
+ int ret;
+
+ /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B,
+ * LED_C and LED_D respectively. At the same time those pins are used to
+ * bootstrap configuration of the reference clock source (LED_A),
+ * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D).
+ * In practise this is done using a LED and a resistor pulling the pin
+ * either to GND or to VIO.
+ * The detected value at boot time is accessible at run-time using the
+ * TPBANK0 register located in the gpio base of the pinctrl, in order
+ * to read it here it needs to be referenced by a phandle called
+ * 'mediatek,pio' in the MDIO bus hosting the PHY.
+ * The 4 bits in TPBANK0 are kept as package shared data and are used to
+ * set LED polarity for each of the LED0.
+ */
+ regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, &reg);
+ if (ret)
+ return ret;
+
+ shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg);
+
+ 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;
+ struct mtk_socphy_priv *priv;
+ int err;
+
+ if (phydev->mdio.addr > 3)
+ return -EINVAL;
+
+ err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
+ sizeof(struct mtk_socphy_shared));
+ if (err)
+ return err;
+
+ if (phy_package_probe_once(phydev)) {
+ err = mt7988_phy_probe_shared(phydev);
+ if (err)
+ return err;
+ }
+
+ shared = phydev->shared->priv;
+ priv = &shared->priv[phydev->mdio.addr];
+
+ phydev->priv = priv;
+
+ mt798x_phy_leds_state_init(phydev);
+
+ err = mt7988_phy_fix_leds_polarities(phydev);
+ if (err)
+ return err;
+
+ return mt798x_phy_calibration(phydev);
+}
+
+static int mt7981_phy_probe(struct phy_device *phydev)
+{
+ struct mtk_socphy_priv *priv;
+
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ mt798x_phy_leds_state_init(phydev);
+
+ return mt798x_phy_calibration(phydev);
+}
+
static struct phy_driver mtk_socphy_driver[] = {
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
@@ -1080,11 +1485,16 @@ static struct phy_driver mtk_socphy_driver[] = {
.config_init = mt798x_phy_config_init,
.config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .probe = mt798x_phy_calibration,
+ .probe = mt7981_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = mtk_socphy_read_page,
.write_page = mtk_socphy_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,
+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
},
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988),
@@ -1092,11 +1502,16 @@ static struct phy_driver mtk_socphy_driver[] = {
.config_init = mt798x_phy_config_init,
.config_intr = genphy_no_config_intr,
.handle_interrupt = genphy_handle_interrupt_no_ack,
- .probe = mt798x_phy_calibration,
+ .probe = mt7988_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = mtk_socphy_read_page,
.write_page = mtk_socphy_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,
+ .led_hw_control_set = mt798x_phy_led_hw_control_set,
+ .led_hw_control_get = mt798x_phy_led_hw_control_get,
},
};
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index 2fa5a90e073b..7a11fdb687cc 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -163,6 +163,10 @@
#define YT8521_CHIP_CONFIG_REG 0xA001
#define YT8521_CCR_SW_RST BIT(15)
+#define YT8531_RGMII_LDO_VOL_MASK GENMASK(5, 4)
+#define YT8531_LDO_VOL_3V3 0x0
+#define YT8531_LDO_VOL_1V8 0x2
+
/* 1b0 disable 1.9ns rxc clock delay *default*
* 1b1 enable 1.9ns rxc clock delay
*/
@@ -236,6 +240,12 @@
*/
#define YTPHY_WCR_TYPE_PULSE BIT(0)
+#define YTPHY_PAD_DRIVE_STRENGTH_REG 0xA010
+#define YT8531_RGMII_RXC_DS_MASK GENMASK(15, 13)
+#define YT8531_RGMII_RXD_DS_HI_MASK BIT(12) /* Bit 2 of rxd_ds */
+#define YT8531_RGMII_RXD_DS_LOW_MASK GENMASK(5, 4) /* Bit 1/0 of rxd_ds */
+#define YT8531_RGMII_RX_DS_DEFAULT 0x3
+
#define YTPHY_SYNCE_CFG_REG 0xA012
#define YT8521_SCR_SYNCE_ENABLE BIT(5)
/* 1b0 output 25m clock
@@ -835,6 +845,110 @@ static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev)
}
/**
+ * struct ytphy_ldo_vol_map - map a current value to a register value
+ * @vol: ldo voltage
+ * @ds: value in the register
+ * @cur: value in device configuration
+ */
+struct ytphy_ldo_vol_map {
+ u32 vol;
+ u32 ds;
+ u32 cur;
+};
+
+static const struct ytphy_ldo_vol_map yt8531_ldo_vol[] = {
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 0, .cur = 1200},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 1, .cur = 2100},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 2, .cur = 2700},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 3, .cur = 2910},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 4, .cur = 3110},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 5, .cur = 3600},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 6, .cur = 3970},
+ {.vol = YT8531_LDO_VOL_1V8, .ds = 7, .cur = 4350},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 0, .cur = 3070},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 1, .cur = 4080},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 2, .cur = 4370},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 3, .cur = 4680},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 4, .cur = 5020},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 5, .cur = 5450},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 6, .cur = 5740},
+ {.vol = YT8531_LDO_VOL_3V3, .ds = 7, .cur = 6140},
+};
+
+static u32 yt8531_get_ldo_vol(struct phy_device *phydev)
+{
+ u32 val;
+
+ val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
+ val = FIELD_GET(YT8531_RGMII_LDO_VOL_MASK, val);
+
+ return val <= YT8531_LDO_VOL_1V8 ? val : YT8531_LDO_VOL_1V8;
+}
+
+static int yt8531_get_ds_map(struct phy_device *phydev, u32 cur)
+{
+ u32 vol;
+ int i;
+
+ vol = yt8531_get_ldo_vol(phydev);
+ for (i = 0; i < ARRAY_SIZE(yt8531_ldo_vol); i++) {
+ if (yt8531_ldo_vol[i].vol == vol && yt8531_ldo_vol[i].cur == cur)
+ return yt8531_ldo_vol[i].ds;
+ }
+
+ return -EINVAL;
+}
+
+static int yt8531_set_ds(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ u32 ds_field_low, ds_field_hi, val;
+ int ret, ds;
+
+ /* set rgmii rx clk driver strength */
+ if (!of_property_read_u32(node, "motorcomm,rx-clk-drv-microamp", &val)) {
+ ds = yt8531_get_ds_map(phydev, val);
+ if (ds < 0)
+ return dev_err_probe(&phydev->mdio.dev, ds,
+ "No matching current value was found.\n");
+ } else {
+ ds = YT8531_RGMII_RX_DS_DEFAULT;
+ }
+
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YTPHY_PAD_DRIVE_STRENGTH_REG,
+ YT8531_RGMII_RXC_DS_MASK,
+ FIELD_PREP(YT8531_RGMII_RXC_DS_MASK, ds));
+ if (ret < 0)
+ return ret;
+
+ /* set rgmii rx data driver strength */
+ if (!of_property_read_u32(node, "motorcomm,rx-data-drv-microamp", &val)) {
+ ds = yt8531_get_ds_map(phydev, val);
+ if (ds < 0)
+ return dev_err_probe(&phydev->mdio.dev, ds,
+ "No matching current value was found.\n");
+ } else {
+ ds = YT8531_RGMII_RX_DS_DEFAULT;
+ }
+
+ ds_field_hi = FIELD_GET(BIT(2), ds);
+ ds_field_hi = FIELD_PREP(YT8531_RGMII_RXD_DS_HI_MASK, ds_field_hi);
+
+ ds_field_low = FIELD_GET(GENMASK(1, 0), ds);
+ ds_field_low = FIELD_PREP(YT8531_RGMII_RXD_DS_LOW_MASK, ds_field_low);
+
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YTPHY_PAD_DRIVE_STRENGTH_REG,
+ YT8531_RGMII_RXD_DS_LOW_MASK | YT8531_RGMII_RXD_DS_HI_MASK,
+ ds_field_low | ds_field_hi);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
* yt8521_probe() - read chip config then set suitable polling_mode
* @phydev: a pointer to a &struct phy_device
*
@@ -1518,6 +1632,10 @@ static int yt8531_config_init(struct phy_device *phydev)
return ret;
}
+ ret = yt8531_set_ds(phydev);
+ if (ret < 0)
+ return ret;
+
return 0;
}
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 029875a59ff8..7ab080ff02df 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -18,24 +18,37 @@
#include <linux/net_tstamp.h>
#define PHY_ID_TJA_1103 0x001BB010
-
-#define PMAPMD_B100T1_PMAPMD_CTL 0x0834
-#define B100T1_PMAPMD_CONFIG_EN BIT(15)
-#define B100T1_PMAPMD_MASTER BIT(14)
-#define MASTER_MODE (B100T1_PMAPMD_CONFIG_EN | \
- B100T1_PMAPMD_MASTER)
-#define SLAVE_MODE (B100T1_PMAPMD_CONFIG_EN)
+#define PHY_ID_TJA_1120 0x001BB031
#define VEND1_DEVICE_CONTROL 0x0040
#define DEVICE_CONTROL_RESET BIT(15)
#define DEVICE_CONTROL_CONFIG_GLOBAL_EN BIT(14)
#define DEVICE_CONTROL_CONFIG_ALL_EN BIT(13)
+#define VEND1_DEVICE_CONFIG 0x0048
+
+#define TJA1120_VEND1_EXT_TS_MODE 0x1012
+
+#define TJA1120_GLOBAL_INFRA_IRQ_ACK 0x2C08
+#define TJA1120_GLOBAL_INFRA_IRQ_EN 0x2C0A
+#define TJA1120_GLOBAL_INFRA_IRQ_STATUS 0x2C0C
+#define TJA1120_DEV_BOOT_DONE BIT(1)
+
+#define TJA1120_VEND1_PTP_TRIG_DATA_S 0x1070
+
+#define TJA1120_EGRESS_TS_DATA_S 0x9060
+#define TJA1120_EGRESS_TS_END 0x9067
+#define TJA1120_TS_VALID BIT(0)
+#define TJA1120_MORE_TS BIT(15)
+
#define VEND1_PHY_IRQ_ACK 0x80A0
#define VEND1_PHY_IRQ_EN 0x80A1
#define VEND1_PHY_IRQ_STATUS 0x80A2
#define PHY_IRQ_LINK_EVENT BIT(1)
+#define VEND1_ALWAYS_ACCESSIBLE 0x801F
+#define FUSA_PASS BIT(4)
+
#define VEND1_PHY_CONTROL 0x8100
#define PHY_CONFIG_EN BIT(14)
#define PHY_START_OP BIT(0)
@@ -43,15 +56,16 @@
#define VEND1_PHY_CONFIG 0x8108
#define PHY_CONFIG_AUTO BIT(0)
+#define TJA1120_EPHY_RESETS 0x810A
+#define EPHY_PCS_RESET BIT(3)
+
#define VEND1_SIGNAL_QUALITY 0x8320
#define SQI_VALID BIT(14)
#define SQI_MASK GENMASK(2, 0)
#define MAX_SQI SQI_MASK
-#define VEND1_CABLE_TEST 0x8330
#define CABLE_TEST_ENABLE BIT(15)
#define CABLE_TEST_START BIT(14)
-#define CABLE_TEST_VALID BIT(13)
#define CABLE_TEST_OK 0x00
#define CABLE_TEST_SHORTED 0x01
#define CABLE_TEST_OPEN 0x02
@@ -63,6 +77,12 @@
#define VEND1_PORT_ABILITIES 0x8046
#define PTP_ABILITY BIT(3)
+#define VEND1_PORT_FUNC_IRQ_EN 0x807A
+#define PTP_IRQS BIT(3)
+
+#define VEND1_PTP_IRQ_ACK 0x9008
+#define EGR_TS_IRQ BIT(1)
+
#define VEND1_PORT_INFRA_CONTROL 0xAC00
#define PORT_INFRA_CONTROL_EN BIT(14)
@@ -85,12 +105,17 @@
#define MII_BASIC_CONFIG_RMII 0x5
#define MII_BASIC_CONFIG_MII 0x4
+#define VEND1_SYMBOL_ERROR_CNT_XTD 0x8351
+#define EXTENDED_CNT_EN BIT(15)
+#define VEND1_MONITOR_STATUS 0xAC80
+#define MONITOR_RESET BIT(15)
+#define VEND1_MONITOR_CONFIG 0xAC86
+#define LOST_FRAMES_CNT_EN BIT(9)
+#define ALL_FRAMES_CNT_EN BIT(8)
+
#define VEND1_SYMBOL_ERROR_COUNTER 0x8350
#define VEND1_LINK_DROP_COUNTER 0x8352
#define VEND1_LINK_LOSSES_AND_FAILURES 0x8353
-#define VEND1_R_GOOD_FRAME_CNT 0xA950
-#define VEND1_R_BAD_FRAME_CNT 0xA952
-#define VEND1_R_RXER_FRAME_CNT 0xA954
#define VEND1_RX_PREAMBLE_COUNT 0xAFCE
#define VEND1_TX_PREAMBLE_COUNT 0xAFCF
#define VEND1_RX_IPG_LENGTH 0xAFD0
@@ -99,81 +124,43 @@
#define VEND1_PTP_CONFIG 0x1102
#define EXT_TRG_EDGE BIT(1)
-#define PPS_OUT_POL BIT(2)
-#define PPS_OUT_EN BIT(3)
-#define VEND1_LTC_LOAD_CTRL 0x1105
-#define READ_LTC BIT(2)
-#define LOAD_LTC BIT(0)
+#define TJA1120_SYNC_TRIG_FILTER 0x1010
+#define PTP_TRIG_RISE_TS BIT(3)
+#define PTP_TRIG_FALLING_TS BIT(2)
-#define VEND1_LTC_WR_NSEC_0 0x1106
-#define VEND1_LTC_WR_NSEC_1 0x1107
-#define VEND1_LTC_WR_SEC_0 0x1108
-#define VEND1_LTC_WR_SEC_1 0x1109
-
-#define VEND1_LTC_RD_NSEC_0 0x110A
-#define VEND1_LTC_RD_NSEC_1 0x110B
-#define VEND1_LTC_RD_SEC_0 0x110C
-#define VEND1_LTC_RD_SEC_1 0x110D
-
-#define VEND1_RATE_ADJ_SUBNS_0 0x110F
-#define VEND1_RATE_ADJ_SUBNS_1 0x1110
#define CLK_RATE_ADJ_LD BIT(15)
#define CLK_RATE_ADJ_DIR BIT(14)
-#define VEND1_HW_LTC_LOCK_CTRL 0x1115
-#define HW_LTC_LOCK_EN BIT(0)
-
-#define VEND1_PTP_IRQ_EN 0x1131
-#define VEND1_PTP_IRQ_STATUS 0x1132
-#define PTP_IRQ_EGR_TS BIT(0)
-
#define VEND1_RX_TS_INSRT_CTRL 0x114D
-#define RX_TS_INSRT_MODE2 0x02
+#define TJA1103_RX_TS_INSRT_MODE2 0x02
+
+#define TJA1120_RX_TS_INSRT_CTRL 0x9012
+#define TJA1120_RX_TS_INSRT_EN BIT(15)
+#define TJA1120_TS_INSRT_MODE BIT(4)
#define VEND1_EGR_RING_DATA_0 0x114E
-#define VEND1_EGR_RING_DATA_1_SEQ_ID 0x114F
-#define VEND1_EGR_RING_DATA_2_NSEC_15_0 0x1150
-#define VEND1_EGR_RING_DATA_3 0x1151
#define VEND1_EGR_RING_CTRL 0x1154
-#define VEND1_EXT_TRG_TS_DATA_0 0x1121
-#define VEND1_EXT_TRG_TS_DATA_1 0x1122
-#define VEND1_EXT_TRG_TS_DATA_2 0x1123
-#define VEND1_EXT_TRG_TS_DATA_3 0x1124
-#define VEND1_EXT_TRG_TS_DATA_4 0x1125
-#define VEND1_EXT_TRG_TS_CTRL 0x1126
-
-#define RING_DATA_0_DOMAIN_NUMBER GENMASK(7, 0)
-#define RING_DATA_0_MSG_TYPE GENMASK(11, 8)
-#define RING_DATA_0_SEC_4_2 GENMASK(14, 2)
#define RING_DATA_0_TS_VALID BIT(15)
-#define RING_DATA_3_NSEC_29_16 GENMASK(13, 0)
-#define RING_DATA_3_SEC_1_0 GENMASK(15, 14)
-#define RING_DATA_5_SEC_16_5 GENMASK(15, 4)
#define RING_DONE BIT(0)
#define TS_SEC_MASK GENMASK(1, 0)
#define VEND1_PORT_FUNC_ENABLES 0x8048
#define PTP_ENABLE BIT(3)
+#define PHY_TEST_ENABLE BIT(0)
#define VEND1_PORT_PTP_CONTROL 0x9000
#define PORT_PTP_CONTROL_BYPASS BIT(11)
-#define VEND1_PTP_CLK_PERIOD 0x1104
#define PTP_CLK_PERIOD_100BT1 15ULL
+#define PTP_CLK_PERIOD_1000BT1 8ULL
-#define VEND1_EVENT_MSG_FILT 0x1148
#define EVENT_MSG_FILT_ALL 0x0F
#define EVENT_MSG_FILT_NONE 0x00
-#define VEND1_TX_PIPE_DLY_NS 0x1149
-#define VEND1_TX_PIPEDLY_SUBNS 0x114A
-#define VEND1_RX_PIPE_DLY_NS 0x114B
-#define VEND1_RX_PIPEDLY_SUBNS 0x114C
-
#define VEND1_GPIO_FUNC_CONFIG_BASE 0x2C40
#define GPIO_FUNC_EN BIT(15)
#define GPIO_FUNC_PTP BIT(6)
@@ -191,16 +178,33 @@
#define MAX_ID_PS 2260U
#define DEFAULT_ID_PS 2000U
-#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK_ULL(31, 0) * (ppb) * \
- PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC)
+#define PPM_TO_SUBNS_INC(ppb, ptp_clk_period) div_u64(GENMASK_ULL(31, 0) * \
+ (ppb) * (ptp_clk_period), NSEC_PER_SEC)
#define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb)
+struct nxp_c45_phy;
+
struct nxp_c45_skb_cb {
struct ptp_header *header;
unsigned int type;
};
+#define NXP_C45_REG_FIELD(_reg, _devad, _offset, _size) \
+ ((struct nxp_c45_reg_field) { \
+ .reg = _reg, \
+ .devad = _devad, \
+ .offset = _offset, \
+ .size = _size, \
+ })
+
+struct nxp_c45_reg_field {
+ u16 reg;
+ u8 devad;
+ u8 offset;
+ u8 size;
+};
+
struct nxp_c45_hwts {
u32 nsec;
u32 sec;
@@ -209,7 +213,76 @@ struct nxp_c45_hwts {
u8 msg_type;
};
+struct nxp_c45_regmap {
+ /* PTP config regs. */
+ u16 vend1_ptp_clk_period;
+ u16 vend1_event_msg_filt;
+
+ /* LTC bits and regs. */
+ struct nxp_c45_reg_field ltc_read;
+ struct nxp_c45_reg_field ltc_write;
+ struct nxp_c45_reg_field ltc_lock_ctrl;
+ u16 vend1_ltc_wr_nsec_0;
+ u16 vend1_ltc_wr_nsec_1;
+ u16 vend1_ltc_wr_sec_0;
+ u16 vend1_ltc_wr_sec_1;
+ u16 vend1_ltc_rd_nsec_0;
+ u16 vend1_ltc_rd_nsec_1;
+ u16 vend1_ltc_rd_sec_0;
+ u16 vend1_ltc_rd_sec_1;
+ u16 vend1_rate_adj_subns_0;
+ u16 vend1_rate_adj_subns_1;
+
+ /* External trigger reg fields. */
+ struct nxp_c45_reg_field irq_egr_ts_en;
+ struct nxp_c45_reg_field irq_egr_ts_status;
+ struct nxp_c45_reg_field domain_number;
+ struct nxp_c45_reg_field msg_type;
+ struct nxp_c45_reg_field sequence_id;
+ struct nxp_c45_reg_field sec_1_0;
+ struct nxp_c45_reg_field sec_4_2;
+ struct nxp_c45_reg_field nsec_15_0;
+ struct nxp_c45_reg_field nsec_29_16;
+
+ /* PPS and EXT Trigger bits and regs. */
+ struct nxp_c45_reg_field pps_enable;
+ struct nxp_c45_reg_field pps_polarity;
+ u16 vend1_ext_trg_data_0;
+ u16 vend1_ext_trg_data_1;
+ u16 vend1_ext_trg_data_2;
+ u16 vend1_ext_trg_data_3;
+ u16 vend1_ext_trg_ctrl;
+
+ /* Cable test reg fields. */
+ u16 cable_test;
+ struct nxp_c45_reg_field cable_test_valid;
+ struct nxp_c45_reg_field cable_test_result;
+};
+
+struct nxp_c45_phy_stats {
+ const char *name;
+ const struct nxp_c45_reg_field counter;
+};
+
+struct nxp_c45_phy_data {
+ const struct nxp_c45_regmap *regmap;
+ const struct nxp_c45_phy_stats *stats;
+ int n_stats;
+ u8 ptp_clk_period;
+ bool ext_ts_both_edges;
+ bool ack_ptp_irq;
+ void (*counters_enable)(struct phy_device *phydev);
+ bool (*get_egressts)(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *hwts);
+ bool (*get_extts)(struct nxp_c45_phy *priv, struct timespec64 *extts);
+ void (*ptp_init)(struct phy_device *phydev);
+ void (*ptp_enable)(struct phy_device *phydev, bool enable);
+ void (*nmi_handler)(struct phy_device *phydev,
+ irqreturn_t *irq_status);
+};
+
struct nxp_c45_phy {
+ const struct nxp_c45_phy_data *phy_data;
struct phy_device *phydev;
struct mii_timestamper mii_ts;
struct ptp_clock *ptp_clock;
@@ -227,13 +300,86 @@ struct nxp_c45_phy {
bool extts;
};
-struct nxp_c45_phy_stats {
- const char *name;
- u8 mmd;
- u16 reg;
- u8 off;
- u16 mask;
-};
+static const
+struct nxp_c45_phy_data *nxp_c45_get_data(struct phy_device *phydev)
+{
+ return phydev->drv->driver_data;
+}
+
+static const
+struct nxp_c45_regmap *nxp_c45_get_regmap(struct phy_device *phydev)
+{
+ const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev);
+
+ return phy_data->regmap;
+}
+
+static int nxp_c45_read_reg_field(struct phy_device *phydev,
+ const struct nxp_c45_reg_field *reg_field)
+{
+ u16 mask;
+ int ret;
+
+ if (reg_field->size == 0) {
+ phydev_err(phydev, "Trying to read a reg field of size 0.\n");
+ return -EINVAL;
+ }
+
+ ret = phy_read_mmd(phydev, reg_field->devad, reg_field->reg);
+ if (ret < 0)
+ return ret;
+
+ mask = reg_field->size == 1 ? BIT(reg_field->offset) :
+ GENMASK(reg_field->offset + reg_field->size - 1,
+ reg_field->offset);
+ ret &= mask;
+ ret >>= reg_field->offset;
+
+ return ret;
+}
+
+static int nxp_c45_write_reg_field(struct phy_device *phydev,
+ const struct nxp_c45_reg_field *reg_field,
+ u16 val)
+{
+ u16 mask;
+ u16 set;
+
+ if (reg_field->size == 0) {
+ phydev_err(phydev, "Trying to write a reg field of size 0.\n");
+ return -EINVAL;
+ }
+
+ mask = reg_field->size == 1 ? BIT(reg_field->offset) :
+ GENMASK(reg_field->offset + reg_field->size - 1,
+ reg_field->offset);
+ set = val << reg_field->offset;
+
+ return phy_modify_mmd_changed(phydev, reg_field->devad,
+ reg_field->reg, mask, set);
+}
+
+static int nxp_c45_set_reg_field(struct phy_device *phydev,
+ const struct nxp_c45_reg_field *reg_field)
+{
+ if (reg_field->size != 1) {
+ phydev_err(phydev, "Trying to set a reg field of size different than 1.\n");
+ return -EINVAL;
+ }
+
+ return nxp_c45_write_reg_field(phydev, reg_field, 1);
+}
+
+static int nxp_c45_clear_reg_field(struct phy_device *phydev,
+ const struct nxp_c45_reg_field *reg_field)
+{
+ if (reg_field->size != 1) {
+ phydev_err(phydev, "Trying to set a reg field of size different than 1.\n");
+ return -EINVAL;
+ }
+
+ return nxp_c45_write_reg_field(phydev, reg_field, 0);
+}
static bool nxp_c45_poll_txts(struct phy_device *phydev)
{
@@ -245,17 +391,17 @@ static int _nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp,
struct ptp_system_timestamp *sts)
{
struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
- READ_LTC);
+ nxp_c45_set_reg_field(priv->phydev, &regmap->ltc_read);
ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_LTC_RD_NSEC_0);
+ regmap->vend1_ltc_rd_nsec_0);
ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_LTC_RD_NSEC_1) << 16;
+ regmap->vend1_ltc_rd_nsec_1) << 16;
ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_LTC_RD_SEC_0);
+ regmap->vend1_ltc_rd_sec_0);
ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_LTC_RD_SEC_1) << 16;
+ regmap->vend1_ltc_rd_sec_1) << 16;
return 0;
}
@@ -277,17 +423,17 @@ static int _nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_nsec_0,
ts->tv_nsec);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_nsec_1,
ts->tv_nsec >> 16);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_sec_0,
ts->tv_sec);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_sec_1,
ts->tv_sec >> 16);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL,
- LOAD_LTC);
+ nxp_c45_set_reg_field(priv->phydev, &regmap->ltc_write);
return 0;
}
@@ -307,6 +453,8 @@ static int nxp_c45_ptp_settime64(struct ptp_clock_info *ptp,
static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(priv->phydev);
+ const struct nxp_c45_regmap *regmap = data->regmap;
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
u64 subns_inc_val;
bool inc;
@@ -315,16 +463,18 @@ static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
inc = ppb >= 0;
ppb = abs(ppb);
- subns_inc_val = PPM_TO_SUBNS_INC(ppb);
+ subns_inc_val = PPM_TO_SUBNS_INC(ppb, data->ptp_clk_period);
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1,
+ regmap->vend1_rate_adj_subns_0,
subns_inc_val);
subns_inc_val >>= 16;
subns_inc_val |= CLK_RATE_ADJ_LD;
if (inc)
subns_inc_val |= CLK_RATE_ADJ_DIR;
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1,
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1,
+ regmap->vend1_rate_adj_subns_1,
subns_inc_val);
mutex_unlock(&priv->ptp_lock);
@@ -365,19 +515,88 @@ static bool nxp_c45_match_ts(struct ptp_header *header,
header->domain_number == hwts->domain_number;
}
-static void nxp_c45_get_extts(struct nxp_c45_phy *priv,
+static bool nxp_c45_get_extts(struct nxp_c45_phy *priv,
struct timespec64 *extts)
{
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
+
extts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EXT_TRG_TS_DATA_0);
+ regmap->vend1_ext_trg_data_0);
extts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EXT_TRG_TS_DATA_1) << 16;
+ regmap->vend1_ext_trg_data_1) << 16;
extts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EXT_TRG_TS_DATA_2);
+ regmap->vend1_ext_trg_data_2);
extts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EXT_TRG_TS_DATA_3) << 16;
- phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EXT_TRG_TS_CTRL,
- RING_DONE);
+ regmap->vend1_ext_trg_data_3) << 16;
+ phy_write_mmd(priv->phydev, MDIO_MMD_VEND1,
+ regmap->vend1_ext_trg_ctrl, RING_DONE);
+
+ return true;
+}
+
+static bool tja1120_extts_is_valid(struct phy_device *phydev)
+{
+ bool valid;
+ int reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_VEND1_PTP_TRIG_DATA_S);
+ valid = !!(reg & TJA1120_TS_VALID);
+
+ return valid;
+}
+
+static bool tja1120_get_extts(struct nxp_c45_phy *priv,
+ struct timespec64 *extts)
+{
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
+ struct phy_device *phydev = priv->phydev;
+ bool more_ts;
+ bool valid;
+ u16 reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ regmap->vend1_ext_trg_ctrl);
+ more_ts = !!(reg & TJA1120_MORE_TS);
+
+ valid = tja1120_extts_is_valid(phydev);
+ if (!valid) {
+ if (!more_ts)
+ goto tja1120_get_extts_out;
+
+ /* Bug workaround for TJA1120 engineering samples: move the new
+ * timestamp from the FIFO to the buffer.
+ */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ regmap->vend1_ext_trg_ctrl, RING_DONE);
+ valid = tja1120_extts_is_valid(phydev);
+ if (!valid)
+ goto tja1120_get_extts_out;
+ }
+
+ nxp_c45_get_extts(priv, extts);
+tja1120_get_extts_out:
+ return valid;
+}
+
+static void nxp_c45_read_egress_ts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *hwts)
+{
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
+ struct phy_device *phydev = priv->phydev;
+
+ hwts->domain_number =
+ nxp_c45_read_reg_field(phydev, &regmap->domain_number);
+ hwts->msg_type =
+ nxp_c45_read_reg_field(phydev, &regmap->msg_type);
+ hwts->sequence_id =
+ nxp_c45_read_reg_field(phydev, &regmap->sequence_id);
+ hwts->nsec =
+ nxp_c45_read_reg_field(phydev, &regmap->nsec_15_0);
+ hwts->nsec |=
+ nxp_c45_read_reg_field(phydev, &regmap->nsec_29_16) << 16;
+ hwts->sec = nxp_c45_read_reg_field(phydev, &regmap->sec_1_0);
+ hwts->sec |= nxp_c45_read_reg_field(phydev, &regmap->sec_4_2) << 2;
}
static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv,
@@ -394,22 +613,56 @@ static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv,
if (!valid)
goto nxp_c45_get_hwtxts_out;
- hwts->domain_number = reg;
- hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8;
- hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10;
- hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EGR_RING_DATA_1_SEQ_ID);
- hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_EGR_RING_DATA_2_NSEC_15_0);
- reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3);
- hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16;
- hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14;
-
+ nxp_c45_read_egress_ts(priv, hwts);
nxp_c45_get_hwtxts_out:
mutex_unlock(&priv->ptp_lock);
return valid;
}
+static bool tja1120_egress_ts_is_valid(struct phy_device *phydev)
+{
+ bool valid;
+ u16 reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, TJA1120_EGRESS_TS_DATA_S);
+ valid = !!(reg & TJA1120_TS_VALID);
+
+ return valid;
+}
+
+static bool tja1120_get_hwtxts(struct nxp_c45_phy *priv,
+ struct nxp_c45_hwts *hwts)
+{
+ struct phy_device *phydev = priv->phydev;
+ bool more_ts;
+ bool valid;
+ u16 reg;
+
+ mutex_lock(&priv->ptp_lock);
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, TJA1120_EGRESS_TS_END);
+ more_ts = !!(reg & TJA1120_MORE_TS);
+ valid = tja1120_egress_ts_is_valid(phydev);
+ if (!valid) {
+ if (!more_ts)
+ goto tja1120_get_hwtxts_out;
+
+ /* Bug workaround for TJA1120 engineering samples: move the
+ * new timestamp from the FIFO to the buffer.
+ */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_EGRESS_TS_END, TJA1120_TS_VALID);
+ valid = tja1120_egress_ts_is_valid(phydev);
+ if (!valid)
+ goto tja1120_get_hwtxts_out;
+ }
+ nxp_c45_read_egress_ts(priv, hwts);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, TJA1120_EGRESS_TS_DATA_S,
+ TJA1120_TS_VALID);
+tja1120_get_hwtxts_out:
+ mutex_unlock(&priv->ptp_lock);
+ return valid;
+}
+
static void nxp_c45_process_txts(struct nxp_c45_phy *priv,
struct nxp_c45_hwts *txts)
{
@@ -448,6 +701,7 @@ static void nxp_c45_process_txts(struct nxp_c45_phy *priv,
static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp)
{
struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps);
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(priv->phydev);
bool poll_txts = nxp_c45_poll_txts(priv->phydev);
struct skb_shared_hwtstamps *shhwtstamps_rx;
struct ptp_clock_event event;
@@ -455,12 +709,12 @@ static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp)
bool reschedule = false;
struct timespec64 ts;
struct sk_buff *skb;
- bool txts_valid;
+ bool ts_valid;
u32 ts_raw;
while (!skb_queue_empty_lockless(&priv->tx_queue) && poll_txts) {
- txts_valid = nxp_c45_get_hwtxts(priv, &hwts);
- if (unlikely(!txts_valid)) {
+ ts_valid = data->get_egressts(priv, &hwts);
+ if (unlikely(!ts_valid)) {
/* Still more skbs in the queue */
reschedule = true;
break;
@@ -482,8 +736,8 @@ static long nxp_c45_do_aux_work(struct ptp_clock_info *ptp)
}
if (priv->extts) {
- nxp_c45_get_extts(priv, &ts);
- if (timespec64_compare(&ts, &priv->extts_ts) != 0) {
+ ts_valid = data->get_extts(priv, &ts);
+ if (ts_valid && timespec64_compare(&ts, &priv->extts_ts) != 0) {
priv->extts_ts = ts;
event.index = priv->extts_index;
event.type = PTP_CLOCK_EXTTS;
@@ -508,6 +762,7 @@ static void nxp_c45_gpio_config(struct nxp_c45_phy *priv,
static int nxp_c45_perout_enable(struct nxp_c45_phy *priv,
struct ptp_perout_request *perout, int on)
{
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev);
struct phy_device *phydev = priv->phydev;
int pin;
@@ -519,10 +774,10 @@ static int nxp_c45_perout_enable(struct nxp_c45_phy *priv,
return pin;
if (!on) {
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG,
- PPS_OUT_EN);
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG,
- PPS_OUT_POL);
+ nxp_c45_clear_reg_field(priv->phydev,
+ &regmap->pps_enable);
+ nxp_c45_clear_reg_field(priv->phydev,
+ &regmap->pps_polarity);
nxp_c45_gpio_config(priv, pin, GPIO_DISABLE);
@@ -551,23 +806,62 @@ static int nxp_c45_perout_enable(struct nxp_c45_phy *priv,
}
if (perout->phase.nsec == 0)
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PTP_CONFIG, PPS_OUT_POL);
+ nxp_c45_clear_reg_field(priv->phydev,
+ &regmap->pps_polarity);
else
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PTP_CONFIG, PPS_OUT_POL);
+ nxp_c45_set_reg_field(priv->phydev,
+ &regmap->pps_polarity);
}
nxp_c45_gpio_config(priv, pin, GPIO_PPS_OUT_CFG);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG, PPS_OUT_EN);
+ nxp_c45_set_reg_field(priv->phydev, &regmap->pps_enable);
return 0;
}
+static void nxp_c45_set_rising_or_falling(struct phy_device *phydev,
+ struct ptp_extts_request *extts)
+{
+ if (extts->flags & PTP_RISING_EDGE)
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_CONFIG, EXT_TRG_EDGE);
+
+ if (extts->flags & PTP_FALLING_EDGE)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_CONFIG, EXT_TRG_EDGE);
+}
+
+static void nxp_c45_set_rising_and_falling(struct phy_device *phydev,
+ struct ptp_extts_request *extts)
+{
+ /* PTP_EXTTS_REQUEST may have only the PTP_ENABLE_FEATURE flag set. In
+ * this case external ts will be enabled on rising edge.
+ */
+ if (extts->flags & PTP_RISING_EDGE ||
+ extts->flags == PTP_ENABLE_FEATURE)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_SYNC_TRIG_FILTER,
+ PTP_TRIG_RISE_TS);
+ else
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_SYNC_TRIG_FILTER,
+ PTP_TRIG_RISE_TS);
+
+ if (extts->flags & PTP_FALLING_EDGE)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_SYNC_TRIG_FILTER,
+ PTP_TRIG_FALLING_TS);
+ else
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_SYNC_TRIG_FILTER,
+ PTP_TRIG_FALLING_TS);
+}
+
static int nxp_c45_extts_enable(struct nxp_c45_phy *priv,
struct ptp_extts_request *extts, int on)
{
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(priv->phydev);
int pin;
if (extts->flags & ~(PTP_ENABLE_FEATURE |
@@ -578,7 +872,8 @@ static int nxp_c45_extts_enable(struct nxp_c45_phy *priv,
/* Sampling on both edges is not supported */
if ((extts->flags & PTP_RISING_EDGE) &&
- (extts->flags & PTP_FALLING_EDGE))
+ (extts->flags & PTP_FALLING_EDGE) &&
+ !data->ext_ts_both_edges)
return -EOPNOTSUPP;
pin = ptp_find_pin(priv->ptp_clock, PTP_PF_EXTTS, extts->index);
@@ -592,13 +887,10 @@ static int nxp_c45_extts_enable(struct nxp_c45_phy *priv,
return 0;
}
- if (extts->flags & PTP_RISING_EDGE)
- phy_clear_bits_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_PTP_CONFIG, EXT_TRG_EDGE);
-
- if (extts->flags & PTP_FALLING_EDGE)
- phy_set_bits_mmd(priv->phydev, MDIO_MMD_VEND1,
- VEND1_PTP_CONFIG, EXT_TRG_EDGE);
+ if (data->ext_ts_both_edges)
+ nxp_c45_set_rising_and_falling(priv->phydev, extts);
+ else
+ nxp_c45_set_rising_or_falling(priv->phydev, extts);
nxp_c45_gpio_config(priv, pin, GPIO_EXTTS_OUT_CFG);
priv->extts = true;
@@ -735,6 +1027,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
mii_ts);
struct phy_device *phydev = priv->phydev;
+ const struct nxp_c45_phy_data *data;
struct hwtstamp_config cfg;
if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg)))
@@ -743,6 +1036,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON)
return -ERANGE;
+ data = nxp_c45_get_data(phydev);
priv->hwts_tx = cfg.tx_type;
switch (cfg.rx_filter) {
@@ -760,27 +1054,24 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
}
if (priv->hwts_rx || priv->hwts_tx) {
- phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ data->regmap->vend1_event_msg_filt,
EVENT_MSG_FILT_ALL);
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PORT_PTP_CONTROL,
- PORT_PTP_CONTROL_BYPASS);
+ data->ptp_enable(phydev, true);
} else {
- phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT,
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ data->regmap->vend1_event_msg_filt,
EVENT_MSG_FILT_NONE);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_PTP_CONTROL,
- PORT_PTP_CONTROL_BYPASS);
+ data->ptp_enable(phydev, false);
}
if (nxp_c45_poll_txts(priv->phydev))
goto nxp_c45_no_ptp_irq;
if (priv->hwts_tx)
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+ nxp_c45_set_reg_field(phydev, &data->regmap->irq_egr_ts_en);
else
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS);
+ nxp_c45_clear_reg_field(phydev, &data->regmap->irq_egr_ts_en);
nxp_c45_no_ptp_irq:
return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
@@ -805,63 +1096,100 @@ static int nxp_c45_ts_info(struct mii_timestamper *mii_ts,
return 0;
}
-static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = {
- { "phy_symbol_error_cnt", MDIO_MMD_VEND1,
- VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) },
- { "phy_link_status_drop_cnt", MDIO_MMD_VEND1,
- VEND1_LINK_DROP_COUNTER, 8, GENMASK(13, 8) },
- { "phy_link_availability_drop_cnt", MDIO_MMD_VEND1,
- VEND1_LINK_DROP_COUNTER, 0, GENMASK(5, 0) },
- { "phy_link_loss_cnt", MDIO_MMD_VEND1,
- VEND1_LINK_LOSSES_AND_FAILURES, 10, GENMASK(15, 10) },
- { "phy_link_failure_cnt", MDIO_MMD_VEND1,
- VEND1_LINK_LOSSES_AND_FAILURES, 0, GENMASK(9, 0) },
- { "r_good_frame_cnt", MDIO_MMD_VEND1,
- VEND1_R_GOOD_FRAME_CNT, 0, GENMASK(15, 0) },
- { "r_bad_frame_cnt", MDIO_MMD_VEND1,
- VEND1_R_BAD_FRAME_CNT, 0, GENMASK(15, 0) },
- { "r_rxer_frame_cnt", MDIO_MMD_VEND1,
- VEND1_R_RXER_FRAME_CNT, 0, GENMASK(15, 0) },
- { "rx_preamble_count", MDIO_MMD_VEND1,
- VEND1_RX_PREAMBLE_COUNT, 0, GENMASK(5, 0) },
- { "tx_preamble_count", MDIO_MMD_VEND1,
- VEND1_TX_PREAMBLE_COUNT, 0, GENMASK(5, 0) },
- { "rx_ipg_length", MDIO_MMD_VEND1,
- VEND1_RX_IPG_LENGTH, 0, GENMASK(8, 0) },
- { "tx_ipg_length", MDIO_MMD_VEND1,
- VEND1_TX_IPG_LENGTH, 0, GENMASK(8, 0) },
+static const struct nxp_c45_phy_stats common_hw_stats[] = {
+ { "phy_link_status_drop_cnt",
+ NXP_C45_REG_FIELD(0x8352, MDIO_MMD_VEND1, 8, 6), },
+ { "phy_link_availability_drop_cnt",
+ NXP_C45_REG_FIELD(0x8352, MDIO_MMD_VEND1, 0, 6), },
+ { "phy_link_loss_cnt",
+ NXP_C45_REG_FIELD(0x8353, MDIO_MMD_VEND1, 10, 6), },
+ { "phy_link_failure_cnt",
+ NXP_C45_REG_FIELD(0x8353, MDIO_MMD_VEND1, 0, 10), },
+ { "phy_symbol_error_cnt",
+ NXP_C45_REG_FIELD(0x8350, MDIO_MMD_VEND1, 0, 16) },
+};
+
+static const struct nxp_c45_phy_stats tja1103_hw_stats[] = {
+ { "rx_preamble_count",
+ NXP_C45_REG_FIELD(0xAFCE, MDIO_MMD_VEND1, 0, 6), },
+ { "tx_preamble_count",
+ NXP_C45_REG_FIELD(0xAFCF, MDIO_MMD_VEND1, 0, 6), },
+ { "rx_ipg_length",
+ NXP_C45_REG_FIELD(0xAFD0, MDIO_MMD_VEND1, 0, 9), },
+ { "tx_ipg_length",
+ NXP_C45_REG_FIELD(0xAFD1, MDIO_MMD_VEND1, 0, 9), },
+};
+
+static const struct nxp_c45_phy_stats tja1120_hw_stats[] = {
+ { "phy_symbol_error_cnt_ext",
+ NXP_C45_REG_FIELD(0x8351, MDIO_MMD_VEND1, 0, 14) },
+ { "tx_frames_xtd",
+ NXP_C45_REG_FIELD(0xACA1, MDIO_MMD_VEND1, 0, 8), },
+ { "tx_frames",
+ NXP_C45_REG_FIELD(0xACA0, MDIO_MMD_VEND1, 0, 16), },
+ { "rx_frames_xtd",
+ NXP_C45_REG_FIELD(0xACA3, MDIO_MMD_VEND1, 0, 8), },
+ { "rx_frames",
+ NXP_C45_REG_FIELD(0xACA2, MDIO_MMD_VEND1, 0, 16), },
+ { "tx_lost_frames_xtd",
+ NXP_C45_REG_FIELD(0xACA5, MDIO_MMD_VEND1, 0, 8), },
+ { "tx_lost_frames",
+ NXP_C45_REG_FIELD(0xACA4, MDIO_MMD_VEND1, 0, 16), },
+ { "rx_lost_frames_xtd",
+ NXP_C45_REG_FIELD(0xACA7, MDIO_MMD_VEND1, 0, 8), },
+ { "rx_lost_frames",
+ NXP_C45_REG_FIELD(0xACA6, MDIO_MMD_VEND1, 0, 16), },
};
static int nxp_c45_get_sset_count(struct phy_device *phydev)
{
- return ARRAY_SIZE(nxp_c45_hw_stats);
+ const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev);
+
+ return ARRAY_SIZE(common_hw_stats) + (phy_data ? phy_data->n_stats : 0);
}
static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data)
{
+ const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev);
+ size_t count = nxp_c45_get_sset_count(phydev);
+ size_t idx;
size_t i;
- for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) {
- strncpy(data + i * ETH_GSTRING_LEN,
- nxp_c45_hw_stats[i].name, ETH_GSTRING_LEN);
+ 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);
+ continue;
+ }
+ idx = i - ARRAY_SIZE(common_hw_stats);
+ strscpy(data + i * ETH_GSTRING_LEN,
+ phy_data->stats[idx].name, ETH_GSTRING_LEN);
}
}
static void nxp_c45_get_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data)
{
+ const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev);
+ size_t count = nxp_c45_get_sset_count(phydev);
+ const struct nxp_c45_reg_field *reg_field;
+ size_t idx;
size_t i;
int ret;
- for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) {
- ret = phy_read_mmd(phydev, nxp_c45_hw_stats[i].mmd,
- nxp_c45_hw_stats[i].reg);
- if (ret < 0) {
- data[i] = U64_MAX;
+ for (i = 0; i < count; i++) {
+ if (i < ARRAY_SIZE(common_hw_stats)) {
+ reg_field = &common_hw_stats[i].counter;
} else {
- data[i] = ret & nxp_c45_hw_stats[i].mask;
- data[i] >>= nxp_c45_hw_stats[i].off;
+ idx = i - ARRAY_SIZE(common_hw_stats);
+ reg_field = &phy_data->stats[idx].counter;
}
+
+ ret = nxp_c45_read_reg_field(phydev, reg_field);
+ if (ret < 0)
+ data[i] = U64_MAX;
+ else
+ data[i] = ret;
}
}
@@ -898,8 +1226,40 @@ static int nxp_c45_config_intr(struct phy_device *phydev)
VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
}
+static int tja1103_config_intr(struct phy_device *phydev)
+{
+ int ret;
+
+ /* We can't disable the FUSA IRQ for TJA1103, but we can clean it up. */
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_ALWAYS_ACCESSIBLE,
+ FUSA_PASS);
+ if (ret)
+ return ret;
+
+ return nxp_c45_config_intr(phydev);
+}
+
+static int tja1120_config_intr(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_GLOBAL_INFRA_IRQ_EN,
+ TJA1120_DEV_BOOT_DONE);
+ else
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_GLOBAL_INFRA_IRQ_EN,
+ TJA1120_DEV_BOOT_DONE);
+ if (ret)
+ return ret;
+
+ return nxp_c45_config_intr(phydev);
+}
+
static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
{
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev);
struct nxp_c45_phy *priv = phydev->priv;
irqreturn_t ret = IRQ_NONE;
struct nxp_c45_hwts hwts;
@@ -913,18 +1273,23 @@ static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
ret = IRQ_HANDLED;
}
- /* There is no need for ACK.
- * The irq signal will be asserted until the EGR TS FIFO will be
- * emptied.
- */
- irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_IRQ_STATUS);
- if (irq & PTP_IRQ_EGR_TS) {
- while (nxp_c45_get_hwtxts(priv, &hwts))
+ irq = nxp_c45_read_reg_field(phydev, &data->regmap->irq_egr_ts_status);
+ if (irq) {
+ /* If ack_ptp_irq is false, the IRQ bit is self-clear and will
+ * be cleared when the EGR TS FIFO is empty. Otherwise, the
+ * IRQ bit should be cleared before reading the timestamp,
+ */
+ if (data->ack_ptp_irq)
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PTP_IRQ_ACK, EGR_TS_IRQ);
+ while (data->get_egressts(priv, &hwts))
nxp_c45_process_txts(priv, &hwts);
ret = IRQ_HANDLED;
}
+ data->nmi_handler(phydev, &ret);
+
return ret;
}
@@ -945,24 +1310,30 @@ static int nxp_c45_soft_reset(struct phy_device *phydev)
static int nxp_c45_cable_test_start(struct phy_device *phydev)
{
- return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST,
- CABLE_TEST_ENABLE | CABLE_TEST_START);
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(phydev);
+
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_ENABLES, PHY_TEST_ENABLE);
+ return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, regmap->cable_test,
+ CABLE_TEST_ENABLE | CABLE_TEST_START);
}
static int nxp_c45_cable_test_get_status(struct phy_device *phydev,
bool *finished)
{
+ const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(phydev);
int ret;
u8 cable_test_result;
- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST);
- if (!(ret & CABLE_TEST_VALID)) {
+ ret = nxp_c45_read_reg_field(phydev, &regmap->cable_test_valid);
+ if (!ret) {
*finished = false;
return 0;
}
*finished = true;
- cable_test_result = ret & GENMASK(2, 0);
+ cable_test_result = nxp_c45_read_reg_field(phydev,
+ &regmap->cable_test_result);
switch (cable_test_result) {
case CABLE_TEST_OK:
@@ -982,78 +1353,14 @@ static int nxp_c45_cable_test_get_status(struct phy_device *phydev,
ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC);
}
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST,
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, regmap->cable_test,
CABLE_TEST_ENABLE);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_ENABLES, PHY_TEST_ENABLE);
return nxp_c45_start_op(phydev);
}
-static int nxp_c45_setup_master_slave(struct phy_device *phydev)
-{
- switch (phydev->master_slave_set) {
- case MASTER_SLAVE_CFG_MASTER_FORCE:
- case MASTER_SLAVE_CFG_MASTER_PREFERRED:
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL,
- MASTER_MODE);
- break;
- case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
- case MASTER_SLAVE_CFG_SLAVE_FORCE:
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL,
- SLAVE_MODE);
- break;
- case MASTER_SLAVE_CFG_UNKNOWN:
- case MASTER_SLAVE_CFG_UNSUPPORTED:
- return 0;
- default:
- phydev_warn(phydev, "Unsupported Master/Slave mode\n");
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static int nxp_c45_read_master_slave(struct phy_device *phydev)
-{
- int reg;
-
- phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
- phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
-
- reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_B100T1_PMAPMD_CTL);
- if (reg < 0)
- return reg;
-
- if (reg & B100T1_PMAPMD_MASTER) {
- phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
- phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
- } else {
- phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
- phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
- }
-
- return 0;
-}
-
-static int nxp_c45_config_aneg(struct phy_device *phydev)
-{
- return nxp_c45_setup_master_slave(phydev);
-}
-
-static int nxp_c45_read_status(struct phy_device *phydev)
-{
- int ret;
-
- ret = genphy_c45_read_status(phydev);
- if (ret)
- return ret;
-
- ret = nxp_c45_read_master_slave(phydev);
- if (ret)
- return ret;
-
- return 0;
-}
-
static int nxp_c45_get_sqi(struct phy_device *phydev)
{
int reg;
@@ -1067,6 +1374,19 @@ static int nxp_c45_get_sqi(struct phy_device *phydev)
return reg;
}
+static void tja1120_link_change_notify(struct phy_device *phydev)
+{
+ /* Bug workaround for TJA1120 enegineering samples: fix egress
+ * timestamps lost after link recovery.
+ */
+ if (phydev->state == PHY_NOLINK) {
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_EPHY_RESETS, EPHY_PCS_RESET);
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_EPHY_RESETS, EPHY_PCS_RESET);
+ }
+}
+
static int nxp_c45_get_sqi_max(struct phy_device *phydev)
{
return MAX_SQI;
@@ -1087,6 +1407,28 @@ static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay)
return 0;
}
+static void nxp_c45_counters_enable(struct phy_device *phydev)
+{
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev);
+
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER,
+ COUNTER_EN);
+
+ data->counters_enable(phydev);
+}
+
+static void nxp_c45_ptp_init(struct phy_device *phydev)
+{
+ const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev);
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ data->regmap->vend1_ptp_clk_period,
+ data->ptp_clk_period);
+ nxp_c45_clear_reg_field(phydev, &data->regmap->ltc_lock_ctrl);
+
+ data->ptp_init(phydev);
+}
+
static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw)
{
/* The delay in degree phase is 73.8 + phase_offset_raw * 0.9.
@@ -1264,35 +1606,26 @@ static int nxp_c45_config_init(struct phy_device *phydev)
phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG,
PHY_CONFIG_AUTO);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER,
- COUNTER_EN);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT,
- COUNTER_EN);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT,
- COUNTER_EN);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH,
- COUNTER_EN);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH,
- COUNTER_EN);
-
ret = nxp_c45_set_phy_mode(phydev);
if (ret)
return ret;
phydev->autoneg = AUTONEG_DISABLE;
- phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK_PERIOD,
- PTP_CLK_PERIOD_100BT1);
- phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_HW_LTC_LOCK_CTRL,
- HW_LTC_LOCK_EN);
- phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL,
- RX_TS_INSRT_MODE2);
- phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
- PTP_ENABLE);
+ nxp_c45_counters_enable(phydev);
+ nxp_c45_ptp_init(phydev);
return nxp_c45_start_op(phydev);
}
+static int nxp_c45_get_features(struct phy_device *phydev)
+{
+ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, phydev->supported);
+
+ return genphy_c45_pma_read_abilities(phydev);
+}
+
static int nxp_c45_probe(struct phy_device *phydev)
{
struct nxp_c45_phy *priv;
@@ -1348,18 +1681,274 @@ static void nxp_c45_remove(struct phy_device *phydev)
skb_queue_purge(&priv->rx_queue);
}
+static void tja1103_counters_enable(struct phy_device *phydev)
+{
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT,
+ COUNTER_EN);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT,
+ COUNTER_EN);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH,
+ COUNTER_EN);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH,
+ COUNTER_EN);
+}
+
+static void tja1103_ptp_init(struct phy_device *phydev)
+{
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL,
+ TJA1103_RX_TS_INSRT_MODE2);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
+ PTP_ENABLE);
+}
+
+static void tja1103_ptp_enable(struct phy_device *phydev, bool enable)
+{
+ if (enable)
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+ else
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_PTP_CONTROL,
+ PORT_PTP_CONTROL_BYPASS);
+}
+
+static void tja1103_nmi_handler(struct phy_device *phydev,
+ irqreturn_t *irq_status)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_ALWAYS_ACCESSIBLE);
+ if (ret & FUSA_PASS) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_ALWAYS_ACCESSIBLE,
+ FUSA_PASS);
+ *irq_status = IRQ_HANDLED;
+ }
+}
+
+static const struct nxp_c45_regmap tja1103_regmap = {
+ .vend1_ptp_clk_period = 0x1104,
+ .vend1_event_msg_filt = 0x1148,
+ .pps_enable =
+ NXP_C45_REG_FIELD(0x1102, MDIO_MMD_VEND1, 3, 1),
+ .pps_polarity =
+ NXP_C45_REG_FIELD(0x1102, MDIO_MMD_VEND1, 2, 1),
+ .ltc_lock_ctrl =
+ NXP_C45_REG_FIELD(0x1115, MDIO_MMD_VEND1, 0, 1),
+ .ltc_read =
+ NXP_C45_REG_FIELD(0x1105, MDIO_MMD_VEND1, 2, 1),
+ .ltc_write =
+ NXP_C45_REG_FIELD(0x1105, MDIO_MMD_VEND1, 0, 1),
+ .vend1_ltc_wr_nsec_0 = 0x1106,
+ .vend1_ltc_wr_nsec_1 = 0x1107,
+ .vend1_ltc_wr_sec_0 = 0x1108,
+ .vend1_ltc_wr_sec_1 = 0x1109,
+ .vend1_ltc_rd_nsec_0 = 0x110A,
+ .vend1_ltc_rd_nsec_1 = 0x110B,
+ .vend1_ltc_rd_sec_0 = 0x110C,
+ .vend1_ltc_rd_sec_1 = 0x110D,
+ .vend1_rate_adj_subns_0 = 0x110F,
+ .vend1_rate_adj_subns_1 = 0x1110,
+ .irq_egr_ts_en =
+ NXP_C45_REG_FIELD(0x1131, MDIO_MMD_VEND1, 0, 1),
+ .irq_egr_ts_status =
+ NXP_C45_REG_FIELD(0x1132, MDIO_MMD_VEND1, 0, 1),
+ .domain_number =
+ NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 0, 8),
+ .msg_type =
+ NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 8, 4),
+ .sequence_id =
+ NXP_C45_REG_FIELD(0x114F, MDIO_MMD_VEND1, 0, 16),
+ .sec_1_0 =
+ NXP_C45_REG_FIELD(0x1151, MDIO_MMD_VEND1, 14, 2),
+ .sec_4_2 =
+ NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 12, 3),
+ .nsec_15_0 =
+ NXP_C45_REG_FIELD(0x1150, MDIO_MMD_VEND1, 0, 16),
+ .nsec_29_16 =
+ NXP_C45_REG_FIELD(0x1151, MDIO_MMD_VEND1, 0, 14),
+ .vend1_ext_trg_data_0 = 0x1121,
+ .vend1_ext_trg_data_1 = 0x1122,
+ .vend1_ext_trg_data_2 = 0x1123,
+ .vend1_ext_trg_data_3 = 0x1124,
+ .vend1_ext_trg_ctrl = 0x1126,
+ .cable_test = 0x8330,
+ .cable_test_valid =
+ NXP_C45_REG_FIELD(0x8330, MDIO_MMD_VEND1, 13, 1),
+ .cable_test_result =
+ NXP_C45_REG_FIELD(0x8330, MDIO_MMD_VEND1, 0, 3),
+};
+
+static const struct nxp_c45_phy_data tja1103_phy_data = {
+ .regmap = &tja1103_regmap,
+ .stats = tja1103_hw_stats,
+ .n_stats = ARRAY_SIZE(tja1103_hw_stats),
+ .ptp_clk_period = PTP_CLK_PERIOD_100BT1,
+ .ext_ts_both_edges = false,
+ .ack_ptp_irq = false,
+ .counters_enable = tja1103_counters_enable,
+ .get_egressts = nxp_c45_get_hwtxts,
+ .get_extts = nxp_c45_get_extts,
+ .ptp_init = tja1103_ptp_init,
+ .ptp_enable = tja1103_ptp_enable,
+ .nmi_handler = tja1103_nmi_handler,
+};
+
+static void tja1120_counters_enable(struct phy_device *phydev)
+{
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_SYMBOL_ERROR_CNT_XTD,
+ EXTENDED_CNT_EN);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_MONITOR_STATUS,
+ MONITOR_RESET);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_MONITOR_CONFIG,
+ ALL_FRAMES_CNT_EN | LOST_FRAMES_CNT_EN);
+}
+
+static void tja1120_ptp_init(struct phy_device *phydev)
+{
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, TJA1120_RX_TS_INSRT_CTRL,
+ TJA1120_RX_TS_INSRT_EN | TJA1120_TS_INSRT_MODE);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, TJA1120_VEND1_EXT_TS_MODE,
+ TJA1120_TS_INSRT_MODE);
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONFIG,
+ PTP_ENABLE);
+}
+
+static void tja1120_ptp_enable(struct phy_device *phydev, bool enable)
+{
+ if (enable)
+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_ENABLES,
+ PTP_ENABLE);
+ else
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_ENABLES,
+ PTP_ENABLE);
+}
+
+static void tja1120_nmi_handler(struct phy_device *phydev,
+ irqreturn_t *irq_status)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_GLOBAL_INFRA_IRQ_STATUS);
+ if (ret & TJA1120_DEV_BOOT_DONE) {
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ TJA1120_GLOBAL_INFRA_IRQ_ACK,
+ TJA1120_DEV_BOOT_DONE);
+ *irq_status = IRQ_HANDLED;
+ }
+}
+
+static const struct nxp_c45_regmap tja1120_regmap = {
+ .vend1_ptp_clk_period = 0x1020,
+ .vend1_event_msg_filt = 0x9010,
+ .pps_enable =
+ NXP_C45_REG_FIELD(0x1006, MDIO_MMD_VEND1, 4, 1),
+ .pps_polarity =
+ NXP_C45_REG_FIELD(0x1006, MDIO_MMD_VEND1, 5, 1),
+ .ltc_lock_ctrl =
+ NXP_C45_REG_FIELD(0x1006, MDIO_MMD_VEND1, 2, 1),
+ .ltc_read =
+ NXP_C45_REG_FIELD(0x1000, MDIO_MMD_VEND1, 1, 1),
+ .ltc_write =
+ NXP_C45_REG_FIELD(0x1000, MDIO_MMD_VEND1, 2, 1),
+ .vend1_ltc_wr_nsec_0 = 0x1040,
+ .vend1_ltc_wr_nsec_1 = 0x1041,
+ .vend1_ltc_wr_sec_0 = 0x1042,
+ .vend1_ltc_wr_sec_1 = 0x1043,
+ .vend1_ltc_rd_nsec_0 = 0x1048,
+ .vend1_ltc_rd_nsec_1 = 0x1049,
+ .vend1_ltc_rd_sec_0 = 0x104A,
+ .vend1_ltc_rd_sec_1 = 0x104B,
+ .vend1_rate_adj_subns_0 = 0x1030,
+ .vend1_rate_adj_subns_1 = 0x1031,
+ .irq_egr_ts_en =
+ NXP_C45_REG_FIELD(0x900A, MDIO_MMD_VEND1, 1, 1),
+ .irq_egr_ts_status =
+ NXP_C45_REG_FIELD(0x900C, MDIO_MMD_VEND1, 1, 1),
+ .domain_number =
+ NXP_C45_REG_FIELD(0x9061, MDIO_MMD_VEND1, 8, 8),
+ .msg_type =
+ NXP_C45_REG_FIELD(0x9061, MDIO_MMD_VEND1, 4, 4),
+ .sequence_id =
+ NXP_C45_REG_FIELD(0x9062, MDIO_MMD_VEND1, 0, 16),
+ .sec_1_0 =
+ NXP_C45_REG_FIELD(0x9065, MDIO_MMD_VEND1, 0, 2),
+ .sec_4_2 =
+ NXP_C45_REG_FIELD(0x9065, MDIO_MMD_VEND1, 2, 3),
+ .nsec_15_0 =
+ NXP_C45_REG_FIELD(0x9063, MDIO_MMD_VEND1, 0, 16),
+ .nsec_29_16 =
+ NXP_C45_REG_FIELD(0x9064, MDIO_MMD_VEND1, 0, 14),
+ .vend1_ext_trg_data_0 = 0x1071,
+ .vend1_ext_trg_data_1 = 0x1072,
+ .vend1_ext_trg_data_2 = 0x1073,
+ .vend1_ext_trg_data_3 = 0x1074,
+ .vend1_ext_trg_ctrl = 0x1075,
+ .cable_test = 0x8360,
+ .cable_test_valid =
+ NXP_C45_REG_FIELD(0x8361, MDIO_MMD_VEND1, 15, 1),
+ .cable_test_result =
+ NXP_C45_REG_FIELD(0x8361, MDIO_MMD_VEND1, 0, 3),
+};
+
+static const struct nxp_c45_phy_data tja1120_phy_data = {
+ .regmap = &tja1120_regmap,
+ .stats = tja1120_hw_stats,
+ .n_stats = ARRAY_SIZE(tja1120_hw_stats),
+ .ptp_clk_period = PTP_CLK_PERIOD_1000BT1,
+ .ext_ts_both_edges = true,
+ .ack_ptp_irq = true,
+ .counters_enable = tja1120_counters_enable,
+ .get_egressts = tja1120_get_hwtxts,
+ .get_extts = tja1120_get_extts,
+ .ptp_init = tja1120_ptp_init,
+ .ptp_enable = tja1120_ptp_enable,
+ .nmi_handler = tja1120_nmi_handler,
+};
+
static struct phy_driver nxp_c45_driver[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103),
.name = "NXP C45 TJA1103",
- .features = PHY_BASIC_T1_FEATURES,
+ .get_features = nxp_c45_get_features,
+ .driver_data = &tja1103_phy_data,
+ .probe = nxp_c45_probe,
+ .soft_reset = nxp_c45_soft_reset,
+ .config_aneg = genphy_c45_config_aneg,
+ .config_init = nxp_c45_config_init,
+ .config_intr = tja1103_config_intr,
+ .handle_interrupt = nxp_c45_handle_interrupt,
+ .read_status = genphy_c45_read_status,
+ .suspend = genphy_c45_pma_suspend,
+ .resume = genphy_c45_pma_resume,
+ .get_sset_count = nxp_c45_get_sset_count,
+ .get_strings = nxp_c45_get_strings,
+ .get_stats = nxp_c45_get_stats,
+ .cable_test_start = nxp_c45_cable_test_start,
+ .cable_test_get_status = nxp_c45_cable_test_get_status,
+ .set_loopback = genphy_c45_loopback,
+ .get_sqi = nxp_c45_get_sqi,
+ .get_sqi_max = nxp_c45_get_sqi_max,
+ .remove = nxp_c45_remove,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120),
+ .name = "NXP C45 TJA1120",
+ .get_features = nxp_c45_get_features,
+ .driver_data = &tja1120_phy_data,
.probe = nxp_c45_probe,
.soft_reset = nxp_c45_soft_reset,
- .config_aneg = nxp_c45_config_aneg,
+ .config_aneg = genphy_c45_config_aneg,
.config_init = nxp_c45_config_init,
- .config_intr = nxp_c45_config_intr,
+ .config_intr = tja1120_config_intr,
.handle_interrupt = nxp_c45_handle_interrupt,
- .read_status = nxp_c45_read_status,
+ .read_status = genphy_c45_read_status,
+ .link_change_notify = tja1120_link_change_notify,
.suspend = genphy_c45_pma_suspend,
.resume = genphy_c45_pma_resume,
.get_sset_count = nxp_c45_get_sset_count,
@@ -1378,6 +1967,7 @@ module_phy_driver(nxp_c45_driver);
static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) },
+ { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120) },
{ /*sentinel*/ },
};
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 93ed07223377..8e6fd4962c48 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -108,7 +108,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_setup_master_slave);
*/
int genphy_c45_pma_setup_forced(struct phy_device *phydev)
{
- int ctrl1, ctrl2, ret;
+ int bt1_ctrl, ctrl1, ctrl2, ret;
/* Half duplex is not supported */
if (phydev->duplex != DUPLEX_FULL)
@@ -176,6 +176,15 @@ int genphy_c45_pma_setup_forced(struct phy_device *phydev)
ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
if (ret < 0)
return ret;
+
+ bt1_ctrl = 0;
+ if (phydev->speed == SPEED_1000)
+ bt1_ctrl = MDIO_PMA_PMD_BT1_CTRL_STRAP_B1000;
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,
+ MDIO_PMA_PMD_BT1_CTRL_STRAP, bt1_ctrl);
+ if (ret < 0)
+ return ret;
}
return genphy_c45_an_disable_aneg(phydev);
@@ -873,6 +882,44 @@ int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
}
/**
+ * genphy_c45_pma_baset1_read_abilities - read supported baset1 link modes from PMA
+ * @phydev: target phy_device struct
+ *
+ * Read the supported link modes from the extended BASE-T1 ability register
+ */
+int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev)
+{
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B10L_ABLE);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B100_ABLE);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B1000_ABLE);
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ phydev->supported,
+ val & MDIO_AN_STAT1_ABLE);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
+
+/**
* genphy_c45_pma_read_abilities - read supported link modes from PMA
* @phydev: target phy_device struct
*
@@ -968,21 +1015,9 @@ int genphy_c45_pma_read_abilities(struct phy_device *phydev)
}
if (val & MDIO_PMA_EXTABLE_BT1) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1);
+ val = genphy_c45_pma_baset1_read_abilities(phydev);
if (val < 0)
return val;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_PMD_BT1_B10L_ABLE);
-
- val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
- if (val < 0)
- return val;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- phydev->supported,
- val & MDIO_AN_STAT1_ABLE);
}
}
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index a64186dc53f8..966c93cbe616 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -142,6 +142,8 @@ int phy_interface_num_ports(phy_interface_t interface)
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_QUSGMII:
return 4;
+ case PHY_INTERFACE_MODE_PSGMII:
+ return 5;
case PHY_INTERFACE_MODE_MAX:
WARN_ONCE(1, "PHY_INTERFACE_MODE_MAX isn't a valid interface mode");
return 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index bdf00b2b2c1d..df54c137c5f5 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -456,6 +456,40 @@ int phy_do_ioctl_running(struct net_device *dev, struct ifreq *ifr, int cmd)
EXPORT_SYMBOL(phy_do_ioctl_running);
/**
+ * __phy_hwtstamp_get - Get hardware timestamping configuration from PHY
+ *
+ * @phydev: the PHY device structure
+ * @config: structure holding the timestamping configuration
+ *
+ * Query the PHY device for its current hardware timestamping configuration.
+ */
+int __phy_hwtstamp_get(struct phy_device *phydev,
+ struct kernel_hwtstamp_config *config)
+{
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, config->ifr, SIOCGHWTSTAMP);
+}
+
+/**
+ * __phy_hwtstamp_set - Modify PHY hardware timestamping configuration
+ *
+ * @phydev: the PHY device structure
+ * @config: structure holding the timestamping configuration
+ * @extack: netlink extended ack structure, for error reporting
+ */
+int __phy_hwtstamp_set(struct phy_device *phydev,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
+{
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, config->ifr, SIOCSHWTSTAMP);
+}
+
+/**
* phy_queue_state_machine - Trigger the state machine to run soon
*
* @phydev: the phy_device struct
@@ -1184,9 +1218,11 @@ void phy_stop_machine(struct phy_device *phydev)
static void phy_process_error(struct phy_device *phydev)
{
- mutex_lock(&phydev->lock);
+ /* phydev->lock must be held for the state change to be safe */
+ if (!mutex_is_locked(&phydev->lock))
+ phydev_err(phydev, "PHY-device data unsafe context\n");
+
phydev->state = PHY_ERROR;
- mutex_unlock(&phydev->lock);
phy_trigger_machine(phydev);
}
@@ -1195,7 +1231,9 @@ static void phy_error_precise(struct phy_device *phydev,
const void *func, int err)
{
WARN(1, "%pS: returned: %d\n", func, err);
+ mutex_lock(&phydev->lock);
phy_process_error(phydev);
+ mutex_unlock(&phydev->lock);
}
/**
@@ -1204,8 +1242,7 @@ static void phy_error_precise(struct phy_device *phydev,
*
* Moves the PHY to the ERROR state in response to a read
* or write error, and tells the controller the link is down.
- * Must not be called from interrupt context, or while the
- * phydev->lock is held.
+ * Must be called with phydev->lock held.
*/
void phy_error(struct phy_device *phydev)
{
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c7cf61fe41cf..2ce74593d6e4 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -27,9 +27,11 @@
#include <linux/of.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
+#include <linux/phylib_stubs.h>
#include <linux/phy_led_triggers.h>
#include <linux/pse-pd/pse.h>
#include <linux/property.h>
+#include <linux/rtnetlink.h>
#include <linux/sfp.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
@@ -1487,8 +1489,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
if (phydev->sfp_bus_attached)
dev->sfp_bus = phydev->sfp_bus;
- else if (dev->sfp_bus)
- phydev->is_on_sfp_module = true;
}
/* Some Ethernet drivers try to connect to a PHY device before
@@ -3020,6 +3020,61 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
return err;
}
+static __maybe_unused struct device *
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+
+ if (phydev->attached_dev)
+ return &phydev->attached_dev->dev;
+ return NULL;
+}
+
+static int __maybe_unused
+phy_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int __maybe_unused
+phy_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
@@ -3057,6 +3112,19 @@ static int of_phy_led(struct phy_device *phydev,
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ if (phydev->drv->led_hw_is_supported &&
+ phydev->drv->led_hw_control_set &&
+ phydev->drv->led_hw_control_get) {
+ cdev->hw_control_is_supported = phy_led_hw_is_supported;
+ cdev->hw_control_set = phy_led_hw_control_set;
+ cdev->hw_control_get = phy_led_hw_control_get;
+ cdev->hw_control_trigger = "netdev";
+ }
+
+ cdev->hw_control_get_device = phy_led_hw_control_get_device;
+#endif
cdev->max_brightness = 1;
init_data.devicename = dev_name(&phydev->mdio.dev);
init_data.fwnode = of_fwnode_handle(led);
@@ -3438,11 +3506,29 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
.start_cable_test_tdr = phy_start_cable_test_tdr,
};
+static const struct phylib_stubs __phylib_stubs = {
+ .hwtstamp_get = __phy_hwtstamp_get,
+ .hwtstamp_set = __phy_hwtstamp_set,
+};
+
+static void phylib_register_stubs(void)
+{
+ phylib_stubs = &__phylib_stubs;
+}
+
+static void phylib_unregister_stubs(void)
+{
+ phylib_stubs = NULL;
+}
+
static int __init phy_init(void)
{
int rc;
+ rtnl_lock();
ethtool_set_ethtool_phy_ops(&phy_ethtool_phy_ops);
+ phylib_register_stubs();
+ rtnl_unlock();
rc = mdio_bus_init();
if (rc)
@@ -3465,7 +3551,10 @@ err_c45:
err_mdio_bus:
mdio_bus_exit();
err_ethtool_phy_ops:
+ rtnl_lock();
+ phylib_unregister_stubs();
ethtool_set_ethtool_phy_ops(NULL);
+ rtnl_unlock();
return rc;
}
@@ -3475,7 +3564,10 @@ static void __exit phy_exit(void)
phy_driver_unregister(&genphy_c45_driver);
phy_driver_unregister(&genphy_driver);
mdio_bus_exit();
+ rtnl_lock();
+ phylib_unregister_stubs();
ethtool_set_ethtool_phy_ops(NULL);
+ rtnl_unlock();
}
subsys_initcall(phy_init);
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index d0aaa5cad853..0d7354955d62 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -34,6 +34,10 @@ enum {
PHYLINK_DISABLE_STOPPED,
PHYLINK_DISABLE_LINK,
PHYLINK_DISABLE_MAC_WOL,
+
+ PCS_STATE_DOWN = 0,
+ PCS_STATE_STARTING,
+ PCS_STATE_STARTED,
};
/**
@@ -72,6 +76,7 @@ struct phylink {
struct phylink_link_state phy_state;
struct work_struct resolve;
unsigned int pcs_neg_mode;
+ unsigned int pcs_state;
bool mac_link_dropped;
bool using_mac_select_pcs;
@@ -205,6 +210,7 @@ static int phylink_interface_max_speed(phy_interface_t interface)
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_PSGMII:
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_QUSGMII:
case PHY_INTERFACE_MODE_SGMII:
@@ -421,6 +427,24 @@ static struct {
};
/**
+ * phylink_limit_mac_speed - limit the phylink_config to a maximum speed
+ * @config: pointer to a &struct phylink_config
+ * @max_speed: maximum speed
+ *
+ * Mask off MAC capabilities for speeds higher than the @max_speed parameter.
+ * Any further motifications of config.mac_capabilities will override this.
+ */
+void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(phylink_caps_params) &&
+ phylink_caps_params[i].speed > max_speed; i++)
+ config->mac_capabilities &= ~phylink_caps_params[i].mask;
+}
+EXPORT_SYMBOL_GPL(phylink_limit_mac_speed);
+
+/**
* phylink_cap_from_speed_duplex - Get mac capability from speed/duplex
* @speed: the speed to search for
* @duplex: the duplex to search for
@@ -470,6 +494,7 @@ unsigned long phylink_get_capabilities(phy_interface_t interface,
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_PSGMII:
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_QUSGMII:
case PHY_INTERFACE_MODE_SGMII:
@@ -863,6 +888,7 @@ static int phylink_parse_mode(struct phylink *pl,
switch (pl->link_config.interface) {
case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_PSGMII:
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_QUSGMII:
case PHY_INTERFACE_MODE_RGMII:
@@ -993,6 +1019,40 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state)
}
}
+static void phylink_pcs_pre_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ if (pcs && pcs->ops->pcs_pre_config)
+ pcs->ops->pcs_pre_config(pcs, interface);
+}
+
+static int phylink_pcs_post_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ int err = 0;
+
+ if (pcs && pcs->ops->pcs_post_config)
+ err = pcs->ops->pcs_post_config(pcs, interface);
+
+ return err;
+}
+
+static void phylink_pcs_disable(struct phylink_pcs *pcs)
+{
+ if (pcs && pcs->ops->pcs_disable)
+ pcs->ops->pcs_disable(pcs);
+}
+
+static int phylink_pcs_enable(struct phylink_pcs *pcs)
+{
+ int err = 0;
+
+ if (pcs && pcs->ops->pcs_enable)
+ err = pcs->ops->pcs_enable(pcs);
+
+ return err;
+}
+
static int phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
const struct phylink_link_state *state,
bool permit_pause_to_mac)
@@ -1027,30 +1087,33 @@ static void phylink_pcs_poll_start(struct phylink *pl)
static void phylink_mac_config(struct phylink *pl,
const struct phylink_link_state *state)
{
+ struct phylink_link_state st = *state;
+
+ /* Stop drivers incorrectly using these */
+ linkmode_zero(st.lp_advertising);
+ st.speed = SPEED_UNKNOWN;
+ st.duplex = DUPLEX_UNKNOWN;
+ st.an_complete = false;
+ st.link = false;
+
phylink_dbg(pl,
- "%s: mode=%s/%s/%s/%s/%s adv=%*pb pause=%02x link=%u\n",
+ "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n",
__func__, phylink_an_mode_str(pl->cur_link_an_mode),
- phy_modes(state->interface),
- phy_speed_to_str(state->speed),
- phy_duplex_to_str(state->duplex),
- phy_rate_matching_to_str(state->rate_matching),
- __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
- state->pause, state->link);
+ phy_modes(st.interface),
+ phy_rate_matching_to_str(st.rate_matching),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising,
+ st.pause);
- pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state);
+ pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st);
}
-static void phylink_mac_pcs_an_restart(struct phylink *pl)
+static void phylink_pcs_an_restart(struct phylink *pl)
{
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
- pl->link_config.advertising) &&
+ if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ pl->link_config.advertising) &&
phy_interface_mode_is_8023z(pl->link_config.interface) &&
- phylink_autoneg_inband(pl->cur_link_an_mode)) {
- if (pl->pcs)
- pl->pcs->ops->pcs_an_restart(pl->pcs);
- else if (pl->config->legacy_pre_march2020)
- pl->mac_ops->mac_an_restart(pl->config);
- }
+ phylink_autoneg_inband(pl->cur_link_an_mode))
+ pl->pcs->ops->pcs_an_restart(pl->pcs);
}
static void phylink_major_config(struct phylink *pl, bool restart,
@@ -1095,11 +1158,28 @@ static void phylink_major_config(struct phylink *pl, bool restart,
/* If we have a new PCS, switch to the new PCS after preparing the MAC
* for the change.
*/
- if (pcs_changed)
+ if (pcs_changed) {
+ phylink_pcs_disable(pl->pcs);
+
+ if (pl->pcs)
+ pl->pcs->phylink = NULL;
+
+ pcs->phylink = pl;
+
pl->pcs = pcs;
+ }
+
+ if (pl->pcs)
+ phylink_pcs_pre_config(pl->pcs, state->interface);
phylink_mac_config(pl, state);
+ if (pl->pcs)
+ phylink_pcs_post_config(pl->pcs, state->interface);
+
+ if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed)
+ phylink_pcs_enable(pl->pcs);
+
neg_mode = pl->cur_link_an_mode;
if (pl->pcs && pl->pcs->neg_mode)
neg_mode = pl->pcs_neg_mode;
@@ -1113,7 +1193,7 @@ static void phylink_major_config(struct phylink *pl, bool restart,
restart = true;
if (restart)
- phylink_mac_pcs_an_restart(pl);
+ phylink_pcs_an_restart(pl);
if (pl->mac_ops->mac_finish) {
err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
@@ -1146,13 +1226,6 @@ static int phylink_change_inband_advert(struct phylink *pl)
if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state))
return 0;
- if (!pl->pcs && pl->config->legacy_pre_march2020) {
- /* Legacy method */
- phylink_mac_config(pl, &pl->link_config);
- phylink_mac_pcs_an_restart(pl);
- return 0;
- }
-
phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__,
phylink_an_mode_str(pl->cur_link_an_mode),
phy_modes(pl->link_config.interface),
@@ -1178,7 +1251,7 @@ static int phylink_change_inband_advert(struct phylink *pl)
return ret;
if (ret > 0)
- phylink_mac_pcs_an_restart(pl);
+ phylink_pcs_an_restart(pl);
return 0;
}
@@ -1205,9 +1278,6 @@ static void phylink_mac_pcs_get_state(struct phylink *pl,
if (pl->pcs)
pl->pcs->ops->pcs_get_state(pl->pcs, state);
- else if (pl->mac_ops->mac_pcs_get_state &&
- pl->config->legacy_pre_march2020)
- pl->mac_ops->mac_pcs_get_state(pl->config, state);
else
state->link = 0;
}
@@ -1440,13 +1510,6 @@ static void phylink_resolve(struct work_struct *w)
}
phylink_major_config(pl, false, &link_state);
pl->link_config.interface = link_state.interface;
- } else if (!pl->pcs && pl->config->legacy_pre_march2020) {
- /* The interface remains unchanged, only the speed,
- * duplex or pause settings have changed. Call the
- * old mac_config() method to configure the MAC/PCS
- * only if we do not have a legacy MAC driver.
- */
- phylink_mac_config(pl, &link_state);
}
}
@@ -1586,6 +1649,7 @@ struct phylink *phylink_create(struct phylink_config *config,
pl->link_config.pause = MLO_PAUSE_AN;
pl->link_config.speed = SPEED_UNKNOWN;
pl->link_config.duplex = DUPLEX_UNKNOWN;
+ pl->pcs_state = PCS_STATE_DOWN;
pl->mac_ops = mac_ops;
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
@@ -1939,6 +2003,14 @@ void phylink_disconnect_phy(struct phylink *pl)
}
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;
+ phylink_run_resolve(pl);
+ phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
+}
+
/**
* phylink_mac_change() - notify phylink of a change in MAC state
* @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -1949,13 +2021,30 @@ EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
*/
void phylink_mac_change(struct phylink *pl, bool up)
{
- if (!up)
- pl->mac_link_dropped = true;
- phylink_run_resolve(pl);
- phylink_dbg(pl, "mac link %s\n", up ? "up" : "down");
+ phylink_link_changed(pl, up, "mac");
}
EXPORT_SYMBOL_GPL(phylink_mac_change);
+/**
+ * phylink_pcs_change() - notify phylink of a change to PCS link state
+ * @pcs: pointer to &struct phylink_pcs
+ * @up: indicates whether the link is currently up.
+ *
+ * The PCS driver should call this when the state of its link changes
+ * (e.g. link failure, new negotiation results, etc.) Note: it should
+ * not determine "up" by reading the BMSR. If in doubt about the link
+ * state at interrupt time, then pass true if pcs_get_state() returns
+ * the latched link-down state, otherwise pass false.
+ */
+void phylink_pcs_change(struct phylink_pcs *pcs, bool up)
+{
+ struct phylink *pl = pcs->phylink;
+
+ if (pl)
+ phylink_link_changed(pl, up, "pcs");
+}
+EXPORT_SYMBOL_GPL(phylink_pcs_change);
+
static irqreturn_t phylink_link_handler(int irq, void *data)
{
struct phylink *pl = data;
@@ -1987,6 +2076,8 @@ void phylink_start(struct phylink *pl)
if (pl->netdev)
netif_carrier_off(pl->netdev);
+ pl->pcs_state = PCS_STATE_STARTING;
+
/* Apply the link configuration to the MAC when starting. This allows
* a fixed-link to start with the correct parameters, and also
* ensures that we set the appropriate advertisement for Serdes links.
@@ -1997,6 +2088,8 @@ void phylink_start(struct phylink *pl)
*/
phylink_mac_initial_config(pl, true);
+ pl->pcs_state = PCS_STATE_STARTED;
+
phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_STOPPED);
if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
@@ -2015,15 +2108,9 @@ void phylink_start(struct phylink *pl)
poll = true;
}
- switch (pl->cfg_link_an_mode) {
- case MLO_AN_FIXED:
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED)
poll |= pl->config->poll_fixed_state;
- break;
- case MLO_AN_INBAND:
- if (pl->pcs)
- poll |= pl->pcs->poll;
- break;
- }
+
if (poll)
mod_timer(&pl->link_poll, jiffies + HZ);
if (pl->phydev)
@@ -2060,6 +2147,10 @@ void phylink_stop(struct phylink *pl)
}
phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
+
+ pl->pcs_state = PCS_STATE_DOWN;
+
+ phylink_pcs_disable(pl->pcs);
}
EXPORT_SYMBOL_GPL(phylink_stop);
@@ -2449,7 +2540,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)
if (pl->phydev)
ret = phy_restart_aneg(pl->phydev);
- phylink_mac_pcs_an_restart(pl);
+ phylink_pcs_an_restart(pl);
return ret;
}
@@ -3433,7 +3524,7 @@ static void phylink_decode_usgmii_word(struct phylink_link_state *state,
*
* Parse the Clause 37 or Cisco SGMII link partner negotiation word into
* the phylink @state structure. This is suitable to be used for implementing
- * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if
+ * the pcs_get_state() member of the struct phylink_pcs_ops structure if
* accessing @bmsr and @lpa cannot be done with MDIO directly.
*/
void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
@@ -3483,7 +3574,7 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state);
* Read the MAC PCS state from the MII device configured in @config and
* parse the Clause 37 or Cisco SGMII link partner negotiation word into
* the phylink @state structure. This is suitable to be directly plugged
- * into the mac_pcs_get_state() member of the struct phylink_mac_ops
+ * into the pcs_get_state() member of the struct phylink_pcs_ops
* structure.
*/
void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
@@ -3594,8 +3685,8 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config);
* clause 37 negotiation.
*
* Restart the clause 37 negotiation with the link partner. This is
- * suitable to be directly plugged into the mac_pcs_get_state() member
- * of the struct phylink_mac_ops structure.
+ * suitable to be directly plugged into the pcs_get_state() member
+ * of the struct phylink_pcs_ops structure.
*/
void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs)
{
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index e8dd47bffe43..208a9393c2df 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -258,6 +258,16 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
switch (id->base.extended_cc) {
case SFF8024_ECC_UNSPEC:
break;
+ case SFF8024_ECC_100G_25GAUI_C2M_AOC:
+ if (br_min <= 28000 && br_max >= 25000) {
+ /* 25GBASE-R, possibly with FEC */
+ __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
+ /* There is currently no link mode for 25000base
+ * with unspecified range, reuse SR.
+ */
+ phylink_set(modes, 25000baseSR_Full);
+ }
+ break;
case SFF8024_ECC_100GBASE_SR4_25GBASE_SR:
phylink_set(modes, 100000baseSR4_Full);
phylink_set(modes, 25000baseSR_Full);
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index d855a18308d7..4ecfac227865 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1763,6 +1763,9 @@ static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
return PTR_ERR(phy);
}
+ /* Mark this PHY as being on a SFP module */
+ phy->is_on_sfp_module = true;
+
err = phy_device_register(phy);
if (err) {
phy_device_free(phy);
diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h
index c7cb50d10099..1fd097dccb9f 100644
--- a/drivers/net/phy/sfp.h
+++ b/drivers/net/phy/sfp.h
@@ -37,7 +37,6 @@ int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
void sfp_module_remove(struct sfp_bus *bus);
int sfp_module_start(struct sfp_bus *bus);
void sfp_module_stop(struct sfp_bus *bus);
-int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
const struct sfp_socket_ops *ops);
void sfp_unregister_socket(struct sfp_bus *bus);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 692930750215..c88edb19d2e7 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -20,6 +20,8 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
+#include <linux/crc16.h>
+#include <linux/etherdevice.h>
#include <linux/smscphy.h>
/* Vendor-specific PHY Definitions */
@@ -51,6 +53,7 @@ struct smsc_phy_priv {
unsigned int edpd_enable:1;
unsigned int edpd_mode_set_by_user:1;
unsigned int edpd_max_wait_ms;
+ bool wol_arp;
};
static int smsc_phy_ack_interrupt(struct phy_device *phydev)
@@ -258,6 +261,243 @@ int lan87xx_read_status(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(lan87xx_read_status);
+static int lan874x_phy_config_init(struct phy_device *phydev)
+{
+ u16 val;
+ int rc;
+
+ /* Setup LED2/nINT/nPME pin to function as nPME. May need user option
+ * to use LED1/nINT/nPME.
+ */
+ val = MII_LAN874X_PHY_PME2_SET;
+
+ /* The bits MII_LAN874X_PHY_WOL_PFDA_FR, MII_LAN874X_PHY_WOL_WUFR,
+ * MII_LAN874X_PHY_WOL_MPR, and MII_LAN874X_PHY_WOL_BCAST_FR need to
+ * be cleared to de-assert PME signal after a WoL event happens, but
+ * using PME auto clear gets around that.
+ */
+ val |= MII_LAN874X_PHY_PME_SELF_CLEAR;
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,
+ val);
+ if (rc < 0)
+ return rc;
+
+ /* set nPME self clear delay time */
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_MCFGR,
+ MII_LAN874X_PHY_PME_SELF_CLEAR_DELAY);
+ if (rc < 0)
+ return rc;
+
+ return smsc_phy_config_init(phydev);
+}
+
+static void lan874x_get_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ struct smsc_phy_priv *priv = phydev->priv;
+ int rc;
+
+ wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC |
+ WAKE_ARP | WAKE_MCAST);
+ wol->wolopts = 0;
+
+ rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);
+ if (rc < 0)
+ return;
+
+ if (rc & MII_LAN874X_PHY_WOL_PFDAEN)
+ wol->wolopts |= WAKE_UCAST;
+
+ if (rc & MII_LAN874X_PHY_WOL_BCSTEN)
+ wol->wolopts |= WAKE_BCAST;
+
+ if (rc & MII_LAN874X_PHY_WOL_MPEN)
+ wol->wolopts |= WAKE_MAGIC;
+
+ if (rc & MII_LAN874X_PHY_WOL_WUEN) {
+ if (priv->wol_arp)
+ wol->wolopts |= WAKE_ARP;
+ else
+ wol->wolopts |= WAKE_MCAST;
+ }
+}
+
+static u16 smsc_crc16(const u8 *buffer, size_t len)
+{
+ return bitrev16(crc16(0xFFFF, buffer, len));
+}
+
+static int lan874x_chk_wol_pattern(const u8 pattern[], const u16 *mask,
+ u8 len, u8 *data, u8 *datalen)
+{
+ size_t i, j, k;
+ int ret = 0;
+ u16 bits;
+
+ /* Pattern filtering can match up to 128 bytes of frame data. There
+ * are 8 registers to program the 16-bit masks, where each bit means
+ * the byte will be compared. The frame data will then go through a
+ * CRC16 calculation for hardware comparison. This helper function
+ * makes sure only relevant frame data are included in this
+ * calculation. It provides a warning when the masks and expected
+ * data size do not match.
+ */
+ i = 0;
+ k = 0;
+ while (len > 0) {
+ bits = *mask;
+ for (j = 0; j < 16; j++, i++, len--) {
+ /* No more pattern. */
+ if (!len) {
+ /* The rest of bitmap is not empty. */
+ if (bits)
+ ret = i + 1;
+ break;
+ }
+ if (bits & 1)
+ data[k++] = pattern[i];
+ bits >>= 1;
+ }
+ mask++;
+ }
+ *datalen = k;
+ return ret;
+}
+
+static int lan874x_set_wol_pattern(struct phy_device *phydev, u16 val,
+ const u8 data[], u8 datalen,
+ const u16 *mask, u8 masklen)
+{
+ u16 crc, reg;
+ int rc;
+
+ /* Starting pattern offset is set before calling this function. */
+ val |= MII_LAN874X_PHY_WOL_FILTER_EN;
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS,
+ MII_LAN874X_PHY_MMD_WOL_WUF_CFGA, val);
+ if (rc < 0)
+ return rc;
+
+ crc = smsc_crc16(data, datalen);
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS,
+ MII_LAN874X_PHY_MMD_WOL_WUF_CFGB, crc);
+ if (rc < 0)
+ return rc;
+
+ masklen = (masklen + 15) & ~0xf;
+ reg = MII_LAN874X_PHY_MMD_WOL_WUF_MASK7;
+ while (masklen >= 16) {
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg, *mask);
+ if (rc < 0)
+ return rc;
+ reg--;
+ mask++;
+ masklen -= 16;
+ }
+
+ /* Clear out the rest of mask registers. */
+ while (reg != MII_LAN874X_PHY_MMD_WOL_WUF_MASK0) {
+ phy_write_mmd(phydev, MDIO_MMD_PCS, reg, 0);
+ reg--;
+ }
+ return rc;
+}
+
+static int lan874x_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ struct net_device *ndev = phydev->attached_dev;
+ struct smsc_phy_priv *priv = phydev->priv;
+ u16 val, val_wucsr;
+ u8 data[128];
+ u8 datalen;
+ int rc;
+
+ /* lan874x has only one WoL filter pattern */
+ if ((wol->wolopts & (WAKE_ARP | WAKE_MCAST)) ==
+ (WAKE_ARP | WAKE_MCAST)) {
+ phydev_info(phydev,
+ "lan874x WoL supports one of ARP|MCAST at a time\n");
+ return -EOPNOTSUPP;
+ }
+
+ rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);
+ if (rc < 0)
+ return rc;
+
+ val_wucsr = rc;
+
+ if (wol->wolopts & WAKE_UCAST)
+ val_wucsr |= MII_LAN874X_PHY_WOL_PFDAEN;
+ else
+ val_wucsr &= ~MII_LAN874X_PHY_WOL_PFDAEN;
+
+ if (wol->wolopts & WAKE_BCAST)
+ val_wucsr |= MII_LAN874X_PHY_WOL_BCSTEN;
+ else
+ val_wucsr &= ~MII_LAN874X_PHY_WOL_BCSTEN;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ val_wucsr |= MII_LAN874X_PHY_WOL_MPEN;
+ else
+ val_wucsr &= ~MII_LAN874X_PHY_WOL_MPEN;
+
+ /* Need to use pattern matching */
+ if (wol->wolopts & (WAKE_ARP | WAKE_MCAST))
+ val_wucsr |= MII_LAN874X_PHY_WOL_WUEN;
+ else
+ val_wucsr &= ~MII_LAN874X_PHY_WOL_WUEN;
+
+ if (wol->wolopts & WAKE_ARP) {
+ const u8 pattern[2] = { 0x08, 0x06 };
+ const u16 mask[1] = { 0x0003 };
+
+ rc = lan874x_chk_wol_pattern(pattern, mask, 2, data,
+ &datalen);
+ if (rc)
+ phydev_dbg(phydev, "pattern not valid at %d\n", rc);
+
+ /* Need to match broadcast destination address and provided
+ * data pattern at offset 12.
+ */
+ val = 12 | MII_LAN874X_PHY_WOL_FILTER_BCSTEN;
+ rc = lan874x_set_wol_pattern(phydev, val, data, datalen, mask,
+ 2);
+ if (rc < 0)
+ return rc;
+ priv->wol_arp = true;
+ }
+
+ if (wol->wolopts & WAKE_MCAST) {
+ /* Need to match multicast destination address. */
+ val = MII_LAN874X_PHY_WOL_FILTER_MCASTTEN;
+ rc = lan874x_set_wol_pattern(phydev, val, data, 0, NULL, 0);
+ if (rc < 0)
+ return rc;
+ priv->wol_arp = false;
+ }
+
+ if (wol->wolopts & (WAKE_MAGIC | WAKE_UCAST)) {
+ const u8 *mac = (const u8 *)ndev->dev_addr;
+ int i, reg;
+
+ reg = MII_LAN874X_PHY_MMD_WOL_RX_ADDRC;
+ for (i = 0; i < 6; i += 2, reg--) {
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg,
+ ((mac[i + 1] << 8) | mac[i]));
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,
+ val_wucsr);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
static int smsc_get_sset_count(struct phy_device *phydev)
{
return ARRAY_SIZE(smsc_hw_stats);
@@ -533,7 +773,7 @@ static struct phy_driver smsc_phy_driver[] = {
/* basic functions */
.read_status = lan87xx_read_status,
- .config_init = smsc_phy_config_init,
+ .config_init = lan874x_phy_config_init,
.soft_reset = smsc_phy_reset,
/* IRQ related */
@@ -548,6 +788,10 @@ static struct phy_driver smsc_phy_driver[] = {
.get_tunable = smsc_phy_get_tunable,
.set_tunable = smsc_phy_set_tunable,
+ /* WoL */
+ .set_wol = lan874x_set_wol,
+ .get_wol = lan874x_get_wol,
+
.suspend = genphy_suspend,
.resume = genphy_resume,
}, {
@@ -566,7 +810,7 @@ static struct phy_driver smsc_phy_driver[] = {
/* basic functions */
.read_status = lan87xx_read_status,
- .config_init = smsc_phy_config_init,
+ .config_init = lan874x_phy_config_init,
.soft_reset = smsc_phy_reset,
/* IRQ related */
@@ -581,6 +825,10 @@ static struct phy_driver smsc_phy_driver[] = {
.get_tunable = smsc_phy_get_tunable,
.set_tunable = smsc_phy_set_tunable,
+ /* WoL */
+ .set_wol = lan874x_set_wol,
+ .get_wol = lan874x_get_wol,
+
.suspend = genphy_suspend,
.resume = genphy_resume,
} };
diff --git a/drivers/net/phy/stubs.c b/drivers/net/phy/stubs.c
new file mode 100644
index 000000000000..cfb9f275eb18
--- /dev/null
+++ b/drivers/net/phy/stubs.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Stubs for PHY library functionality called by the core network stack.
+ * These are necessary because CONFIG_PHYLIB can be a module, and built-in
+ * code cannot directly call symbols exported by modules.
+ */
+#include <linux/phylib_stubs.h>
+
+const struct phylib_stubs *phylib_stubs;
+EXPORT_SYMBOL_GPL(phylib_stubs);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 3b79c603b936..ba8b6bd8233c 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -968,7 +968,7 @@ abort:
***********************************************************************/
static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
- struct sock *sk = (struct sock *)chan->private;
+ struct sock *sk = chan->private;
return __pppoe_xmit(sk, skb);
}
@@ -976,7 +976,7 @@ static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path,
const struct ppp_channel *chan)
{
- struct sock *sk = (struct sock *)chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 32183f24e63f..6833ef0c7930 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -129,10 +129,10 @@ static void del_chan(struct pppox_sock *sock)
spin_unlock(&chan_lock);
}
-static struct rtable *pptp_route_output(struct pppox_sock *po,
+static struct rtable *pptp_route_output(const struct pppox_sock *po,
struct flowi4 *fl4)
{
- struct sock *sk = &po->sk;
+ const struct sock *sk = &po->sk;
struct net *net;
net = sock_net(sk);
@@ -148,7 +148,7 @@ static struct rtable *pptp_route_output(struct pppox_sock *po,
static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
- struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct net *net = sock_net(sk);
struct pptp_opt *opt = &po->proto.pptp;
@@ -575,7 +575,7 @@ out:
static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
unsigned long arg)
{
- struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
void __user *argp = (void __user *)arg;
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 49d1d6acf95e..5c01cc7b9949 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -22,6 +22,7 @@
#include <net/net_namespace.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
+#include <net/xdp.h>
#include <linux/virtio_net.h>
#include <linux/skb_array.h>
@@ -614,8 +615,10 @@ static inline struct sk_buff *tap_alloc_skb(struct sock *sk, size_t prepad,
if (prepad + len < PAGE_SIZE || !linear)
linear = len;
+ if (len - linear > MAX_SKB_FRAGS * (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+ linear = len - MAX_SKB_FRAGS * (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER);
skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock,
- err, 0);
+ err, PAGE_ALLOC_COSTLY_ORDER);
if (!skb)
return NULL;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 382756c3fb83..e8b94580194e 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -149,7 +149,6 @@ static int __team_option_inst_add(struct team *team, struct team_option *option,
struct team_option_inst *opt_inst;
unsigned int array_size;
unsigned int i;
- int err;
array_size = option->array_size;
if (!array_size)
@@ -165,11 +164,8 @@ static int __team_option_inst_add(struct team *team, struct team_option *option,
opt_inst->changed = true;
opt_inst->removed = false;
list_add_tail(&opt_inst->list, &team->option_inst_list);
- if (option->init) {
- err = option->init(team, &opt_inst->info);
- if (err)
- return err;
- }
+ if (option->init)
+ option->init(team, &opt_inst->info);
}
return 0;
@@ -362,7 +358,9 @@ static int team_option_get(struct team *team,
{
if (!opt_inst->option->getter)
return -EOPNOTSUPP;
- return opt_inst->option->getter(team, ctx);
+
+ opt_inst->option->getter(team, ctx);
+ return 0;
}
static int team_option_set(struct team *team,
@@ -1377,10 +1375,9 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
* Net device ops
*****************/
-static int team_mode_option_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void team_mode_option_get(struct team *team, struct team_gsetter_ctx *ctx)
{
ctx->data.str_val = team->mode->kind;
- return 0;
}
static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
@@ -1388,11 +1385,10 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
return team_change_mode(team, ctx->data.str_val);
}
-static int team_notify_peers_count_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_notify_peers_count_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->notify_peers.count;
- return 0;
}
static int team_notify_peers_count_set(struct team *team,
@@ -1402,11 +1398,10 @@ static int team_notify_peers_count_set(struct team *team,
return 0;
}
-static int team_notify_peers_interval_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_notify_peers_interval_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->notify_peers.interval;
- return 0;
}
static int team_notify_peers_interval_set(struct team *team,
@@ -1416,11 +1411,10 @@ static int team_notify_peers_interval_set(struct team *team,
return 0;
}
-static int team_mcast_rejoin_count_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_mcast_rejoin_count_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->mcast_rejoin.count;
- return 0;
}
static int team_mcast_rejoin_count_set(struct team *team,
@@ -1430,11 +1424,10 @@ static int team_mcast_rejoin_count_set(struct team *team,
return 0;
}
-static int team_mcast_rejoin_interval_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_mcast_rejoin_interval_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
ctx->data.u32_val = team->mcast_rejoin.interval;
- return 0;
}
static int team_mcast_rejoin_interval_set(struct team *team,
@@ -1444,13 +1437,12 @@ static int team_mcast_rejoin_interval_set(struct team *team,
return 0;
}
-static int team_port_en_option_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_port_en_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
ctx->data.bool_val = team_port_enabled(port);
- return 0;
}
static int team_port_en_option_set(struct team *team,
@@ -1465,13 +1457,12 @@ static int team_port_en_option_set(struct team *team,
return 0;
}
-static int team_user_linkup_option_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_user_linkup_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
ctx->data.bool_val = port->user.linkup;
- return 0;
}
static void __team_carrier_check(struct team *team);
@@ -1487,13 +1478,12 @@ static int team_user_linkup_option_set(struct team *team,
return 0;
}
-static int team_user_linkup_en_option_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_user_linkup_en_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
ctx->data.bool_val = port->user.linkup_enabled;
- return 0;
}
static int team_user_linkup_en_option_set(struct team *team,
@@ -1507,13 +1497,12 @@ static int team_user_linkup_en_option_set(struct team *team,
return 0;
}
-static int team_priority_option_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_priority_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
ctx->data.s32_val = port->priority;
- return 0;
}
static int team_priority_option_set(struct team *team,
@@ -1529,13 +1518,12 @@ static int team_priority_option_set(struct team *team,
return 0;
}
-static int team_queue_id_option_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void team_queue_id_option_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
ctx->data.u32_val = port->queue_id;
- return 0;
}
static int team_queue_id_option_set(struct team *team,
@@ -2323,8 +2311,7 @@ static struct team *team_nl_team_get(struct genl_info *info)
ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
dev = dev_get_by_index(net, ifindex);
if (!dev || dev->netdev_ops != &team_netdev_ops) {
- if (dev)
- dev_put(dev);
+ dev_put(dev);
return NULL;
}
@@ -2895,7 +2882,7 @@ static int __init team_nl_init(void)
return genl_register_family(&team_nl_family);
}
-static void team_nl_fini(void)
+static void __exit team_nl_fini(void)
{
genl_unregister_family(&team_nl_family);
}
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
index 3147a4fdf8d9..e0f599e2a51d 100644
--- a/drivers/net/team/team_mode_activebackup.c
+++ b/drivers/net/team/team_mode_activebackup.c
@@ -57,14 +57,13 @@ static void ab_port_leave(struct team *team, struct team_port *port)
}
}
-static int ab_active_port_init(struct team *team,
- struct team_option_inst_info *info)
+static void ab_active_port_init(struct team *team,
+ struct team_option_inst_info *info)
{
ab_priv(team)->ap_opt_inst_info = info;
- return 0;
}
-static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct team_port *active_port;
@@ -74,7 +73,6 @@ static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
ctx->data.u32_val = active_port->dev->ifindex;
else
ctx->data.u32_val = 0;
- return 0;
}
static int ab_active_port_set(struct team *team, struct team_gsetter_ctx *ctx)
diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c
index 313a3e2d68bf..61d7d79f0c36 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -8,7 +8,6 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/if_team.h>
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 18d99fda997c..00f8989c29c0 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -30,8 +30,6 @@ static rx_handler_result_t lb_receive(struct team *team, struct team_port *port,
struct lb_priv;
typedef struct team_port *lb_select_tx_port_func_t(struct team *,
- struct lb_priv *,
- struct sk_buff *,
unsigned char);
#define LB_TX_HASHTABLE_SIZE 256 /* hash is a char */
@@ -118,8 +116,6 @@ static void lb_tx_hash_to_port_mapping_null_port(struct team *team,
/* Basic tx selection based solely by hash */
static struct team_port *lb_hash_select_tx_port(struct team *team,
- struct lb_priv *lb_priv,
- struct sk_buff *skb,
unsigned char hash)
{
int port_index = team_num_to_port_index(team, hash);
@@ -129,17 +125,16 @@ static struct team_port *lb_hash_select_tx_port(struct team *team,
/* Hash to port mapping select tx port */
static struct team_port *lb_htpm_select_tx_port(struct team *team,
- struct lb_priv *lb_priv,
- struct sk_buff *skb,
unsigned char hash)
{
+ struct lb_priv *lb_priv = get_lb_priv(team);
struct team_port *port;
port = rcu_dereference_bh(LB_HTPM_PORT_BY_HASH(lb_priv, hash));
if (likely(port))
return port;
/* If no valid port in the table, fall back to simple hash */
- return lb_hash_select_tx_port(team, lb_priv, skb, hash);
+ return lb_hash_select_tx_port(team, hash);
}
struct lb_select_tx_port {
@@ -229,7 +224,7 @@ static bool lb_transmit(struct team *team, struct sk_buff *skb)
hash = lb_get_skb_hash(lb_priv, skb);
select_tx_port_func = rcu_dereference_bh(lb_priv->select_tx_port_func);
- port = select_tx_port_func(team, lb_priv, skb, hash);
+ port = select_tx_port_func(team, hash);
if (unlikely(!port))
goto drop;
if (team_dev_queue_xmit(team, port, skb))
@@ -242,19 +237,18 @@ drop:
return false;
}
-static int lb_bpf_func_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void lb_bpf_func_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
if (!lb_priv->ex->orig_fprog) {
ctx->data.bin_val.len = 0;
ctx->data.bin_val.ptr = NULL;
- return 0;
+ return;
}
ctx->data.bin_val.len = lb_priv->ex->orig_fprog->len *
sizeof(struct sock_filter);
ctx->data.bin_val.ptr = lb_priv->ex->orig_fprog->filter;
- return 0;
}
static int __fprog_create(struct sock_fprog_kern **pfprog, u32 data_len,
@@ -335,7 +329,7 @@ static void lb_bpf_func_free(struct team *team)
bpf_prog_destroy(fp);
}
-static int lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
lb_select_tx_port_func_t *func;
@@ -346,7 +340,6 @@ static int lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
name = lb_select_tx_port_get_name(func);
BUG_ON(!name);
ctx->data.str_val = name;
- return 0;
}
static int lb_tx_method_set(struct team *team, struct team_gsetter_ctx *ctx)
@@ -361,18 +354,17 @@ static int lb_tx_method_set(struct team *team, struct team_gsetter_ctx *ctx)
return 0;
}
-static int lb_tx_hash_to_port_mapping_init(struct team *team,
- struct team_option_inst_info *info)
+static void lb_tx_hash_to_port_mapping_init(struct team *team,
+ struct team_option_inst_info *info)
{
struct lb_priv *lb_priv = get_lb_priv(team);
unsigned char hash = info->array_index;
LB_HTPM_OPT_INST_INFO_BY_HASH(lb_priv, hash) = info;
- return 0;
}
-static int lb_tx_hash_to_port_mapping_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void lb_tx_hash_to_port_mapping_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
struct team_port *port;
@@ -380,7 +372,6 @@ static int lb_tx_hash_to_port_mapping_get(struct team *team,
port = LB_HTPM_PORT_BY_HASH(lb_priv, hash);
ctx->data.u32_val = port ? port->dev->ifindex : 0;
- return 0;
}
static int lb_tx_hash_to_port_mapping_set(struct team *team,
@@ -401,44 +392,40 @@ static int lb_tx_hash_to_port_mapping_set(struct team *team,
return -ENODEV;
}
-static int lb_hash_stats_init(struct team *team,
- struct team_option_inst_info *info)
+static void lb_hash_stats_init(struct team *team,
+ struct team_option_inst_info *info)
{
struct lb_priv *lb_priv = get_lb_priv(team);
unsigned char hash = info->array_index;
lb_priv->ex->stats.info[hash].opt_inst_info = info;
- return 0;
}
-static int lb_hash_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void lb_hash_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
unsigned char hash = ctx->info->array_index;
ctx->data.bin_val.ptr = &lb_priv->ex->stats.info[hash].stats;
ctx->data.bin_val.len = sizeof(struct lb_stats);
- return 0;
}
-static int lb_port_stats_init(struct team *team,
- struct team_option_inst_info *info)
+static void lb_port_stats_init(struct team *team,
+ struct team_option_inst_info *info)
{
struct team_port *port = info->port;
struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
lb_port_priv->stats_info.opt_inst_info = info;
- return 0;
}
-static int lb_port_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
+static void lb_port_stats_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
struct lb_port_priv *lb_port_priv = get_lb_port_priv(port);
ctx->data.bin_val.ptr = &lb_port_priv->stats_info.stats;
ctx->data.bin_val.len = sizeof(struct lb_stats);
- return 0;
}
static void __lb_stats_info_refresh_prepare(struct lb_stats_info *s_info)
@@ -531,13 +518,12 @@ static void lb_stats_refresh(struct work_struct *work)
mutex_unlock(&team->lock);
}
-static int lb_stats_refresh_interval_get(struct team *team,
- struct team_gsetter_ctx *ctx)
+static void lb_stats_refresh_interval_get(struct team *team,
+ struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
ctx->data.u32_val = lb_priv->ex->stats.refresh_interval;
- return 0;
}
static int lb_stats_refresh_interval_set(struct team *team,
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index 3ec63de97ae3..dd405d82c6ac 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -8,7 +8,6 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/if_team.h>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 100339bc8b04..89ab9efe522c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1523,11 +1523,13 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,
int err;
/* Under a page? Don't bother with paged skb. */
- if (prepad + len < PAGE_SIZE || !linear)
+ if (prepad + len < PAGE_SIZE)
linear = len;
+ if (len - linear > MAX_SKB_FRAGS * (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+ linear = len - MAX_SKB_FRAGS * (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER);
skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock,
- &err, 0);
+ &err, PAGE_ALLOC_COSTLY_ORDER);
if (!skb)
return ERR_PTR(err);
@@ -1838,6 +1840,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
*/
zerocopy = false;
} else {
+ if (!linear)
+ linear = min_t(size_t, good_linear, copylen);
+
skb = tun_alloc_skb(tfile, align, copylen, linear,
noblock);
}
@@ -3738,7 +3743,7 @@ err_linkops:
return ret;
}
-static void tun_cleanup(void)
+static void __exit tun_cleanup(void)
{
misc_deregister(&tun_miscdev);
rtnl_link_unregister(&tun_link_ops);
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 0738baa5b82e..332c853ca99b 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1314,16 +1314,24 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
byteen_end = byteen & BYTE_EN_END_MASK;
byen = byteen_start | (byteen_start << 4);
- ret = set_registers(tp, index, type | byen, 4, data);
- if (ret < 0)
- goto error1;
- index += 4;
- data += 4;
- size -= 4;
+ /* Split the first DWORD if the byte_en is not 0xff */
+ if (byen != BYTE_EN_DWORD) {
+ ret = set_registers(tp, index, type | byen, 4, data);
+ if (ret < 0)
+ goto error1;
- if (size) {
+ index += 4;
+ data += 4;
size -= 4;
+ }
+
+ if (size) {
+ byen = byteen_end | (byteen_end >> 4);
+
+ /* Split the last DWORD if the byte_en is not 0xff */
+ if (byen != BYTE_EN_DWORD)
+ size -= 4;
while (size) {
if (size > limit) {
@@ -1350,10 +1358,9 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
}
}
- byen = byteen_end | (byteen_end >> 4);
- ret = set_registers(tp, index, type | byen, 4, data);
- if (ret < 0)
- goto error1;
+ /* Set the last DWORD */
+ if (byen != BYTE_EN_DWORD)
+ ret = set_registers(tp, index, type | byen, 4, data);
}
error1:
@@ -3971,29 +3978,10 @@ static void rtl_reset_bmu(struct r8152 *tp)
/* Clear the bp to stop the firmware before loading a new one */
static void rtl_clear_bp(struct r8152 *tp, u16 type)
{
- switch (tp->version) {
- case RTL_VER_01:
- case RTL_VER_02:
- case RTL_VER_07:
- break;
- case RTL_VER_03:
- case RTL_VER_04:
- case RTL_VER_05:
- case RTL_VER_06:
- ocp_write_byte(tp, type, PLA_BP_EN, 0);
- break;
- case RTL_VER_14:
- ocp_write_word(tp, type, USB_BP2_EN, 0);
+ u16 bp[16] = {0};
+ u16 bp_num;
- ocp_write_word(tp, type, USB_BP_8, 0);
- ocp_write_word(tp, type, USB_BP_9, 0);
- ocp_write_word(tp, type, USB_BP_10, 0);
- ocp_write_word(tp, type, USB_BP_11, 0);
- ocp_write_word(tp, type, USB_BP_12, 0);
- ocp_write_word(tp, type, USB_BP_13, 0);
- ocp_write_word(tp, type, USB_BP_14, 0);
- ocp_write_word(tp, type, USB_BP_15, 0);
- break;
+ switch (tp->version) {
case RTL_VER_08:
case RTL_VER_09:
case RTL_VER_10:
@@ -4001,32 +3989,31 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type)
case RTL_VER_12:
case RTL_VER_13:
case RTL_VER_15:
- default:
if (type == MCU_TYPE_USB) {
ocp_write_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
-
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_10, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_11, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_12, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_13, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_14, 0);
- ocp_write_word(tp, MCU_TYPE_USB, USB_BP_15, 0);
- } else {
- ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
+ bp_num = 16;
+ break;
}
+ fallthrough;
+ case RTL_VER_03:
+ case RTL_VER_04:
+ case RTL_VER_05:
+ case RTL_VER_06:
+ ocp_write_byte(tp, type, PLA_BP_EN, 0);
+ fallthrough;
+ case RTL_VER_01:
+ case RTL_VER_02:
+ case RTL_VER_07:
+ bp_num = 8;
+ break;
+ case RTL_VER_14:
+ default:
+ ocp_write_word(tp, type, USB_BP2_EN, 0);
+ bp_num = 16;
break;
}
- ocp_write_word(tp, type, PLA_BP_0, 0);
- ocp_write_word(tp, type, PLA_BP_1, 0);
- ocp_write_word(tp, type, PLA_BP_2, 0);
- ocp_write_word(tp, type, PLA_BP_3, 0);
- ocp_write_word(tp, type, PLA_BP_4, 0);
- ocp_write_word(tp, type, PLA_BP_5, 0);
- ocp_write_word(tp, type, PLA_BP_6, 0);
- ocp_write_word(tp, type, PLA_BP_7, 0);
+ generic_ocp_write(tp, PLA_BP_0, BYTE_EN_DWORD, bp_num << 1, bp, type);
/* wait 3 ms to make sure the firmware is stopped */
usleep_range(3000, 6000);
@@ -5000,10 +4987,9 @@ static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy)
static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac)
{
- u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg;
+ u16 bp_en_addr, type, fw_ver_reg;
u32 length;
u8 *data;
- int i;
switch (__le32_to_cpu(mac->blk_hdr.type)) {
case RTL_FW_PLA:
@@ -5045,12 +5031,8 @@ static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac)
ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr),
__le16_to_cpu(mac->bp_ba_value));
- bp_index = __le16_to_cpu(mac->bp_start);
- bp_num = __le16_to_cpu(mac->bp_num);
- for (i = 0; i < bp_num; i++) {
- ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i]));
- bp_index += 2;
- }
+ generic_ocp_write(tp, __le16_to_cpu(mac->bp_start), BYTE_EN_DWORD,
+ __le16_to_cpu(mac->bp_num) << 1, mac->bp, type);
bp_en_addr = __le16_to_cpu(mac->bp_en_addr);
if (bp_en_addr)
@@ -9778,8 +9760,7 @@ static int rtl8152_probe(struct usb_interface *intf,
usb_set_intfdata(intf, tp);
- netif_napi_add_weight(netdev, &tp->napi, r8152_poll,
- tp->support_2500full ? 256 : 64);
+ netif_napi_add(netdev, &tp->napi, r8152_poll);
ret = register_netdev(netdev);
if (ret != 0) {
@@ -9851,6 +9832,7 @@ static const struct usb_device_id rtl8152_table[] = {
{ USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) },
{ USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) },
{ USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) },
+ { USB_DEVICE(VENDOR_ID_DLINK, 0xb301) },
{}
};
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 509e901da41d..d43e62ebc2fc 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -26,7 +26,7 @@
#include <linux/ptr_ring.h>
#include <linux/bpf_trace.h>
#include <linux/net_tstamp.h>
-#include <net/page_pool.h>
+#include <net/page_pool/helpers.h>
#define DRV_NAME "veth"
#define DRV_VERSION "1.0"
@@ -373,14 +373,13 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS)) {
if (!use_napi)
dev_lstats_add(dev, length);
+ else
+ __veth_xdp_flush(rq);
} else {
drop:
atomic64_inc(&priv->dropped);
}
- if (use_napi)
- __veth_xdp_flush(rq);
-
rcu_read_unlock();
return NETDEV_TX_OK;
@@ -1861,10 +1860,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
nla_peer = data[VETH_INFO_PEER];
ifmp = nla_data(nla_peer);
- err = rtnl_nla_parse_ifla(peer_tb,
- nla_data(nla_peer) + sizeof(struct ifinfomsg),
- nla_len(nla_peer) - sizeof(struct ifinfomsg),
- NULL);
+ err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
if (err < 0)
return err;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 8e9f4cfe941f..231ad91a919d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -22,6 +22,7 @@
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
+#include <net/netdev_rx_queue.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@@ -126,6 +127,11 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
#define VIRTNET_SQ_STATS_LEN ARRAY_SIZE(virtnet_sq_stats_desc)
#define VIRTNET_RQ_STATS_LEN ARRAY_SIZE(virtnet_rq_stats_desc)
+struct virtnet_interrupt_coalesce {
+ u32 max_packets;
+ u32 max_usecs;
+};
+
/* Internal representation of a send virtqueue */
struct send_queue {
/* Virtqueue associated with this send _queue */
@@ -139,6 +145,8 @@ struct send_queue {
struct virtnet_sq_stats stats;
+ struct virtnet_interrupt_coalesce intr_coal;
+
struct napi_struct napi;
/* Record whether sq is in reset state. */
@@ -156,6 +164,8 @@ struct receive_queue {
struct virtnet_rq_stats stats;
+ struct virtnet_interrupt_coalesce intr_coal;
+
/* Chain pages by the private ptr. */
struct page *pages;
@@ -207,6 +217,7 @@ struct control_buf {
struct virtio_net_ctrl_rss rss;
struct virtio_net_ctrl_coal_tx coal_tx;
struct virtio_net_ctrl_coal_rx coal_rx;
+ struct virtio_net_ctrl_coal_vq coal_vq;
};
struct virtnet_info {
@@ -281,10 +292,8 @@ struct virtnet_info {
u32 speed;
/* Interrupt coalescing settings */
- u32 tx_usecs;
- u32 rx_usecs;
- u32 tx_max_packets;
- u32 rx_max_packets;
+ struct virtnet_interrupt_coalesce intr_coal_tx;
+ struct virtnet_interrupt_coalesce intr_coal_rx;
unsigned long guest_offloads;
unsigned long guest_offloads_capable;
@@ -303,6 +312,14 @@ struct padded_vnet_hdr {
char padding[12];
};
+struct virtio_net_common_hdr {
+ union {
+ struct virtio_net_hdr hdr;
+ struct virtio_net_hdr_mrg_rxbuf mrg_hdr;
+ struct virtio_net_hdr_v1_hash hash_v1_hdr;
+ };
+};
+
static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
@@ -344,9 +361,10 @@ static int rxq2vq(int rxq)
return rxq * 2;
}
-static inline struct virtio_net_hdr_mrg_rxbuf *skb_vnet_hdr(struct sk_buff *skb)
+static inline struct virtio_net_common_hdr *
+skb_vnet_common_hdr(struct sk_buff *skb)
{
- return (struct virtio_net_hdr_mrg_rxbuf *)skb->cb;
+ return (struct virtio_net_common_hdr *)skb->cb;
}
/*
@@ -469,7 +487,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
unsigned int headroom)
{
struct sk_buff *skb;
- struct virtio_net_hdr_mrg_rxbuf *hdr;
+ struct virtio_net_common_hdr *hdr;
unsigned int copy, hdr_len, hdr_padded_len;
struct page *page_to_free = NULL;
int tailroom, shinfo_size;
@@ -554,7 +572,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
give_pages(rq, page);
ok:
- hdr = skb_vnet_hdr(skb);
+ hdr = skb_vnet_common_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
if (page_to_free)
put_page(page_to_free);
@@ -966,7 +984,7 @@ static struct sk_buff *receive_small_build_skb(struct virtnet_info *vi,
return NULL;
buf += header_offset;
- memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len);
+ memcpy(skb_vnet_common_hdr(skb), buf, vi->hdr_len);
return skb;
}
@@ -1577,7 +1595,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
{
struct net_device *dev = vi->dev;
struct sk_buff *skb;
- struct virtio_net_hdr_mrg_rxbuf *hdr;
+ struct virtio_net_common_hdr *hdr;
if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len);
@@ -1597,9 +1615,9 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
if (unlikely(!skb))
return;
- hdr = skb_vnet_hdr(skb);
+ hdr = skb_vnet_common_hdr(skb);
if (dev->features & NETIF_F_RXHASH && vi->has_rss_hash_report)
- virtio_skb_set_hash((const struct virtio_net_hdr_v1_hash *)hdr, skb);
+ virtio_skb_set_hash(&hdr->hash_v1_hdr, skb);
if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2105,7 +2123,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
if (can_push)
hdr = (struct virtio_net_hdr_mrg_rxbuf *)(skb->data - hdr_len);
else
- hdr = skb_vnet_hdr(skb);
+ hdr = &skb_vnet_common_hdr(skb)->mrg_hdr;
if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
virtio_is_little_endian(vi->vdev), false,
@@ -3056,8 +3074,8 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
return -EINVAL;
/* Save parameters */
- vi->tx_usecs = ec->tx_coalesce_usecs;
- vi->tx_max_packets = ec->tx_max_coalesced_frames;
+ vi->intr_coal_tx.max_usecs = ec->tx_coalesce_usecs;
+ vi->intr_coal_tx.max_packets = ec->tx_max_coalesced_frames;
vi->ctrl->coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
vi->ctrl->coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
@@ -3069,8 +3087,57 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
return -EINVAL;
/* Save parameters */
- vi->rx_usecs = ec->rx_coalesce_usecs;
- vi->rx_max_packets = ec->rx_max_coalesced_frames;
+ vi->intr_coal_rx.max_usecs = ec->rx_coalesce_usecs;
+ vi->intr_coal_rx.max_packets = ec->rx_max_coalesced_frames;
+
+ return 0;
+}
+
+static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
+ u16 vqn, u32 max_usecs, u32 max_packets)
+{
+ struct scatterlist sgs;
+
+ vi->ctrl->coal_vq.vqn = cpu_to_le16(vqn);
+ vi->ctrl->coal_vq.coal.max_usecs = cpu_to_le32(max_usecs);
+ vi->ctrl->coal_vq.coal.max_packets = cpu_to_le32(max_packets);
+ sg_init_one(&sgs, &vi->ctrl->coal_vq, sizeof(vi->ctrl->coal_vq));
+
+ if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
+ VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET,
+ &sgs))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int virtnet_send_notf_coal_vq_cmds(struct virtnet_info *vi,
+ struct ethtool_coalesce *ec,
+ u16 queue)
+{
+ int err;
+
+ if (ec->rx_coalesce_usecs || ec->rx_max_coalesced_frames) {
+ err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(queue),
+ ec->rx_coalesce_usecs,
+ ec->rx_max_coalesced_frames);
+ if (err)
+ return err;
+ /* Save parameters */
+ vi->rq[queue].intr_coal.max_usecs = ec->rx_coalesce_usecs;
+ vi->rq[queue].intr_coal.max_packets = ec->rx_max_coalesced_frames;
+ }
+
+ if (ec->tx_coalesce_usecs || ec->tx_max_coalesced_frames) {
+ err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(queue),
+ ec->tx_coalesce_usecs,
+ ec->tx_max_coalesced_frames);
+ if (err)
+ return err;
+ /* Save parameters */
+ vi->sq[queue].intr_coal.max_usecs = ec->tx_coalesce_usecs;
+ vi->sq[queue].intr_coal.max_packets = ec->tx_max_coalesced_frames;
+ }
return 0;
}
@@ -3090,22 +3157,42 @@ static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
return 0;
}
+static int virtnet_should_update_vq_weight(int dev_flags, int weight,
+ int vq_weight, bool *should_update)
+{
+ if (weight ^ vq_weight) {
+ if (dev_flags & IFF_UP)
+ return -EBUSY;
+ *should_update = true;
+ }
+
+ return 0;
+}
+
static int virtnet_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack)
{
struct virtnet_info *vi = netdev_priv(dev);
- int ret, i, napi_weight;
+ int ret, queue_number, napi_weight;
bool update_napi = false;
/* Can't change NAPI weight if the link is up */
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
- if (napi_weight ^ vi->sq[0].napi.weight) {
- if (dev->flags & IFF_UP)
- return -EBUSY;
- else
- update_napi = true;
+ for (queue_number = 0; queue_number < vi->max_queue_pairs; queue_number++) {
+ ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
+ vi->sq[queue_number].napi.weight,
+ &update_napi);
+ if (ret)
+ return ret;
+
+ if (update_napi) {
+ /* All queues that belong to [queue_number, vi->max_queue_pairs] will be
+ * updated for the sake of simplicity, which might not be necessary
+ */
+ break;
+ }
}
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
@@ -3117,8 +3204,8 @@ static int virtnet_set_coalesce(struct net_device *dev,
return ret;
if (update_napi) {
- for (i = 0; i < vi->max_queue_pairs; i++)
- vi->sq[i].napi.weight = napi_weight;
+ for (; queue_number < vi->max_queue_pairs; queue_number++)
+ vi->sq[queue_number].napi.weight = napi_weight;
}
return ret;
@@ -3132,10 +3219,67 @@ static int virtnet_get_coalesce(struct net_device *dev,
struct virtnet_info *vi = netdev_priv(dev);
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
- ec->rx_coalesce_usecs = vi->rx_usecs;
- ec->tx_coalesce_usecs = vi->tx_usecs;
- ec->tx_max_coalesced_frames = vi->tx_max_packets;
- ec->rx_max_coalesced_frames = vi->rx_max_packets;
+ ec->rx_coalesce_usecs = vi->intr_coal_rx.max_usecs;
+ ec->tx_coalesce_usecs = vi->intr_coal_tx.max_usecs;
+ ec->tx_max_coalesced_frames = vi->intr_coal_tx.max_packets;
+ ec->rx_max_coalesced_frames = vi->intr_coal_rx.max_packets;
+ } else {
+ ec->rx_max_coalesced_frames = 1;
+
+ if (vi->sq[0].napi.weight)
+ ec->tx_max_coalesced_frames = 1;
+ }
+
+ return 0;
+}
+
+static int virtnet_set_per_queue_coalesce(struct net_device *dev,
+ u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ int ret, napi_weight;
+ bool update_napi = false;
+
+ if (queue >= vi->max_queue_pairs)
+ return -EINVAL;
+
+ /* Can't change NAPI weight if the link is up */
+ napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
+ ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
+ vi->sq[queue].napi.weight,
+ &update_napi);
+ if (ret)
+ return ret;
+
+ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
+ ret = virtnet_send_notf_coal_vq_cmds(vi, ec, queue);
+ else
+ ret = virtnet_coal_params_supported(ec);
+
+ if (ret)
+ return ret;
+
+ if (update_napi)
+ vi->sq[queue].napi.weight = napi_weight;
+
+ return 0;
+}
+
+static int virtnet_get_per_queue_coalesce(struct net_device *dev,
+ u32 queue,
+ struct ethtool_coalesce *ec)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+
+ if (queue >= vi->max_queue_pairs)
+ return -EINVAL;
+
+ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
+ ec->rx_coalesce_usecs = vi->rq[queue].intr_coal.max_usecs;
+ ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
+ ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
+ ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
} else {
ec->rx_max_coalesced_frames = 1;
@@ -3276,6 +3420,8 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.set_link_ksettings = virtnet_set_link_ksettings,
.set_coalesce = virtnet_set_coalesce,
.get_coalesce = virtnet_get_coalesce,
+ .set_per_queue_coalesce = virtnet_set_per_queue_coalesce,
+ .get_per_queue_coalesce = virtnet_get_per_queue_coalesce,
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
.get_rxfh = virtnet_get_rxfh,
@@ -3952,6 +4098,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
"VIRTIO_NET_F_CTRL_VQ") ||
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_NOTF_COAL,
+ "VIRTIO_NET_F_CTRL_VQ") ||
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_VQ_NOTF_COAL,
"VIRTIO_NET_F_CTRL_VQ"))) {
return false;
}
@@ -4119,10 +4267,10 @@ static int virtnet_probe(struct virtio_device *vdev)
}
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
- vi->rx_usecs = 0;
- vi->tx_usecs = 0;
- vi->tx_max_packets = 0;
- vi->rx_max_packets = 0;
+ vi->intr_coal_rx.max_usecs = 0;
+ vi->intr_coal_tx.max_usecs = 0;
+ vi->intr_coal_tx.max_packets = 0;
+ vi->intr_coal_rx.max_packets = 0;
}
if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
@@ -4376,6 +4524,7 @@ static struct virtio_device_id id_table[] = {
VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, VIRTIO_NET_F_NOTF_COAL, \
+ VIRTIO_NET_F_VQ_NOTF_COAL, \
VIRTIO_NET_F_GUEST_HDRLEN
static unsigned int features[] = {
diff --git a/drivers/net/vmxnet3/Makefile b/drivers/net/vmxnet3/Makefile
index a666a88ac1ff..f82870c10205 100644
--- a/drivers/net/vmxnet3/Makefile
+++ b/drivers/net/vmxnet3/Makefile
@@ -32,4 +32,4 @@
obj-$(CONFIG_VMXNET3) += vmxnet3.o
-vmxnet3-objs := vmxnet3_drv.o vmxnet3_ethtool.o
+vmxnet3-objs := vmxnet3_drv.o vmxnet3_ethtool.o vmxnet3_xdp.o
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 7fa74b8b2100..0578864792b6 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -28,6 +28,7 @@
#include <net/ip6_checksum.h>
#include "vmxnet3_int.h"
+#include "vmxnet3_xdp.h"
char vmxnet3_driver_name[] = "vmxnet3";
#define VMXNET3_DRIVER_DESC "VMware vmxnet3 virtual NIC driver"
@@ -338,14 +339,16 @@ static void
vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
struct pci_dev *pdev)
{
- if (tbi->map_type == VMXNET3_MAP_SINGLE)
+ u32 map_type = tbi->map_type;
+
+ if (map_type & VMXNET3_MAP_SINGLE)
dma_unmap_single(&pdev->dev, tbi->dma_addr, tbi->len,
DMA_TO_DEVICE);
- else if (tbi->map_type == VMXNET3_MAP_PAGE)
+ else if (map_type & VMXNET3_MAP_PAGE)
dma_unmap_page(&pdev->dev, tbi->dma_addr, tbi->len,
DMA_TO_DEVICE);
else
- BUG_ON(tbi->map_type != VMXNET3_MAP_NONE);
+ BUG_ON(map_type & ~VMXNET3_MAP_XDP);
tbi->map_type = VMXNET3_MAP_NONE; /* to help debugging */
}
@@ -353,19 +356,20 @@ vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
static int
vmxnet3_unmap_pkt(u32 eop_idx, struct vmxnet3_tx_queue *tq,
- struct pci_dev *pdev, struct vmxnet3_adapter *adapter)
+ struct pci_dev *pdev, struct vmxnet3_adapter *adapter,
+ struct xdp_frame_bulk *bq)
{
- struct sk_buff *skb;
+ struct vmxnet3_tx_buf_info *tbi;
int entries = 0;
+ u32 map_type;
/* no out of order completion */
BUG_ON(tq->buf_info[eop_idx].sop_idx != tq->tx_ring.next2comp);
BUG_ON(VMXNET3_TXDESC_GET_EOP(&(tq->tx_ring.base[eop_idx].txd)) != 1);
- skb = tq->buf_info[eop_idx].skb;
- BUG_ON(skb == NULL);
- tq->buf_info[eop_idx].skb = NULL;
-
+ tbi = &tq->buf_info[eop_idx];
+ BUG_ON(!tbi->skb);
+ map_type = tbi->map_type;
VMXNET3_INC_RING_IDX_ONLY(eop_idx, tq->tx_ring.size);
while (tq->tx_ring.next2comp != eop_idx) {
@@ -381,7 +385,14 @@ vmxnet3_unmap_pkt(u32 eop_idx, struct vmxnet3_tx_queue *tq,
entries++;
}
- dev_kfree_skb_any(skb);
+ if (map_type & VMXNET3_MAP_XDP)
+ xdp_return_frame_bulk(tbi->xdpf, bq);
+ else
+ dev_kfree_skb_any(tbi->skb);
+
+ /* xdpf and skb are in an anonymous union. */
+ tbi->skb = NULL;
+
return entries;
}
@@ -390,8 +401,12 @@ static int
vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
- int completed = 0;
union Vmxnet3_GenericDesc *gdesc;
+ struct xdp_frame_bulk bq;
+ int completed = 0;
+
+ xdp_frame_bulk_init(&bq);
+ rcu_read_lock();
gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) {
@@ -402,11 +417,13 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX(
&gdesc->tcd), tq, adapter->pdev,
- adapter);
+ adapter, &bq);
vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring);
gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
}
+ xdp_flush_frame_bulk(&bq);
+ rcu_read_unlock();
if (completed) {
spin_lock(&tq->tx_lock);
@@ -426,26 +443,36 @@ static void
vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter)
{
+ struct xdp_frame_bulk bq;
+ u32 map_type;
int i;
+ xdp_frame_bulk_init(&bq);
+ rcu_read_lock();
+
while (tq->tx_ring.next2comp != tq->tx_ring.next2fill) {
struct vmxnet3_tx_buf_info *tbi;
tbi = tq->buf_info + tq->tx_ring.next2comp;
+ map_type = tbi->map_type;
vmxnet3_unmap_tx_buf(tbi, adapter->pdev);
if (tbi->skb) {
- dev_kfree_skb_any(tbi->skb);
+ if (map_type & VMXNET3_MAP_XDP)
+ xdp_return_frame_bulk(tbi->xdpf, &bq);
+ else
+ dev_kfree_skb_any(tbi->skb);
tbi->skb = NULL;
}
vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
}
- /* sanity check, verify all buffers are indeed unmapped and freed */
- for (i = 0; i < tq->tx_ring.size; i++) {
- BUG_ON(tq->buf_info[i].skb != NULL ||
- tq->buf_info[i].map_type != VMXNET3_MAP_NONE);
- }
+ xdp_flush_frame_bulk(&bq);
+ rcu_read_unlock();
+
+ /* sanity check, verify all buffers are indeed unmapped */
+ for (i = 0; i < tq->tx_ring.size; i++)
+ BUG_ON(tq->buf_info[i].map_type != VMXNET3_MAP_NONE);
tq->tx_ring.gen = VMXNET3_INIT_GEN;
tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0;
@@ -599,7 +626,17 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
gd = ring->base + ring->next2fill;
rbi->comp_state = VMXNET3_RXD_COMP_PENDING;
- if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
+ if (rbi->buf_type == VMXNET3_RX_BUF_XDP) {
+ void *data = vmxnet3_pp_get_buff(rq->page_pool,
+ &rbi->dma_addr,
+ GFP_KERNEL);
+ if (!data) {
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
+ rbi->page = virt_to_page(data);
+ val = VMXNET3_RXD_BTYPE_HEAD << VMXNET3_RXD_BTYPE_SHIFT;
+ } else if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
if (rbi->skb == NULL) {
rbi->skb = __netdev_alloc_skb_ip_align(adapter->netdev,
rbi->len,
@@ -1263,6 +1300,63 @@ drop_pkt:
return NETDEV_TX_OK;
}
+static int
+vmxnet3_create_pp(struct vmxnet3_adapter *adapter,
+ struct vmxnet3_rx_queue *rq, int size)
+{
+ bool xdp_prog = vmxnet3_xdp_enabled(adapter);
+ const struct page_pool_params pp_params = {
+ .order = 0,
+ .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+ .pool_size = size,
+ .nid = NUMA_NO_NODE,
+ .dev = &adapter->pdev->dev,
+ .offset = VMXNET3_XDP_RX_OFFSET,
+ .max_len = VMXNET3_XDP_MAX_FRSIZE,
+ .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
+ };
+ struct page_pool *pp;
+ int err;
+
+ pp = page_pool_create(&pp_params);
+ if (IS_ERR(pp))
+ return PTR_ERR(pp);
+
+ err = xdp_rxq_info_reg(&rq->xdp_rxq, adapter->netdev, rq->qid,
+ rq->napi.napi_id);
+ if (err < 0)
+ goto err_free_pp;
+
+ err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq, MEM_TYPE_PAGE_POOL, pp);
+ if (err)
+ goto err_unregister_rxq;
+
+ rq->page_pool = pp;
+
+ return 0;
+
+err_unregister_rxq:
+ xdp_rxq_info_unreg(&rq->xdp_rxq);
+err_free_pp:
+ page_pool_destroy(pp);
+
+ return err;
+}
+
+void *
+vmxnet3_pp_get_buff(struct page_pool *pp, dma_addr_t *dma_addr,
+ gfp_t gfp_mask)
+{
+ struct page *page;
+
+ page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN);
+ if (unlikely(!page))
+ return NULL;
+
+ *dma_addr = page_pool_get_dma_addr(page) + pp->p.offset;
+
+ return page_address(page);
+}
static netdev_tx_t
vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
@@ -1423,6 +1517,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct Vmxnet3_RxDesc rxCmdDesc;
struct Vmxnet3_RxCompDesc rxComp;
#endif
+ bool need_flush = false;
+
vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
&rxComp);
while (rcd->gen == rq->comp_ring.gen) {
@@ -1463,6 +1559,31 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
goto rcd_done;
}
+ if (rcd->sop && rcd->eop && vmxnet3_xdp_enabled(adapter)) {
+ struct sk_buff *skb_xdp_pass;
+ int act;
+
+ if (VMXNET3_RX_DATA_RING(adapter, rcd->rqID)) {
+ ctx->skb = NULL;
+ goto skip_xdp; /* Handle it later. */
+ }
+
+ if (rbi->buf_type != VMXNET3_RX_BUF_XDP)
+ goto rcd_done;
+
+ act = vmxnet3_process_xdp(adapter, rq, rcd, rbi, rxd,
+ &skb_xdp_pass);
+ if (act == XDP_PASS) {
+ ctx->skb = skb_xdp_pass;
+ goto sop_done;
+ }
+ ctx->skb = NULL;
+ need_flush |= act == XDP_REDIRECT;
+
+ goto rcd_done;
+ }
+skip_xdp:
+
if (rcd->sop) { /* first buf of the pkt */
bool rxDataRingUsed;
u16 len;
@@ -1471,7 +1592,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
(rcd->rqID != rq->qid &&
rcd->rqID != rq->dataRingQid));
- BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_SKB);
+ BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_SKB &&
+ rbi->buf_type != VMXNET3_RX_BUF_XDP);
BUG_ON(ctx->skb != NULL || rbi->skb == NULL);
if (unlikely(rcd->len == 0)) {
@@ -1489,6 +1611,25 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
rxDataRingUsed =
VMXNET3_RX_DATA_RING(adapter, rcd->rqID);
len = rxDataRingUsed ? rcd->len : rbi->len;
+
+ if (rxDataRingUsed && vmxnet3_xdp_enabled(adapter)) {
+ struct sk_buff *skb_xdp_pass;
+ size_t sz;
+ int act;
+
+ sz = rcd->rxdIdx * rq->data_ring.desc_size;
+ act = vmxnet3_process_xdp_small(adapter, rq,
+ &rq->data_ring.base[sz],
+ rcd->len,
+ &skb_xdp_pass);
+ if (act == XDP_PASS) {
+ ctx->skb = skb_xdp_pass;
+ goto sop_done;
+ }
+ need_flush |= act == XDP_REDIRECT;
+
+ goto rcd_done;
+ }
new_skb = netdev_alloc_skb_ip_align(adapter->netdev,
len);
if (new_skb == NULL) {
@@ -1621,6 +1762,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
}
+sop_done:
skb = ctx->skb;
if (rcd->eop) {
u32 mtu = adapter->netdev->mtu;
@@ -1757,6 +1899,8 @@ refill_buf:
vmxnet3_getRxComp(rcd,
&rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp);
}
+ if (need_flush)
+ xdp_do_flush();
return num_pkts;
}
@@ -1775,24 +1919,32 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
for (ring_idx = 0; ring_idx < 2; ring_idx++) {
for (i = 0; i < rq->rx_ring[ring_idx].size; i++) {
+ struct vmxnet3_rx_buf_info *rbi;
#ifdef __BIG_ENDIAN_BITFIELD
struct Vmxnet3_RxDesc rxDesc;
#endif
+
+ rbi = &rq->buf_info[ring_idx][i];
vmxnet3_getRxDesc(rxd,
&rq->rx_ring[ring_idx].base[i].rxd, &rxDesc);
if (rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
- rq->buf_info[ring_idx][i].skb) {
+ rbi->page && rbi->buf_type == VMXNET3_RX_BUF_XDP) {
+ page_pool_recycle_direct(rq->page_pool,
+ rbi->page);
+ rbi->page = NULL;
+ } else if (rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
+ rbi->skb) {
dma_unmap_single(&adapter->pdev->dev, rxd->addr,
rxd->len, DMA_FROM_DEVICE);
- dev_kfree_skb(rq->buf_info[ring_idx][i].skb);
- rq->buf_info[ring_idx][i].skb = NULL;
+ dev_kfree_skb(rbi->skb);
+ rbi->skb = NULL;
} else if (rxd->btype == VMXNET3_RXD_BTYPE_BODY &&
- rq->buf_info[ring_idx][i].page) {
+ rbi->page) {
dma_unmap_page(&adapter->pdev->dev, rxd->addr,
rxd->len, DMA_FROM_DEVICE);
- put_page(rq->buf_info[ring_idx][i].page);
- rq->buf_info[ring_idx][i].page = NULL;
+ put_page(rbi->page);
+ rbi->page = NULL;
}
}
@@ -1813,6 +1965,7 @@ vmxnet3_rq_cleanup_all(struct vmxnet3_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++)
vmxnet3_rq_cleanup(&adapter->rx_queue[i], adapter);
+ rcu_assign_pointer(adapter->xdp_bpf_prog, NULL);
}
@@ -1842,6 +1995,11 @@ static void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
}
}
+ if (xdp_rxq_info_is_reg(&rq->xdp_rxq))
+ xdp_rxq_info_unreg(&rq->xdp_rxq);
+ page_pool_destroy(rq->page_pool);
+ rq->page_pool = NULL;
+
if (rq->data_ring.base) {
dma_free_coherent(&adapter->pdev->dev,
rq->rx_ring[0].size * rq->data_ring.desc_size,
@@ -1885,14 +2043,16 @@ static int
vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter)
{
- int i;
+ int i, err;
/* initialize buf_info */
for (i = 0; i < rq->rx_ring[0].size; i++) {
- /* 1st buf for a pkt is skbuff */
+ /* 1st buf for a pkt is skbuff or xdp page */
if (i % adapter->rx_buf_per_pkt == 0) {
- rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_SKB;
+ rq->buf_info[0][i].buf_type = vmxnet3_xdp_enabled(adapter) ?
+ VMXNET3_RX_BUF_XDP :
+ VMXNET3_RX_BUF_SKB;
rq->buf_info[0][i].len = adapter->skb_buf_size;
} else { /* subsequent bufs for a pkt is frag */
rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_PAGE;
@@ -1913,8 +2073,18 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
rq->rx_ring[i].gen = VMXNET3_INIT_GEN;
rq->rx_ring[i].isOutOfOrder = 0;
}
+
+ err = vmxnet3_create_pp(adapter, rq,
+ rq->rx_ring[0].size + rq->rx_ring[1].size);
+ if (err)
+ return err;
+
if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
adapter) == 0) {
+ xdp_rxq_info_unreg(&rq->xdp_rxq);
+ page_pool_destroy(rq->page_pool);
+ rq->page_pool = NULL;
+
/* at least has 1 rx buffer for the 1st ring */
return -ENOMEM;
}
@@ -2016,7 +2186,7 @@ err:
}
-static int
+int
vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter)
{
int i, err = 0;
@@ -3053,7 +3223,7 @@ vmxnet3_free_pci_resources(struct vmxnet3_adapter *adapter)
}
-static void
+void
vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
{
size_t sz, i, ring0_size, ring1_size, comp_size;
@@ -3612,6 +3782,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = vmxnet3_netpoll,
#endif
+ .ndo_bpf = vmxnet3_xdp,
+ .ndo_xdp_xmit = vmxnet3_xdp_xmit,
};
int err;
u32 ver;
@@ -3864,6 +4036,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
vmxnet3_declare_features(adapter);
+ netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
+ NETDEV_XDP_ACT_NDO_XMIT;
adapter->rxdata_desc_size = VMXNET3_VERSION_GE_3(adapter) ?
VMXNET3_DEF_RXDATA_DESC_SIZE : 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 18cf7c723201..98c22d7d87a2 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -28,6 +28,7 @@
#include "vmxnet3_int.h"
#include <net/vxlan.h>
#include <net/geneve.h>
+#include "vmxnet3_xdp.h"
#define VXLAN_UDP_PORT 8472
@@ -76,6 +77,10 @@ vmxnet3_tq_driver_stats[] = {
copy_skb_header) },
{ " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
oversized_hdr) },
+ { " xdp xmit", offsetof(struct vmxnet3_tq_driver_stats,
+ xdp_xmit) },
+ { " xdp xmit err", offsetof(struct vmxnet3_tq_driver_stats,
+ xdp_xmit_err) },
};
/* per rq stats maintained by the device */
@@ -106,6 +111,16 @@ vmxnet3_rq_driver_stats[] = {
drop_fcs) },
{ " rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
rx_buf_alloc_failure) },
+ { " xdp packets", offsetof(struct vmxnet3_rq_driver_stats,
+ xdp_packets) },
+ { " xdp tx", offsetof(struct vmxnet3_rq_driver_stats,
+ xdp_tx) },
+ { " xdp redirects", offsetof(struct vmxnet3_rq_driver_stats,
+ xdp_redirects) },
+ { " xdp drops", offsetof(struct vmxnet3_rq_driver_stats,
+ xdp_drops) },
+ { " xdp aborted", offsetof(struct vmxnet3_rq_driver_stats,
+ xdp_aborted) },
};
/* global stats maintained by the driver */
@@ -249,10 +264,18 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
netdev_features_t vmxnet3_fix_features(struct net_device *netdev,
netdev_features_t features)
{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
/* If Rx checksum is disabled, then LRO should also be disabled */
if (!(features & NETIF_F_RXCSUM))
features &= ~NETIF_F_LRO;
+ /* If XDP is enabled, then LRO should not be enabled */
+ if (vmxnet3_xdp_enabled(adapter) && (features & NETIF_F_LRO)) {
+ netdev_err(netdev, "LRO is not supported with XDP");
+ features &= ~NETIF_F_LRO;
+ }
+
return features;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 3367db23aa13..915aaf18c409 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -56,6 +56,9 @@
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
#include <linux/log2.h>
+#include <linux/bpf.h>
+#include <net/page_pool/helpers.h>
+#include <net/xdp.h>
#include "vmxnet3_defs.h"
@@ -188,19 +191,20 @@ struct vmxnet3_tx_data_ring {
dma_addr_t basePA;
};
-enum vmxnet3_buf_map_type {
- VMXNET3_MAP_INVALID = 0,
- VMXNET3_MAP_NONE,
- VMXNET3_MAP_SINGLE,
- VMXNET3_MAP_PAGE,
-};
+#define VMXNET3_MAP_NONE 0
+#define VMXNET3_MAP_SINGLE BIT(0)
+#define VMXNET3_MAP_PAGE BIT(1)
+#define VMXNET3_MAP_XDP BIT(2)
struct vmxnet3_tx_buf_info {
u32 map_type;
u16 len;
u16 sop_idx;
dma_addr_t dma_addr;
- struct sk_buff *skb;
+ union {
+ struct sk_buff *skb;
+ struct xdp_frame *xdpf;
+ };
};
struct vmxnet3_tq_driver_stats {
@@ -217,6 +221,9 @@ struct vmxnet3_tq_driver_stats {
u64 linearized; /* # of pkts linearized */
u64 copy_skb_header; /* # of times we have to copy skb header */
u64 oversized_hdr;
+
+ u64 xdp_xmit;
+ u64 xdp_xmit_err;
};
struct vmxnet3_tx_ctx {
@@ -253,12 +260,13 @@ struct vmxnet3_tx_queue {
* stopped */
int qid;
u16 txdata_desc_size;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+} ____cacheline_aligned;
enum vmxnet3_rx_buf_type {
VMXNET3_RX_BUF_NONE = 0,
VMXNET3_RX_BUF_SKB = 1,
- VMXNET3_RX_BUF_PAGE = 2
+ VMXNET3_RX_BUF_PAGE = 2,
+ VMXNET3_RX_BUF_XDP = 3,
};
#define VMXNET3_RXD_COMP_PENDING 0
@@ -285,6 +293,12 @@ struct vmxnet3_rq_driver_stats {
u64 drop_err;
u64 drop_fcs;
u64 rx_buf_alloc_failure;
+
+ u64 xdp_packets; /* Total packets processed by XDP. */
+ u64 xdp_tx;
+ u64 xdp_redirects;
+ u64 xdp_drops;
+ u64 xdp_aborted;
};
struct vmxnet3_rx_data_ring {
@@ -307,7 +321,9 @@ struct vmxnet3_rx_queue {
struct vmxnet3_rx_buf_info *buf_info[2];
struct Vmxnet3_RxQueueCtrl *shared;
struct vmxnet3_rq_driver_stats stats;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+ struct page_pool *page_pool;
+ struct xdp_rxq_info xdp_rxq;
+} ____cacheline_aligned;
#define VMXNET3_DEVICE_MAX_TX_QUEUES 32
#define VMXNET3_DEVICE_MAX_RX_QUEUES 32 /* Keep this value as a power of 2 */
@@ -415,6 +431,7 @@ struct vmxnet3_adapter {
u16 tx_prod_offset;
u16 rx_prod_offset;
u16 rx_prod2_offset;
+ struct bpf_prog __rcu *xdp_bpf_prog;
};
#define VMXNET3_WRITE_BAR0_REG(adapter, reg, val) \
@@ -490,6 +507,12 @@ vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter);
void
vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
+int
+vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter);
+
netdev_features_t
vmxnet3_fix_features(struct net_device *netdev, netdev_features_t features);
diff --git a/drivers/net/vmxnet3/vmxnet3_xdp.c b/drivers/net/vmxnet3/vmxnet3_xdp.c
new file mode 100644
index 000000000000..80ddaff759d4
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_xdp.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ * Copyright (C) 2008-2023, VMware, Inc. All Rights Reserved.
+ * Maintained by: pv-drivers@vmware.com
+ *
+ */
+
+#include "vmxnet3_int.h"
+#include "vmxnet3_xdp.h"
+
+static void
+vmxnet3_xdp_exchange_program(struct vmxnet3_adapter *adapter,
+ struct bpf_prog *prog)
+{
+ rcu_assign_pointer(adapter->xdp_bpf_prog, prog);
+}
+
+static inline struct vmxnet3_tx_queue *
+vmxnet3_xdp_get_tq(struct vmxnet3_adapter *adapter)
+{
+ struct vmxnet3_tx_queue *tq;
+ int tq_number;
+ int cpu;
+
+ tq_number = adapter->num_tx_queues;
+ cpu = smp_processor_id();
+ if (likely(cpu < tq_number))
+ tq = &adapter->tx_queue[cpu];
+ else
+ tq = &adapter->tx_queue[reciprocal_scale(cpu, tq_number)];
+
+ return tq;
+}
+
+static int
+vmxnet3_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf,
+ struct netlink_ext_ack *extack)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct bpf_prog *new_bpf_prog = bpf->prog;
+ struct bpf_prog *old_bpf_prog;
+ bool need_update;
+ bool running;
+ int err;
+
+ if (new_bpf_prog && netdev->mtu > VMXNET3_XDP_MAX_MTU) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "MTU %u too large for XDP",
+ netdev->mtu);
+ return -EOPNOTSUPP;
+ }
+
+ if (adapter->netdev->features & NETIF_F_LRO) {
+ NL_SET_ERR_MSG_MOD(extack, "LRO is not supported with XDP");
+ adapter->netdev->features &= ~NETIF_F_LRO;
+ }
+
+ old_bpf_prog = rcu_dereference(adapter->xdp_bpf_prog);
+ if (!new_bpf_prog && !old_bpf_prog)
+ return 0;
+
+ running = netif_running(netdev);
+ need_update = !!old_bpf_prog != !!new_bpf_prog;
+
+ if (running && need_update)
+ vmxnet3_quiesce_dev(adapter);
+
+ vmxnet3_xdp_exchange_program(adapter, new_bpf_prog);
+ if (old_bpf_prog)
+ bpf_prog_put(old_bpf_prog);
+
+ if (!running || !need_update)
+ return 0;
+
+ if (new_bpf_prog)
+ xdp_features_set_redirect_target(netdev, false);
+ else
+ xdp_features_clear_redirect_target(netdev);
+
+ vmxnet3_reset_dev(adapter);
+ vmxnet3_rq_destroy_all(adapter);
+ vmxnet3_adjust_rx_ring_size(adapter);
+ err = vmxnet3_rq_create_all(adapter);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "failed to re-create rx queues for XDP.");
+ return -EOPNOTSUPP;
+ }
+ err = vmxnet3_activate_dev(adapter);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "failed to activate device for XDP.");
+ return -EOPNOTSUPP;
+ }
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+
+ return 0;
+}
+
+/* This is the main xdp call used by kernel to set/unset eBPF program. */
+int
+vmxnet3_xdp(struct net_device *netdev, struct netdev_bpf *bpf)
+{
+ switch (bpf->command) {
+ case XDP_SETUP_PROG:
+ return vmxnet3_xdp_set(netdev, bpf, bpf->extack);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+vmxnet3_xdp_xmit_frame(struct vmxnet3_adapter *adapter,
+ struct xdp_frame *xdpf,
+ struct vmxnet3_tx_queue *tq, bool dma_map)
+{
+ struct vmxnet3_tx_buf_info *tbi = NULL;
+ union Vmxnet3_GenericDesc *gdesc;
+ struct vmxnet3_tx_ctx ctx;
+ int tx_num_deferred;
+ struct page *page;
+ u32 buf_size;
+ u32 dw2;
+
+ dw2 = (tq->tx_ring.gen ^ 0x1) << VMXNET3_TXD_GEN_SHIFT;
+ dw2 |= xdpf->len;
+ ctx.sop_txd = tq->tx_ring.base + tq->tx_ring.next2fill;
+ gdesc = ctx.sop_txd;
+
+ buf_size = xdpf->len;
+ tbi = tq->buf_info + tq->tx_ring.next2fill;
+
+ if (vmxnet3_cmd_ring_desc_avail(&tq->tx_ring) == 0) {
+ tq->stats.tx_ring_full++;
+ return -ENOSPC;
+ }
+
+ tbi->map_type = VMXNET3_MAP_XDP;
+ if (dma_map) { /* ndo_xdp_xmit */
+ tbi->dma_addr = dma_map_single(&adapter->pdev->dev,
+ xdpf->data, buf_size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+ return -EFAULT;
+ tbi->map_type |= VMXNET3_MAP_SINGLE;
+ } else { /* XDP buffer from page pool */
+ page = virt_to_page(xdpf->data);
+ tbi->dma_addr = page_pool_get_dma_addr(page) +
+ VMXNET3_XDP_HEADROOM;
+ dma_sync_single_for_device(&adapter->pdev->dev,
+ tbi->dma_addr, buf_size,
+ DMA_TO_DEVICE);
+ }
+ tbi->xdpf = xdpf;
+ tbi->len = buf_size;
+
+ gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+ WARN_ON_ONCE(gdesc->txd.gen == tq->tx_ring.gen);
+
+ gdesc->txd.addr = cpu_to_le64(tbi->dma_addr);
+ gdesc->dword[2] = cpu_to_le32(dw2);
+
+ /* Setup the EOP desc */
+ gdesc->dword[3] = cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
+
+ gdesc->txd.om = 0;
+ gdesc->txd.msscof = 0;
+ gdesc->txd.hlen = 0;
+ gdesc->txd.ti = 0;
+
+ tx_num_deferred = le32_to_cpu(tq->shared->txNumDeferred);
+ le32_add_cpu(&tq->shared->txNumDeferred, 1);
+ tx_num_deferred++;
+
+ vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
+
+ /* set the last buf_info for the pkt */
+ tbi->sop_idx = ctx.sop_txd - tq->tx_ring.base;
+
+ dma_wmb();
+ gdesc->dword[2] = cpu_to_le32(le32_to_cpu(gdesc->dword[2]) ^
+ VMXNET3_TXD_GEN);
+
+ /* No need to handle the case when tx_num_deferred doesn't reach
+ * threshold. Backend driver at hypervisor side will poll and reset
+ * tq->shared->txNumDeferred to 0.
+ */
+ if (tx_num_deferred >= le32_to_cpu(tq->shared->txThreshold)) {
+ tq->shared->txNumDeferred = 0;
+ VMXNET3_WRITE_BAR0_REG(adapter,
+ VMXNET3_REG_TXPROD + tq->qid * 8,
+ tq->tx_ring.next2fill);
+ }
+
+ return 0;
+}
+
+static int
+vmxnet3_xdp_xmit_back(struct vmxnet3_adapter *adapter,
+ struct xdp_frame *xdpf)
+{
+ struct vmxnet3_tx_queue *tq;
+ struct netdev_queue *nq;
+ int err;
+
+ tq = vmxnet3_xdp_get_tq(adapter);
+ if (tq->stopped)
+ return -ENETDOWN;
+
+ nq = netdev_get_tx_queue(adapter->netdev, tq->qid);
+
+ __netif_tx_lock(nq, smp_processor_id());
+ err = vmxnet3_xdp_xmit_frame(adapter, xdpf, tq, false);
+ __netif_tx_unlock(nq);
+
+ return err;
+}
+
+/* ndo_xdp_xmit */
+int
+vmxnet3_xdp_xmit(struct net_device *dev,
+ int n, struct xdp_frame **frames, u32 flags)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(dev);
+ struct vmxnet3_tx_queue *tq;
+ int i;
+
+ if (unlikely(test_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state)))
+ return -ENETDOWN;
+ if (unlikely(test_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state)))
+ return -EINVAL;
+
+ tq = vmxnet3_xdp_get_tq(adapter);
+ if (tq->stopped)
+ return -ENETDOWN;
+
+ for (i = 0; i < n; i++) {
+ if (vmxnet3_xdp_xmit_frame(adapter, frames[i], tq, true)) {
+ tq->stats.xdp_xmit_err++;
+ break;
+ }
+ }
+ tq->stats.xdp_xmit += i;
+
+ return i;
+}
+
+static int
+vmxnet3_run_xdp(struct vmxnet3_rx_queue *rq, struct xdp_buff *xdp,
+ struct bpf_prog *prog)
+{
+ struct xdp_frame *xdpf;
+ struct page *page;
+ int err;
+ u32 act;
+
+ rq->stats.xdp_packets++;
+ act = bpf_prog_run_xdp(prog, xdp);
+ page = virt_to_page(xdp->data_hard_start);
+
+ switch (act) {
+ case XDP_PASS:
+ return act;
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(rq->adapter->netdev, xdp, prog);
+ if (!err) {
+ rq->stats.xdp_redirects++;
+ } else {
+ rq->stats.xdp_drops++;
+ page_pool_recycle_direct(rq->page_pool, page);
+ }
+ return act;
+ case XDP_TX:
+ xdpf = xdp_convert_buff_to_frame(xdp);
+ if (unlikely(!xdpf ||
+ vmxnet3_xdp_xmit_back(rq->adapter, xdpf))) {
+ rq->stats.xdp_drops++;
+ page_pool_recycle_direct(rq->page_pool, page);
+ } else {
+ rq->stats.xdp_tx++;
+ }
+ return act;
+ default:
+ bpf_warn_invalid_xdp_action(rq->adapter->netdev, prog, act);
+ fallthrough;
+ case XDP_ABORTED:
+ trace_xdp_exception(rq->adapter->netdev, prog, act);
+ rq->stats.xdp_aborted++;
+ break;
+ case XDP_DROP:
+ rq->stats.xdp_drops++;
+ break;
+ }
+
+ page_pool_recycle_direct(rq->page_pool, page);
+
+ return act;
+}
+
+static struct sk_buff *
+vmxnet3_build_skb(struct vmxnet3_rx_queue *rq, struct page *page,
+ const struct xdp_buff *xdp)
+{
+ struct sk_buff *skb;
+
+ skb = build_skb(page_address(page), PAGE_SIZE);
+ if (unlikely(!skb)) {
+ page_pool_recycle_direct(rq->page_pool, page);
+ rq->stats.rx_buf_alloc_failure++;
+ return NULL;
+ }
+
+ /* bpf prog might change len and data position. */
+ skb_reserve(skb, xdp->data - xdp->data_hard_start);
+ skb_put(skb, xdp->data_end - xdp->data);
+ skb_mark_for_recycle(skb);
+
+ return skb;
+}
+
+/* Handle packets from DataRing. */
+int
+vmxnet3_process_xdp_small(struct vmxnet3_adapter *adapter,
+ struct vmxnet3_rx_queue *rq,
+ void *data, int len,
+ struct sk_buff **skb_xdp_pass)
+{
+ struct bpf_prog *xdp_prog;
+ struct xdp_buff xdp;
+ struct page *page;
+ int act;
+
+ page = page_pool_alloc_pages(rq->page_pool, GFP_ATOMIC);
+ if (unlikely(!page)) {
+ rq->stats.rx_buf_alloc_failure++;
+ return XDP_DROP;
+ }
+
+ xdp_init_buff(&xdp, PAGE_SIZE, &rq->xdp_rxq);
+ xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset,
+ len, false);
+ xdp_buff_clear_frags_flag(&xdp);
+
+ /* Must copy the data because it's at dataring. */
+ memcpy(xdp.data, data, len);
+
+ xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog);
+ if (!xdp_prog) {
+ act = XDP_PASS;
+ goto out_skb;
+ }
+ act = vmxnet3_run_xdp(rq, &xdp, xdp_prog);
+ if (act != XDP_PASS)
+ return act;
+
+out_skb:
+ *skb_xdp_pass = vmxnet3_build_skb(rq, page, &xdp);
+ if (!*skb_xdp_pass)
+ return XDP_DROP;
+
+ /* No need to refill. */
+ return likely(*skb_xdp_pass) ? act : XDP_DROP;
+}
+
+int
+vmxnet3_process_xdp(struct vmxnet3_adapter *adapter,
+ struct vmxnet3_rx_queue *rq,
+ struct Vmxnet3_RxCompDesc *rcd,
+ struct vmxnet3_rx_buf_info *rbi,
+ struct Vmxnet3_RxDesc *rxd,
+ struct sk_buff **skb_xdp_pass)
+{
+ struct bpf_prog *xdp_prog;
+ dma_addr_t new_dma_addr;
+ struct xdp_buff xdp;
+ struct page *page;
+ void *new_data;
+ int act;
+
+ page = rbi->page;
+ dma_sync_single_for_cpu(&adapter->pdev->dev,
+ page_pool_get_dma_addr(page) +
+ rq->page_pool->p.offset, rcd->len,
+ page_pool_get_dma_dir(rq->page_pool));
+
+ xdp_init_buff(&xdp, rbi->len, &rq->xdp_rxq);
+ xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset,
+ rcd->len, false);
+ xdp_buff_clear_frags_flag(&xdp);
+
+ xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog);
+ if (!xdp_prog) {
+ act = XDP_PASS;
+ goto out_skb;
+ }
+ act = vmxnet3_run_xdp(rq, &xdp, xdp_prog);
+
+ if (act == XDP_PASS) {
+out_skb:
+ *skb_xdp_pass = vmxnet3_build_skb(rq, page, &xdp);
+ if (!*skb_xdp_pass)
+ act = XDP_DROP;
+ }
+
+ new_data = vmxnet3_pp_get_buff(rq->page_pool, &new_dma_addr,
+ GFP_ATOMIC);
+ if (!new_data) {
+ rq->stats.rx_buf_alloc_failure++;
+ return XDP_DROP;
+ }
+ rbi->page = virt_to_page(new_data);
+ rbi->dma_addr = new_dma_addr;
+ rxd->addr = cpu_to_le64(rbi->dma_addr);
+ rxd->len = rbi->len;
+
+ return act;
+}
diff --git a/drivers/net/vmxnet3/vmxnet3_xdp.h b/drivers/net/vmxnet3/vmxnet3_xdp.h
new file mode 100644
index 000000000000..f9d843e060a3
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_xdp.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ * Copyright (C) 2008-2023, VMware, Inc. All Rights Reserved.
+ * Maintained by: pv-drivers@vmware.com
+ *
+ */
+
+#ifndef _VMXNET3_XDP_H
+#define _VMXNET3_XDP_H
+
+#include <linux/filter.h>
+#include <linux/bpf_trace.h>
+#include <linux/netlink.h>
+
+#include "vmxnet3_int.h"
+
+#define VMXNET3_XDP_HEADROOM (XDP_PACKET_HEADROOM + NET_IP_ALIGN)
+#define VMXNET3_XDP_RX_TAILROOM SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
+#define VMXNET3_XDP_RX_OFFSET VMXNET3_XDP_HEADROOM
+#define VMXNET3_XDP_MAX_FRSIZE (PAGE_SIZE - VMXNET3_XDP_HEADROOM - \
+ VMXNET3_XDP_RX_TAILROOM)
+#define VMXNET3_XDP_MAX_MTU (VMXNET3_XDP_MAX_FRSIZE - ETH_HLEN - \
+ 2 * VLAN_HLEN - ETH_FCS_LEN)
+
+int vmxnet3_xdp(struct net_device *netdev, struct netdev_bpf *bpf);
+int vmxnet3_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
+ u32 flags);
+int vmxnet3_process_xdp(struct vmxnet3_adapter *adapter,
+ struct vmxnet3_rx_queue *rq,
+ struct Vmxnet3_RxCompDesc *rcd,
+ struct vmxnet3_rx_buf_info *rbi,
+ struct Vmxnet3_RxDesc *rxd,
+ struct sk_buff **skb_xdp_pass);
+int vmxnet3_process_xdp_small(struct vmxnet3_adapter *adapter,
+ struct vmxnet3_rx_queue *rq,
+ void *data, int len,
+ struct sk_buff **skb_xdp_pass);
+void *vmxnet3_pp_get_buff(struct page_pool *pp, dma_addr_t *dma_addr,
+ gfp_t gfp_mask);
+
+static inline bool vmxnet3_xdp_enabled(struct vmxnet3_adapter *adapter)
+{
+ return !!rcu_access_pointer(adapter->xdp_bpf_prog);
+}
+
+#endif
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 6043e63b42f9..a3408e4e1491 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -638,9 +638,7 @@ static void vrf_finish_direct(struct sk_buff *skb)
eth_zero_addr(eth->h_dest);
eth->h_proto = skb->protocol;
- rcu_read_lock_bh();
dev_queue_xmit_nit(skb, vrf_dev);
- rcu_read_unlock_bh();
skb_pull(skb, ETH_HLEN);
}
@@ -1979,7 +1977,8 @@ static int vrf_netns_init_sysctl(struct net *net, struct netns_vrf *nn_vrf)
/* init the extra1 parameter with the reference to current netns */
table[0].extra1 = net;
- nn_vrf->ctl_hdr = register_net_sysctl(net, "net/vrf", table);
+ nn_vrf->ctl_hdr = register_net_sysctl_sz(net, "net/vrf", table,
+ ARRAY_SIZE(vrf_table));
if (!nn_vrf->ctl_hdr) {
kfree(table);
return -ENOMEM;
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index c9a9373733c0..e463f59e95c2 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2328,14 +2328,11 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
struct vxlan_dev *dst_vxlan, __be32 vni,
bool snoop)
{
- struct pcpu_sw_netstats *tx_stats, *rx_stats;
union vxlan_addr loopback;
union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
struct net_device *dev;
int len = skb->len;
- tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
- rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats);
skb->pkt_type = PACKET_HOST;
skb->encapsulation = 0;
skb->dev = dst_vxlan->dev;
@@ -2361,17 +2358,11 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
if ((dst_vxlan->cfg.flags & VXLAN_F_LEARN) && snoop)
vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
- u64_stats_update_begin(&tx_stats->syncp);
- u64_stats_inc(&tx_stats->tx_packets);
- u64_stats_add(&tx_stats->tx_bytes, len);
- u64_stats_update_end(&tx_stats->syncp);
+ dev_sw_netstats_tx_add(src_vxlan->dev, 1, len);
vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len);
if (__netif_rx(skb) == NET_RX_SUCCESS) {
- u64_stats_update_begin(&rx_stats->syncp);
- u64_stats_inc(&rx_stats->rx_packets);
- u64_stats_add(&rx_stats->rx_bytes, len);
- u64_stats_update_end(&rx_stats->syncp);
+ dev_sw_netstats_rx_add(dst_vxlan->dev, len);
vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX,
len);
} else {
@@ -2720,6 +2711,45 @@ drop:
dev_kfree_skb(skb);
}
+static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev,
+ u32 nhid, __be32 vni)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_rdst nh_rdst;
+ struct nexthop *nh;
+ bool do_xmit;
+ u32 hash;
+
+ memset(&nh_rdst, 0, sizeof(struct vxlan_rdst));
+ hash = skb_get_hash(skb);
+
+ rcu_read_lock();
+ nh = nexthop_find_by_id(dev_net(dev), nhid);
+ if (unlikely(!nh || !nexthop_is_fdb(nh) || !nexthop_is_multipath(nh))) {
+ rcu_read_unlock();
+ goto drop;
+ }
+ do_xmit = vxlan_fdb_nh_path_select(nh, hash, &nh_rdst);
+ rcu_read_unlock();
+
+ if (vxlan->cfg.saddr.sa.sa_family != nh_rdst.remote_ip.sa.sa_family)
+ goto drop;
+
+ if (likely(do_xmit))
+ vxlan_xmit_one(skb, dev, vni, &nh_rdst, false);
+ else
+ goto drop;
+
+ return NETDEV_TX_OK;
+
+drop:
+ dev->stats.tx_dropped++;
+ vxlan_vnifilter_count(netdev_priv(dev), vni, NULL,
+ VXLAN_VNI_STATS_TX_DROPS, 0);
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
/* Transmit local packets over Vxlan
*
* Outer IP header inherits ECN and DF from inner header.
@@ -2735,6 +2765,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
struct vxlan_fdb *f;
struct ethhdr *eth;
__be32 vni = 0;
+ u32 nhid = 0;
info = skb_tunnel_info(skb);
@@ -2744,6 +2775,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
if (info && info->mode & IP_TUNNEL_INFO_BRIDGE &&
info->mode & IP_TUNNEL_INFO_TX) {
vni = tunnel_id_to_key32(info->key.tun_id);
+ nhid = info->key.nhid;
} else {
if (info && info->mode & IP_TUNNEL_INFO_TX)
vxlan_xmit_one(skb, dev, vni, NULL, false);
@@ -2771,6 +2803,9 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
}
+ if (nhid)
+ return vxlan_xmit_nhid(skb, dev, nhid, vni);
+
if (vxlan->cfg.flags & VXLAN_F_MDB) {
struct vxlan_mdb_entry *mdb_entry;
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index c3ff30ab782e..9c59d0bf8c3d 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -696,7 +696,7 @@ static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan,
{
struct vxlan_vni_node *vninode;
- vninode = kzalloc(sizeof(*vninode), GFP_ATOMIC);
+ vninode = kzalloc(sizeof(*vninode), GFP_KERNEL);
if (!vninode)
return NULL;
vninode->stats = netdev_alloc_pcpu_stats(struct vxlan_vni_stats_pcpu);
diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c
index 6d1bd9f52d02..dc09b75a3248 100644
--- a/drivers/net/wireguard/netlink.c
+++ b/drivers/net/wireguard/netlink.c
@@ -200,7 +200,7 @@ static int wg_get_device_start(struct netlink_callback *cb)
{
struct wg_device *wg;
- wg = lookup_interface(genl_dumpit_info(cb)->attrs, cb->skb);
+ wg = lookup_interface(genl_info_dump(cb)->attrs, cb->skb);
if (IS_ERR(wg))
return PTR_ERR(wg);
DUMP_CTX(cb)->wg = wg;
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index 4a006fb4d424..a378bc48b1d2 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -5,7 +5,7 @@
*/
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include "core.h"
@@ -733,7 +733,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
int ret;
struct ath10k_bus_params bus_params = {};
- hw_rev = (enum ath10k_hw_rev)of_device_get_match_data(&pdev->dev);
+ hw_rev = (uintptr_t)of_device_get_match_data(&pdev->dev);
if (!hw_rev) {
dev_err(&pdev->dev, "OF data missing\n");
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index e0c9f45e7476..7b24297146e7 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -69,7 +69,7 @@ struct htt_ver_req {
* The HTT tx descriptor is defined in two manners: by a struct with
* bitfields, and by a series of [dword offset, bit mask, bit shift]
* definitions.
- * The target should use the struct def, for simplicitly and clarity,
+ * The target should use the struct def, for simplicity and clarity,
* but the host shall use the bit-mast + bit-shift defs, to be endian-
* neutral. Specifically, the host shall use the get/set macros built
* around the mask + shift defs.
@@ -2086,7 +2086,7 @@ static inline bool ath10k_htt_rx_proc_rx_frag_ind(struct ath10k_htt *htt,
* for correctly accessing rx descriptor data.
*/
-/* base struct used for abstracting the rx descritor representation */
+/* base struct used for abstracting the rx descriptor representation */
struct htt_rx_desc {
union {
/* This field is filled on the host using the msdu buffer
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a7f44f6335fb..7535524bb85e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1636,7 +1636,7 @@ static int ath10k_pci_dump_memory_generic(struct ath10k *ar,
buf,
current_region->len);
- /* No individiual memory sections defined so we can
+ /* No individual memory sections defined so we can
* copy the entire memory region.
*/
ret = ath10k_pci_diag_read_mem(ar,
@@ -3816,7 +3816,7 @@ static void __exit ath10k_pci_exit(void)
module_exit(ath10k_pci_exit);
MODULE_AUTHOR("Qualcomm Atheros");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros PCIe/AHB 802.11ac WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");
/* QCA988x 2.0 firmware files */
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 79e09c7a82b3..56fbcfb80bf8 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -2389,7 +2389,7 @@ static int ath10k_sdio_dump_memory_generic(struct ath10k *ar,
buf,
current_region->len);
- /* No individiual memory sections defined so we can
+ /* No individual memory sections defined so we can
* copy the entire memory region.
*/
if (fast_dump)
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index b0067af685b1..3c482baacec1 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -1126,5 +1126,5 @@ static struct usb_driver ath10k_usb_driver = {
module_usb_driver(ath10k_usb_driver);
MODULE_AUTHOR("Atheros Communications, Inc.");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN USB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros USB 802.11ac WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 6d04a66fe5e0..b112e8826093 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3854,9 +3854,9 @@ enum wmi_pdev_param {
* retransmitting frames.
*/
WMI_PDEV_PARAM_DYNAMIC_BW,
- /* Non aggregrate/ 11g sw retry threshold.0-disable */
+ /* Non aggregate/ 11g sw retry threshold.0-disable */
WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
- /* aggregrate sw retry threshold. 0-disable*/
+ /* aggregate sw retry threshold. 0-disable*/
WMI_PDEV_PARAM_AGG_SW_RETRY_TH,
/* Station kickout threshold (non of consecutive failures).0-disable */
WMI_PDEV_PARAM_STA_KICKOUT_TH,
@@ -3953,9 +3953,9 @@ enum wmi_10x_pdev_param {
WMI_10X_PDEV_PARAM_PROTECTION_MODE,
/* Dynamic bandwidth 0: disable 1: enable */
WMI_10X_PDEV_PARAM_DYNAMIC_BW,
- /* Non aggregrate/ 11g sw retry threshold.0-disable */
+ /* Non aggregate/ 11g sw retry threshold.0-disable */
WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
- /* aggregrate sw retry threshold. 0-disable*/
+ /* aggregate sw retry threshold. 0-disable*/
WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH,
/* Station kickout threshold (non of consecutive failures).0-disable */
WMI_10X_PDEV_PARAM_STA_KICKOUT_TH,
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 139da578831a..1215ebdf173a 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -14,6 +14,7 @@
#include "ahb.h"
#include "debug.h"
#include "hif.h"
+#include "qmi.h"
#include <linux/remoteproc.h>
#include "pcic.h"
#include <linux/soc/qcom/smem.h>
@@ -418,32 +419,6 @@ static void ath11k_ahb_power_down(struct ath11k_base *ab)
rproc_shutdown(ab_ahb->tgt_rproc);
}
-static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab)
-{
- int timeout;
-
- if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done ||
- ab->hw_params.cold_boot_calib == 0 ||
- ab->hw_params.cbcal_restart_fw == 0)
- return 0;
-
- ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n");
- timeout = wait_event_timeout(ab->qmi.cold_boot_waitq,
- (ab->qmi.cal_done == 1),
- ATH11K_COLD_BOOT_FW_RESET_DELAY);
- if (timeout <= 0) {
- ath11k_cold_boot_cal = 0;
- ath11k_warn(ab, "Coldboot Calibration failed timed out\n");
- }
-
- /* reset the firmware */
- ath11k_ahb_power_down(ab);
- ath11k_ahb_power_up(ab);
-
- ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\n");
- return 0;
-}
-
static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
{
struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
@@ -1121,7 +1096,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
return -EINVAL;
}
- hw_rev = (enum ath11k_hw_rev)of_id->data;
+ hw_rev = (uintptr_t)of_id->data;
switch (hw_rev) {
case ATH11K_HW_IPQ8074:
@@ -1226,7 +1201,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
goto err_ce_free;
}
- ath11k_ahb_fwreset_from_cold_boot(ab);
+ ath11k_qmi_fwreset_from_cold_boot(ab);
return 0;
@@ -1331,17 +1306,7 @@ static struct platform_driver ath11k_ahb_driver = {
.shutdown = ath11k_ahb_shutdown,
};
-static int ath11k_ahb_init(void)
-{
- return platform_driver_register(&ath11k_ahb_driver);
-}
-module_init(ath11k_ahb_init);
-
-static void ath11k_ahb_exit(void)
-{
- platform_driver_unregister(&ath11k_ahb_driver);
-}
-module_exit(ath11k_ahb_exit);
+module_platform_driver(ath11k_ahb_driver);
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h
index 1fc6360e7f01..c0f6a0ba86df 100644
--- a/drivers/net/wireless/ath/ath11k/ce.h
+++ b/drivers/net/wireless/ath/ath11k/ce.h
@@ -203,9 +203,6 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab);
void ath11k_ce_free_pipes(struct ath11k_base *ab);
int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id);
void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id);
-int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
- u8 *ul_pipe, u8 *dl_pipe);
-int ath11k_ce_attr_attach(struct ath11k_base *ab);
void ath11k_ce_get_shadow_config(struct ath11k_base *ab,
u32 **shadow_cfg, u32 *shadow_cfg_len);
void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab);
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index bebfd342e28b..fc7c4564a715 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -86,7 +86,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = false,
.idle_ps = false,
.supports_sta_ps = false,
- .cold_boot_calib = true,
+ .coldboot_cal_mm = true,
+ .coldboot_cal_ftm = true,
.cbcal_restart_fw = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -167,7 +168,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = false,
.idle_ps = false,
.supports_sta_ps = false,
- .cold_boot_calib = true,
+ .coldboot_cal_mm = true,
+ .coldboot_cal_ftm = true,
.cbcal_restart_fw = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -248,7 +250,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.supports_sta_ps = true,
- .cold_boot_calib = false,
+ .coldboot_cal_mm = false,
+ .coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -332,8 +335,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = false,
.idle_ps = false,
.supports_sta_ps = false,
- .cold_boot_calib = false,
- .cbcal_restart_fw = false,
+ .coldboot_cal_mm = false,
+ .coldboot_cal_ftm = true,
+ .cbcal_restart_fw = true,
.fw_mem_mode = 2,
.num_vdevs = 8,
.num_peers = 128,
@@ -413,7 +417,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.supports_sta_ps = true,
- .cold_boot_calib = false,
+ .coldboot_cal_mm = false,
+ .coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -495,7 +500,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.supports_sta_ps = true,
- .cold_boot_calib = false,
+ .coldboot_cal_mm = false,
+ .coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -578,7 +584,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.supports_sta_ps = true,
- .cold_boot_calib = true,
+ .coldboot_cal_mm = true,
+ .coldboot_cal_ftm = true,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
@@ -667,7 +674,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_suspend = false,
.hal_params = &ath11k_hw_hal_params_ipq8074,
.single_pdev_only = false,
- .cold_boot_calib = true,
+ .coldboot_cal_mm = true,
+ .coldboot_cal_ftm = true,
.cbcal_restart_fw = true,
.fix_l1ss = true,
.supports_dynamic_smps_6ghz = false,
@@ -749,6 +757,18 @@ void ath11k_fw_stats_free(struct ath11k_fw_stats *stats)
ath11k_fw_stats_bcn_free(&stats->bcn);
}
+bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab)
+{
+ if (!ath11k_cold_boot_cal)
+ return false;
+
+ if (ath11k_ftm_mode)
+ return ab->hw_params.coldboot_cal_ftm;
+
+ else
+ return ab->hw_params.coldboot_cal_mm;
+}
+
int ath11k_core_suspend(struct ath11k_base *ab)
{
int ret;
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 9d15b4390b9c..b04447762483 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1186,6 +1186,7 @@ void ath11k_core_halt(struct ath11k *ar);
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab);
+bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index d04f78ab6b37..15815af453b2 100644
--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -635,7 +635,7 @@ enum htt_ppdu_stats_tag_type {
* b'24 - status_swap: 1 is to swap status TLV
* b'25 - pkt_swap: 1 is to swap packet TLV
* b'26:31 - rsvd1: reserved for future use
- * dword1 - b'0:16 - ring_buffer_size: size of bufferes referenced by rx ring,
+ * dword1 - b'0:16 - ring_buffer_size: size of buffers referenced by rx ring,
* in byte units.
* Valid only for HW_TO_SW_RING and SW_TO_HW_RING
* - b'16:31 - rsvd2: Reserved for future use
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 5c76664ba0dd..62bc98852f0f 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -2408,7 +2408,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
rx_status->freq = center_freq;
} else if (channel_num >= 1 && channel_num <= 14) {
rx_status->band = NL80211_BAND_2GHZ;
- } else if (channel_num >= 36 && channel_num <= 173) {
+ } else if (channel_num >= 36 && channel_num <= 177) {
rx_status->band = NL80211_BAND_5GHZ;
} else {
spin_lock_bh(&ar->data_lock);
@@ -3423,7 +3423,7 @@ static int ath11k_dp_rx_h_defrag_reo_reinject(struct ath11k *ar, struct dp_rx_ti
ath11k_hal_rx_buf_addr_info_set(msdu0, paddr, cookie,
ab->hw_params.hal_params->rx_buf_rbm);
- /* Fill mpdu details into reo entrace ring */
+ /* Fill mpdu details into reo entrance ring */
srng = &ab->hal.srng_list[ab->dp.reo_reinject_ring.ring_id];
spin_lock_bh(&srng->lock);
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index a34833de7c67..0dda76f7a4b5 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -238,7 +238,7 @@ tcl_ring_sel:
spin_unlock_bh(&tcl_ring->lock);
ret = -ENOMEM;
- /* Checking for available tcl descritors in another ring in
+ /* Checking for available tcl descriptors in another ring in
* case of failure due to full tcl ring now, is better than
* checking this ring earlier for each pkt tx.
* Restart ring selection if some rings are not checked yet.
@@ -344,7 +344,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab,
dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
if (!skb_cb->vif) {
- dev_kfree_skb_any(msdu);
+ ieee80211_free_txskb(ar->hw, msdu);
return;
}
@@ -369,7 +369,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab,
"dp_tx: failed to find the peer with peer_id %d\n",
ts->peer_id);
spin_unlock_bh(&ab->base_lock);
- dev_kfree_skb_any(msdu);
+ ieee80211_free_txskb(ar->hw, msdu);
return;
}
spin_unlock_bh(&ab->base_lock);
@@ -566,12 +566,12 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) {
- dev_kfree_skb_any(msdu);
+ ieee80211_free_txskb(ar->hw, msdu);
return;
}
if (unlikely(!skb_cb->vif)) {
- dev_kfree_skb_any(msdu);
+ ieee80211_free_txskb(ar->hw, msdu);
return;
}
@@ -624,7 +624,7 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
"dp_tx: failed to find the peer with peer_id %d\n",
ts->peer_id);
spin_unlock_bh(&ab->base_lock);
- dev_kfree_skb_any(msdu);
+ ieee80211_free_txskb(ar->hw, msdu);
return;
}
arsta = (struct ath11k_sta *)peer->sta->drv_priv;
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index f5533630a7f9..d51a99669dd6 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -187,7 +187,8 @@ struct ath11k_hw_params {
bool supports_shadow_regs;
bool idle_ps;
bool supports_sta_ps;
- bool cold_boot_calib;
+ bool coldboot_cal_mm;
+ bool coldboot_cal_ftm;
bool cbcal_restart_fw;
int fw_mem_mode;
u32 num_vdevs;
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 8c77ade49437..c071bf5841af 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -566,7 +566,7 @@ static void ath11k_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct ath11k_vif_iter *arvif_iter = data;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
if (arvif->vdev_id == arvif_iter->vdev_id)
arvif_iter->arvif = arvif;
@@ -1464,7 +1464,7 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif)
u32 params = 0;
u8 i = 0;
- tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv;
+ tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
beacons = ieee80211_beacon_get_template_ema_list(tx_arvif->ar->hw,
tx_arvif->vif, 0);
@@ -1520,8 +1520,8 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif)
struct sk_buff *bcn;
int ret;
- if (arvif->vif->mbssid_tx_vif) {
- tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv;
+ if (vif->mbssid_tx_vif) {
+ tx_arvif = ath11k_vif_to_arvif(vif->mbssid_tx_vif);
if (tx_arvif != arvif) {
ar = tx_arvif->ar;
ab = ar->ab;
@@ -1562,7 +1562,7 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
* non-transmitting interfaces, and results in a crash if sent.
*/
if (vif->mbssid_tx_vif &&
- arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up)
+ arvif != ath11k_vif_to_arvif(vif->mbssid_tx_vif) && arvif->is_up)
return 0;
if (vif->bss_conf.ema_ap && vif->mbssid_tx_vif)
@@ -1626,7 +1626,7 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif,
ether_addr_copy(arvif->bssid, info->bssid);
if (arvif->vif->mbssid_tx_vif)
- tx_arvif = (struct ath11k_vif *)arvif->vif->mbssid_tx_vif->drv_priv;
+ tx_arvif = ath11k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid,
@@ -1649,7 +1649,7 @@ static void ath11k_mac_handle_beacon_iter(void *data, u8 *mac,
{
struct sk_buff *skb = data;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
if (vif->type != NL80211_IFTYPE_STATION)
return;
@@ -1672,7 +1672,7 @@ static void ath11k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
u32 *vdev_id = data;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k *ar = arvif->ar;
struct ieee80211_hw *hw = ar->hw;
@@ -1718,7 +1718,7 @@ static void ath11k_peer_assoc_h_basic(struct ath11k *ar,
struct ieee80211_sta *sta,
struct peer_assoc_params *arg)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
u32 aid;
lockdep_assert_held(&ar->conf_mutex);
@@ -1746,7 +1746,7 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar,
struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_chan_def def;
struct cfg80211_bss *bss;
- struct ath11k_vif *arvif = (struct ath11k_vif *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
const u8 *rsnie = NULL;
const u8 *wpaie = NULL;
@@ -1804,7 +1804,7 @@ static void ath11k_peer_assoc_h_rates(struct ath11k *ar,
struct ieee80211_sta *sta,
struct peer_assoc_params *arg)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
struct cfg80211_chan_def def;
const struct ieee80211_supported_band *sband;
@@ -1867,7 +1867,7 @@ static void ath11k_peer_assoc_h_ht(struct ath11k *ar,
struct peer_assoc_params *arg)
{
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
const u8 *ht_mcs_mask;
@@ -2064,7 +2064,7 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
struct peer_assoc_params *arg)
{
const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
u16 *vht_mcs_mask;
@@ -2261,7 +2261,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
struct ieee80211_sta *sta,
struct peer_assoc_params *arg)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
enum nl80211_band band;
@@ -2584,7 +2584,7 @@ static void ath11k_peer_assoc_h_qos(struct ath11k *ar,
struct ieee80211_sta *sta,
struct peer_assoc_params *arg)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
switch (arvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
@@ -2747,7 +2747,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
struct ieee80211_sta *sta,
struct peer_assoc_params *arg)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
const u8 *ht_mcs_mask;
@@ -2933,7 +2933,7 @@ static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta_he_cap *he_cap)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ieee80211_he_cap_elem he_cap_elem = {0};
struct ieee80211_sta_he_cap *cap_band = NULL;
struct cfg80211_chan_def def;
@@ -2995,7 +2995,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf)
{
struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct peer_assoc_params peer_arg;
struct ieee80211_sta *ap_sta;
struct ath11k_peer *peer;
@@ -3111,7 +3111,7 @@ static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
int ret;
lockdep_assert_held(&ar->conf_mutex);
@@ -3160,7 +3160,7 @@ static void ath11k_recalculate_mgmt_rate(struct ath11k *ar,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *def)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
const struct ieee80211_supported_band *sband;
u8 basic_rate_idx;
int hw_rate_code;
@@ -4632,7 +4632,7 @@ static int ath11k_station_disassoc(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
@@ -5160,7 +5160,7 @@ static int ath11k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
int ret = 0;
s16 txpwr;
@@ -5210,7 +5210,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
{
struct ath11k *ar = hw->priv;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k_peer *peer;
u32 bw, smps;
@@ -5337,7 +5337,7 @@ static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
const struct ieee80211_tx_queue_params *params)
{
struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct wmi_wmm_params_arg *p = NULL;
int ret;
@@ -6455,7 +6455,7 @@ static int ath11k_mac_setup_vdev_params_mbssid(struct ath11k_vif *arvif,
return 0;
}
- tx_arvif = (void *)tx_vif->drv_priv;
+ tx_arvif = ath11k_vif_to_arvif(tx_vif);
if (arvif->vif->bss_conf.nontransmitted) {
if (ar->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy)
@@ -7408,7 +7408,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
/* TODO: Update ar->rx_channel */
for (i = 0; i < n_vifs; i++) {
- arvif = (void *)vifs[i].vif->drv_priv;
+ arvif = ath11k_vif_to_arvif(vifs[i].vif);
if (WARN_ON(!arvif->is_started))
continue;
@@ -7450,7 +7450,7 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
mbssid_tx_vif = arvif->vif->mbssid_tx_vif;
if (mbssid_tx_vif)
- tx_arvif = (struct ath11k_vif *)mbssid_tx_vif->drv_priv;
+ tx_arvif = ath11k_vif_to_arvif(mbssid_tx_vif);
ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
arvif->bssid,
@@ -7546,7 +7546,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
int ret;
if (WARN_ON(arvif->is_started))
@@ -7596,7 +7596,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
int ret;
struct peer_create_params param;
@@ -7686,7 +7686,7 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k_peer *peer;
int ret;
@@ -8255,7 +8255,7 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b
const struct cfg80211_bitrate_mask *mask)
{
bool he_fixed_rate = false, vht_fixed_rate = false;
- struct ath11k_peer *peer, *tmp;
+ struct ath11k_peer *peer;
const u16 *vht_mcs_mask, *he_mcs_mask;
struct ieee80211_link_sta *deflink;
u8 vht_nss, he_nss;
@@ -8278,7 +8278,7 @@ ath11k_mac_validate_vht_he_fixed_rate_settings(struct ath11k *ar, enum nl80211_b
rcu_read_lock();
spin_lock_bh(&ar->ab->base_lock);
- list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) {
+ list_for_each_entry(peer, &ar->ab->peers, list) {
if (peer->sta) {
deflink = &peer->sta->deflink;
@@ -8307,7 +8307,7 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
{
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
struct ath11k_pdev_cap *cap;
struct ath11k *ar = arvif->ar;
@@ -8904,7 +8904,7 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
enum ieee80211_roc_type type)
{
struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = (void *)vif->drv_priv;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct scan_req_params arg;
int ret;
u32 scan_time_msec;
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 79e2cbe82638..9573bd959cac 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -15,6 +15,7 @@
#include "mhi.h"
#include "debug.h"
#include "pcic.h"
+#include "qmi.h"
#define ATH11K_PCI_BAR_NUM 0
#define ATH11K_PCI_DMA_MASK 32
@@ -897,6 +898,7 @@ unsupported_wcn6855_soc:
ath11k_err(ab, "failed to init core: %d\n", ret);
goto err_irq_affinity_cleanup;
}
+ ath11k_qmi_fwreset_from_cold_boot(ab);
return 0;
err_irq_affinity_cleanup:
@@ -1034,7 +1036,7 @@ static void ath11k_pci_exit(void)
module_exit(ath11k_pci_exit);
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11ax WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");
/* firmware files */
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index d4eaf7d2ba84..41fad03a3025 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -9,11 +9,11 @@
#include "qmi.h"
#include "core.h"
#include "debug.h"
+#include "hif.h"
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/ioport.h>
#include <linux/firmware.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02
@@ -2079,7 +2079,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
return -EINVAL;
}
- if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) {
+ if (ath11k_core_coldboot_cal_support(ab)) {
if (hremote_node) {
ab->qmi.target_mem[idx].paddr =
res.start + host_ddr_sz;
@@ -2839,6 +2839,33 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab,
return 0;
}
+int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab)
+{
+ int timeout;
+
+ if (!ath11k_core_coldboot_cal_support(ab) ||
+ ab->hw_params.cbcal_restart_fw == 0)
+ return 0;
+
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "wait for cold boot done\n");
+
+ timeout = wait_event_timeout(ab->qmi.cold_boot_waitq,
+ (ab->qmi.cal_done == 1),
+ ATH11K_COLD_BOOT_FW_RESET_DELAY);
+
+ if (timeout <= 0) {
+ ath11k_warn(ab, "Coldboot Calibration timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ /* reset the firmware */
+ ath11k_hif_power_down(ab);
+ ath11k_hif_power_up(ab);
+ ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n");
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_qmi_fwreset_from_cold_boot);
+
static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab)
{
int timeout;
@@ -3209,8 +3236,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
break;
}
- if (ath11k_cold_boot_cal && ab->qmi.cal_done == 0 &&
- ab->hw_params.cold_boot_calib) {
+ if (ab->qmi.cal_done == 0 &&
+ ath11k_core_coldboot_cal_support(ab)) {
ath11k_qmi_process_coldboot_calibration(ab);
} else {
clear_bit(ATH11K_FLAG_CRASH_FLUSH,
diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
index 0909d53cefeb..d477e2be814b 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -37,7 +37,7 @@
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
#define ATH11K_FIRMWARE_MODE_OFF 4
-#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ)
+#define ATH11K_COLD_BOOT_FW_RESET_DELAY (60 * HZ)
#define ATH11K_QMI_DEVICE_BAR_SIZE 0x200000
@@ -514,10 +514,9 @@ struct qmi_wlanfw_wlan_ini_resp_msg_v01 {
int ath11k_qmi_firmware_start(struct ath11k_base *ab,
u32 mode);
void ath11k_qmi_firmware_stop(struct ath11k_base *ab);
-void ath11k_qmi_event_work(struct work_struct *work);
-void ath11k_qmi_msg_recv_work(struct work_struct *work);
void ath11k_qmi_deinit_service(struct ath11k_base *ab);
int ath11k_qmi_init_service(struct ath11k_base *ab);
void ath11k_qmi_free_resource(struct ath11k_base *ab);
+int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab);
#endif
diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c
index 8fc5cddb28bd..43bb23265d34 100644
--- a/drivers/net/wireless/ath/ath11k/testmode.c
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
@@ -350,7 +350,7 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[],
if (ar->ab->fw_mode != ATH11K_FIRMWARE_MODE_FTM &&
(tag == WMI_TAG_VDEV_SET_PARAM_CMD || tag == WMI_TAG_UNIT_TEST_CMD)) {
if (vif) {
- arvif = (struct ath11k_vif *)vif->drv_priv;
+ arvif = ath11k_vif_to_arvif(vif);
*ptr = arvif->vdev_id;
} else {
ret = -EINVAL;
diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h
index 17cf16235e0b..79af3b6159f1 100644
--- a/drivers/net/wireless/ath/ath12k/ce.h
+++ b/drivers/net/wireless/ath/ath12k/ce.h
@@ -176,9 +176,6 @@ int ath12k_ce_alloc_pipes(struct ath12k_base *ab);
void ath12k_ce_free_pipes(struct ath12k_base *ab);
int ath12k_ce_get_attr_flags(struct ath12k_base *ab, int ce_id);
void ath12k_ce_poll_send_completed(struct ath12k_base *ab, u8 pipe_id);
-int ath12k_ce_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,
- u8 *ul_pipe, u8 *dl_pipe);
-int ath12k_ce_attr_attach(struct ath12k_base *ab);
void ath12k_ce_get_shadow_config(struct ath12k_base *ab,
u32 **shadow_cfg, u32 *shadow_cfg_len);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 2f93296db792..d873b573dac6 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -238,6 +238,7 @@ struct ath12k_vif {
u32 key_cipher;
u8 tx_encap_type;
u8 vdev_stats_id;
+ u32 punct_bitmap;
};
struct ath12k_vif_iter {
@@ -580,6 +581,14 @@ struct ath12k_band_cap {
u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE];
struct ath12k_wmi_ppe_threshold_arg he_ppet;
u16 he_6ghz_capa;
+ u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];
+ u32 eht_cap_phy_info[WMI_MAX_EHTCAP_PHY_SIZE];
+ u32 eht_mcs_20_only;
+ u32 eht_mcs_80;
+ u32 eht_mcs_160;
+ u32 eht_mcs_320;
+ struct ath12k_wmi_ppe_threshold_arg eht_ppet;
+ u32 eht_cap_info_internal;
};
struct ath12k_pdev_cap {
@@ -614,6 +623,12 @@ struct ath12k_pdev {
struct mlo_timestamp timestamp;
};
+struct ath12k_fw_pdev {
+ u32 pdev_id;
+ u32 phy_id;
+ u32 supported_bands;
+};
+
struct ath12k_board_data {
const struct firmware *fw;
const void *data;
@@ -669,7 +684,26 @@ struct ath12k_base {
struct mutex core_lock;
/* Protects data like peers */
spinlock_t base_lock;
+
+ /* Single pdev device (struct ath12k_hw_params::single_pdev_only):
+ *
+ * Firmware maintains data for all bands but advertises a single
+ * phy to the host which is stored as a single element in this
+ * array.
+ *
+ * Other devices:
+ *
+ * This array will contain as many elements as the number of
+ * radios.
+ */
struct ath12k_pdev pdevs[MAX_RADIOS];
+
+ /* struct ath12k_hw_params::single_pdev_only devices use this to
+ * store phy specific data
+ */
+ struct ath12k_fw_pdev fw_pdev[MAX_RADIOS];
+ u8 fw_pdev_count;
+
struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS];
struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
unsigned long long free_vdev_map;
@@ -754,7 +788,6 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
int ath12k_core_fetch_bdf(struct ath12k_base *ath12k,
struct ath12k_board_data *bd);
void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd);
-int ath12k_core_check_dt(struct ath12k_base *ath12k);
void ath12k_core_halt(struct ath12k *ar);
int ath12k_core_resume(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index ae1645d0f42a..f933896f2a68 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1129,6 +1129,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
struct ath12k_dp *dp = &ab->dp;
struct sk_buff *skb;
int i;
+ u32 pool_id, tx_spt_page;
if (!dp->spt_info)
return;
@@ -1148,6 +1149,14 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
dev_kfree_skb_any(skb);
}
+ for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
+ if (!dp->spt_info->rxbaddr[i])
+ continue;
+
+ kfree(dp->spt_info->rxbaddr[i]);
+ dp->spt_info->rxbaddr[i] = NULL;
+ }
+
spin_unlock_bh(&dp->rx_desc_lock);
/* TX Descriptor cleanup */
@@ -1170,6 +1179,21 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
spin_unlock_bh(&dp->tx_desc_lock[i]);
}
+ for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) {
+ spin_lock_bh(&dp->tx_desc_lock[pool_id]);
+
+ 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])
+ continue;
+
+ kfree(dp->spt_info->txbaddr[tx_spt_page]);
+ dp->spt_info->txbaddr[tx_spt_page] = NULL;
+ }
+
+ spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
+ }
+
/* unmap SPT pages */
for (i = 0; i < dp->num_spt_pages; i++) {
if (!dp->spt_info[i].vaddr)
@@ -1343,6 +1367,8 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
return -ENOMEM;
}
+ dp->spt_info->rxbaddr[i] = &rx_descs[0];
+
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j);
rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC;
@@ -1368,8 +1394,10 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
return -ENOMEM;
}
+ tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
+ dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0];
+
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
- tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page;
tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j);
tx_descs[j].pool_id = pool_id;
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 7c5dafce5a68..61f765432516 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -289,6 +289,8 @@ 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 {
@@ -712,7 +714,7 @@ enum htt_stats_internal_ppdu_frametype {
* b'24 - status_swap: 1 is to swap status TLV
* b'25 - pkt_swap: 1 is to swap packet TLV
* b'26:31 - rsvd1: reserved for future use
- * dword1 - b'0:16 - ring_buffer_size: size of bufferes referenced by rx ring,
+ * dword1 - b'0:16 - ring_buffer_size: size of buffers referenced by rx ring,
* in byte units.
* Valid only for HW_TO_SW_RING and SW_TO_HW_RING
* - b'16:31 - rsvd2: Reserved for future use
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index ffd9a2018610..e6e64d437c47 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -2539,7 +2539,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab,
struct ath12k_skb_rxcb *rxcb;
struct sk_buff *msdu;
struct ath12k *ar;
- u8 mac_id;
+ u8 mac_id, pdev_id;
int ret;
if (skb_queue_empty(msdu_list))
@@ -2550,8 +2550,9 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab,
while ((msdu = __skb_dequeue(msdu_list))) {
rxcb = ATH12K_SKB_RXCB(msdu);
mac_id = rxcb->mac_id;
- ar = ab->pdevs[mac_id].ar;
- if (!rcu_dereference(ab->pdevs_active[mac_id])) {
+ pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
+ ar = ab->pdevs[pdev_id].ar;
+ if (!rcu_dereference(ab->pdevs_active[pdev_id])) {
dev_kfree_skb_any(msdu);
continue;
}
@@ -3026,7 +3027,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar,
desc_info->cookie,
HAL_RX_BUF_RBM_SW3_BM);
- /* Fill mpdu details into reo entrace ring */
+ /* Fill mpdu details into reo entrance ring */
srng = &ab->hal.srng_list[dp->reo_reinject_ring.ring_id];
spin_lock_bh(&srng->lock);
@@ -3385,6 +3386,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
dma_addr_t paddr;
bool is_frag;
bool drop = false;
+ int pdev_id;
tot_n_bufs_reaped = 0;
quota = budget;
@@ -3440,7 +3442,8 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
mac_id = le32_get_bits(reo_desc->info0,
HAL_REO_DEST_RING_INFO0_SRC_LINK_ID);
- ar = ab->pdevs[mac_id].ar;
+ pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
+ ar = ab->pdevs[pdev_id].ar;
if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, drop,
msdu_cookies[i]))
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index d3c7c76d6b75..8874c815d7fa 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -301,7 +301,7 @@ tcl_ring_sel:
spin_unlock_bh(&tcl_ring->lock);
ret = -ENOMEM;
- /* Checking for available tcl descritors in another ring in
+ /* Checking for available tcl descriptors in another ring in
* case of failure due to full tcl ring now, is better than
* checking this ring earlier for each pkt tx.
* Restart ring selection if some rings are not checked yet.
@@ -347,6 +347,7 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab,
{
struct ath12k *ar;
struct ath12k_skb_cb *skb_cb;
+ u8 pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
skb_cb = ATH12K_SKB_CB(msdu);
@@ -357,7 +358,7 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab,
dev_kfree_skb_any(msdu);
- ar = ab->pdevs[mac_id].ar;
+ ar = ab->pdevs[pdev_id].ar;
if (atomic_dec_and_test(&ar->dp.num_tx_pending))
wake_up(&ar->dp.tx_empty_waitq);
}
@@ -536,7 +537,7 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id)
struct hal_tx_status ts = { 0 };
struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];
struct hal_wbm_release_ring *desc;
- u8 mac_id;
+ u8 mac_id, pdev_id;
u64 desc_va;
spin_lock_bh(&status_ring->lock);
@@ -605,7 +606,8 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id)
continue;
}
- ar = ab->pdevs[mac_id].ar;
+ pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id);
+ ar = ab->pdevs[pdev_id].ar;
if (atomic_dec_and_test(&ar->dp.num_tx_pending))
wake_up(&ar->dp.tx_empty_waitq);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 1bb9802ef569..88346e66bb75 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -182,32 +182,35 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = {
[NL80211_BAND_2GHZ] = {
[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
- [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20_2G,
- [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20_2G,
- [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40_2G,
- [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80_2G,
+ [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20_2G,
+ [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20_2G,
+ [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40_2G,
+ [NL80211_CHAN_WIDTH_80] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN,
+ [NL80211_CHAN_WIDTH_320] = MODE_UNKNOWN,
},
[NL80211_BAND_5GHZ] = {
[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
- [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
- [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
- [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
- [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
- [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
- [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
+ [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20,
+ [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20,
+ [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40,
+ [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80,
+ [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160,
+ [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80,
+ [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320,
},
[NL80211_BAND_6GHZ] = {
[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
- [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
- [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
- [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
- [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
- [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
- [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
+ [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20,
+ [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20,
+ [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40,
+ [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80,
+ [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160,
+ [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80,
+ [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320,
},
};
@@ -292,6 +295,24 @@ static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode)
return "11ax-he40-2g";
case MODE_11AX_HE80_2G:
return "11ax-he80-2g";
+ case MODE_11BE_EHT20:
+ return "11be-eht20";
+ case MODE_11BE_EHT40:
+ return "11be-eht40";
+ case MODE_11BE_EHT80:
+ return "11be-eht80";
+ case MODE_11BE_EHT80_80:
+ return "11be-eht80+80";
+ case MODE_11BE_EHT160:
+ return "11be-eht160";
+ case MODE_11BE_EHT160_160:
+ return "11be-eht160+160";
+ case MODE_11BE_EHT320:
+ return "11be-eht320";
+ case MODE_11BE_EHT20_2G:
+ return "11be-eht20-2g";
+ case MODE_11BE_EHT40_2G:
+ return "11be-eht40-2g";
case MODE_UNKNOWN:
/* skip */
break;
@@ -821,6 +842,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id,
arg.pref_tx_streams = ar->num_tx_chains;
arg.pref_rx_streams = ar->num_rx_chains;
+ arg.punct_bitmap = 0xFFFFFFFF;
arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
@@ -1637,9 +1659,9 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar,
arg->peer_nss = min(sta->deflink.rx_nss, max_nss);
memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
- sizeof(arg->peer_he_cap_macinfo));
+ sizeof(he_cap->he_cap_elem.mac_cap_info));
memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
- sizeof(arg->peer_he_cap_phyinfo));
+ sizeof(he_cap->he_cap_elem.phy_cap_info));
arg->peer_he_ops = vif->bss_conf.he_oper.params;
/* the top most byte is used to indicate BSS color info */
@@ -1929,6 +1951,41 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_he(struct ath12k *ar,
return MODE_UNKNOWN;
}
+static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar,
+ struct ieee80211_sta *sta)
+{
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320)
+ if (sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[0] &
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+ return MODE_11BE_EHT320;
+
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) {
+ if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ return MODE_11BE_EHT160;
+
+ if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+ return MODE_11BE_EHT80_80;
+
+ ath12k_warn(ar->ab, "invalid EHT PHY capability info for 160 Mhz: %d\n",
+ sta->deflink.he_cap.he_cap_elem.phy_cap_info[0]);
+
+ return MODE_11BE_EHT160;
+ }
+
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80)
+ return MODE_11BE_EHT80;
+
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40)
+ return MODE_11BE_EHT40;
+
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
+ return MODE_11BE_EHT20;
+
+ return MODE_UNKNOWN;
+}
+
static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -1950,7 +2007,12 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
switch (band) {
case NL80211_BAND_2GHZ:
- if (sta->deflink.he_cap.has_he) {
+ if (sta->deflink.eht_cap.has_eht) {
+ if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40)
+ phymode = MODE_11BE_EHT40_2G;
+ else
+ phymode = MODE_11BE_EHT20_2G;
+ } else if (sta->deflink.he_cap.has_he) {
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80)
phymode = MODE_11AX_HE80_2G;
else if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40)
@@ -1977,8 +2039,10 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
break;
case NL80211_BAND_5GHZ:
case NL80211_BAND_6GHZ:
- /* Check HE first */
- if (sta->deflink.he_cap.has_he) {
+ /* Check EHT first */
+ if (sta->deflink.eht_cap.has_eht) {
+ phymode = ath12k_mac_get_phymode_eht(ar, sta);
+ } else if (sta->deflink.he_cap.has_he) {
phymode = ath12k_mac_get_phymode_he(ar, sta);
} else if (sta->deflink.vht_cap.vht_supported &&
!ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
@@ -2004,6 +2068,152 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
WARN_ON(phymode == MODE_UNKNOWN);
}
+static void ath12k_mac_set_eht_mcs(u8 rx_tx_mcs7, u8 rx_tx_mcs9,
+ u8 rx_tx_mcs11, u8 rx_tx_mcs13,
+ u32 *rx_mcs, u32 *tx_mcs)
+{
+ *rx_mcs = 0;
+ u32p_replace_bits(rx_mcs,
+ u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_RX),
+ WMI_EHT_MCS_NSS_0_7);
+ u32p_replace_bits(rx_mcs,
+ u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_RX),
+ WMI_EHT_MCS_NSS_8_9);
+ u32p_replace_bits(rx_mcs,
+ u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_RX),
+ WMI_EHT_MCS_NSS_10_11);
+ u32p_replace_bits(rx_mcs,
+ u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_RX),
+ WMI_EHT_MCS_NSS_12_13);
+
+ *tx_mcs = 0;
+ u32p_replace_bits(tx_mcs,
+ u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_TX),
+ WMI_EHT_MCS_NSS_0_7);
+ u32p_replace_bits(tx_mcs,
+ u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_TX),
+ WMI_EHT_MCS_NSS_8_9);
+ u32p_replace_bits(tx_mcs,
+ u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_TX),
+ WMI_EHT_MCS_NSS_10_11);
+ u32p_replace_bits(tx_mcs,
+ u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_TX),
+ WMI_EHT_MCS_NSS_12_13);
+}
+
+static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres,
+ struct ath12k_wmi_ppe_threshold_arg *ppet)
+{
+ u32 bit_pos = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE, val;
+ u8 nss, ru, i;
+ u8 ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2;
+
+ ppet->numss_m1 = u8_get_bits(ppe_thres[0], IEEE80211_EHT_PPE_THRES_NSS_MASK);
+ ppet->ru_bit_mask = u16_get_bits(get_unaligned_le16(ppe_thres),
+ IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
+
+ for (nss = 0; nss <= ppet->numss_m1; nss++) {
+ for (ru = 0;
+ ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
+ ru++) {
+ if ((ppet->ru_bit_mask & BIT(ru)) == 0)
+ continue;
+
+ val = 0;
+ for (i = 0; i < ppet_bit_len_per_ru; i++) {
+ val |= (((ppe_thres[bit_pos / 8] >>
+ (bit_pos % 8)) & 0x1) << i);
+ bit_pos++;
+ }
+ ppet->ppet16_ppet8_ru3_ru0[nss] |=
+ (val << (ru * ppet_bit_len_per_ru));
+ }
+ }
+}
+
+static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ath12k_wmi_peer_assoc_arg *arg)
+{
+ 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 = (struct ath12k_vif *)vif->drv_priv;
+ u32 *rx_mcs, *tx_mcs;
+
+ if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht)
+ return;
+
+ arg->eht_flag = true;
+
+ if ((eht_cap->eht_cap_elem.phy_cap_info[5] &
+ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) &&
+ eht_cap->eht_ppe_thres[0] != 0)
+ ath12k_mac_set_eht_ppe_threshold(eht_cap->eht_ppe_thres,
+ &arg->peer_eht_ppet);
+
+ memcpy(arg->peer_eht_cap_mac, eht_cap->eht_cap_elem.mac_cap_info,
+ sizeof(eht_cap->eht_cap_elem.mac_cap_info));
+ memcpy(arg->peer_eht_cap_phy, eht_cap->eht_cap_elem.phy_cap_info,
+ sizeof(eht_cap->eht_cap_elem.phy_cap_info));
+
+ rx_mcs = arg->peer_eht_rx_mcs_set;
+ tx_mcs = arg->peer_eht_tx_mcs_set;
+
+ switch (sta->deflink.bandwidth) {
+ case IEEE80211_STA_RX_BW_320:
+ bw = &eht_cap->eht_mcs_nss_supp.bw._320;
+ ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs11_max_nss,
+ bw->rx_tx_mcs13_max_nss,
+ &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320],
+ &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320]);
+ arg->peer_eht_mcs_count++;
+ fallthrough;
+ case IEEE80211_STA_RX_BW_160:
+ bw = &eht_cap->eht_mcs_nss_supp.bw._160;
+ ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs11_max_nss,
+ bw->rx_tx_mcs13_max_nss,
+ &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160],
+ &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160]);
+ arg->peer_eht_mcs_count++;
+ fallthrough;
+ default:
+ if ((he_cap->he_cap_elem.phy_cap_info[0] &
+ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) {
+ bw_20 = &eht_cap->eht_mcs_nss_supp.only_20mhz;
+
+ ath12k_mac_set_eht_mcs(bw_20->rx_tx_mcs7_max_nss,
+ bw_20->rx_tx_mcs9_max_nss,
+ bw_20->rx_tx_mcs11_max_nss,
+ bw_20->rx_tx_mcs13_max_nss,
+ &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
+ &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]);
+ } else {
+ bw = &eht_cap->eht_mcs_nss_supp.bw._80;
+ ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs9_max_nss,
+ bw->rx_tx_mcs11_max_nss,
+ bw->rx_tx_mcs13_max_nss,
+ &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80],
+ &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]);
+ }
+
+ arg->peer_eht_mcs_count++;
+ break;
+ }
+
+ arg->punct_bitmap = ~arvif->punct_bitmap;
+}
+
static void ath12k_peer_assoc_prepare(struct ath12k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2023,6 +2233,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar,
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_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);
@@ -2554,6 +2765,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP)
ath12k_mac_fils_discovery(arvif, info);
+ if (changed & BSS_CHANGED_EHT_PUNCTURING)
+ arvif->punct_bitmap = info->eht_puncturing;
+
mutex_unlock(&ar->conf_mutex);
}
@@ -2755,9 +2969,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
arg.scan_id = ATH12K_SCAN_ID;
if (req->ie_len) {
+ arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL);
+ if (!arg.extraie.ptr) {
+ ret = -ENOMEM;
+ goto exit;
+ }
arg.extraie.len = req->ie_len;
- arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL);
- memcpy(arg.extraie.ptr, req->ie, req->ie_len);
}
if (req->n_ssids) {
@@ -2770,6 +2987,14 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
if (req->n_channels) {
arg.num_chan = req->n_channels;
+ arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
+ GFP_KERNEL);
+
+ if (!arg.chan_list) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
for (i = 0; i < arg.num_chan; i++)
arg.chan_list[i] = req->channels[i]->center_freq;
}
@@ -2788,6 +3013,8 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
ATH12K_MAC_SCAN_TIMEOUT_MSECS));
exit:
+ kfree(arg.chan_list);
+
if (req->ie_len)
kfree(arg.extraie.ptr);
@@ -4209,18 +4436,178 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap,
return cpu_to_le16(bcap->he_6ghz_capa);
}
-static int ath12k_mac_copy_he_cap(struct ath12k *ar,
- struct ath12k_pdev_cap *cap,
- struct ieee80211_sband_iftype_data *data,
- int band)
+static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap,
+ int iftype, u8 num_tx_chains,
+ struct ieee80211_sta_he_cap *he_cap)
+{
+ struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
+ struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp;
+
+ he_cap->has_he = true;
+ memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info,
+ sizeof(he_cap_elem->mac_cap_info));
+ memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info,
+ sizeof(he_cap_elem->phy_cap_info));
+
+ he_cap_elem->mac_cap_info[1] &=
+ IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
+
+ he_cap_elem->phy_cap_info[5] &=
+ ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
+ he_cap_elem->phy_cap_info[5] &=
+ ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
+ he_cap_elem->phy_cap_info[5] |= num_tx_chains - 1;
+
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ he_cap_elem->phy_cap_info[3] &=
+ ~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK;
+ he_cap_elem->phy_cap_info[9] |=
+ IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
+ break;
+ case NL80211_IFTYPE_STATION:
+ he_cap_elem->mac_cap_info[0] &= ~IEEE80211_HE_MAC_CAP0_TWT_RES;
+ he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ;
+ he_cap_elem->phy_cap_info[9] |=
+ IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ ath12k_mac_filter_he_cap_mesh(he_cap_elem);
+ break;
+ }
+
+ mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff);
+ mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff);
+ mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+ mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+ mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+ mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+
+ memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
+ if (he_cap_elem->phy_cap_info[6] &
+ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
+ ath12k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres);
+}
+
+static void
+ath12k_mac_copy_eht_mcs_nss(struct ath12k_band_cap *band_cap,
+ struct ieee80211_eht_mcs_nss_supp *mcs_nss,
+ const struct ieee80211_he_cap_elem *he_cap,
+ const struct ieee80211_eht_cap_elem_fixed *eht_cap)
+{
+ if ((he_cap->phy_cap_info[0] &
+ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0)
+ memcpy(&mcs_nss->only_20mhz, &band_cap->eht_mcs_20_only,
+ sizeof(struct ieee80211_eht_mcs_nss_supp_20mhz_only));
+
+ if (he_cap->phy_cap_info[0] &
+ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G))
+ memcpy(&mcs_nss->bw._80, &band_cap->eht_mcs_80,
+ sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
+
+ if (he_cap->phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ memcpy(&mcs_nss->bw._160, &band_cap->eht_mcs_160,
+ sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
+
+ if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+ memcpy(&mcs_nss->bw._320, &band_cap->eht_mcs_320,
+ sizeof(struct ieee80211_eht_mcs_nss_supp_bw));
+}
+
+static void ath12k_mac_copy_eht_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *fw_ppet,
+ struct ieee80211_sta_eht_cap *cap)
+{
+ u16 bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE;
+ u8 i, nss, ru, ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2;
+
+ u8p_replace_bits(&cap->eht_ppe_thres[0], fw_ppet->numss_m1,
+ IEEE80211_EHT_PPE_THRES_NSS_MASK);
+
+ u16p_replace_bits((u16 *)&cap->eht_ppe_thres[0], fw_ppet->ru_bit_mask,
+ IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
+
+ for (nss = 0; nss <= fw_ppet->numss_m1; nss++) {
+ for (ru = 0;
+ ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
+ ru++) {
+ u32 val = 0;
+
+ if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0)
+ continue;
+
+ u32p_replace_bits(&val, fw_ppet->ppet16_ppet8_ru3_ru0[nss] >>
+ (ru * ppet_bit_len_per_ru),
+ GENMASK(ppet_bit_len_per_ru - 1, 0));
+
+ for (i = 0; i < ppet_bit_len_per_ru; i++) {
+ cap->eht_ppe_thres[bit / 8] |=
+ (((val >> i) & 0x1) << ((bit % 8)));
+ bit++;
+ }
+ }
+ }
+}
+
+static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap,
+ struct ieee80211_he_cap_elem *he_cap_elem,
+ int iftype,
+ struct ieee80211_sta_eht_cap *eht_cap)
{
+ struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
+
+ memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap));
+ eht_cap->has_eht = true;
+ memcpy(eht_cap_elem->mac_cap_info, band_cap->eht_cap_mac_info,
+ sizeof(eht_cap_elem->mac_cap_info));
+ memcpy(eht_cap_elem->phy_cap_info, band_cap->eht_cap_phy_info,
+ sizeof(eht_cap_elem->phy_cap_info));
+
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ eht_cap_elem->phy_cap_info[0] &=
+ ~IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ;
+ eht_cap_elem->phy_cap_info[4] &=
+ ~IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO;
+ eht_cap_elem->phy_cap_info[5] &=
+ ~IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP;
+ break;
+ case NL80211_IFTYPE_STATION:
+ eht_cap_elem->phy_cap_info[7] &=
+ ~(IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ);
+ eht_cap_elem->phy_cap_info[7] &=
+ ~(IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ);
+ break;
+ default:
+ break;
+ }
+
+ ath12k_mac_copy_eht_mcs_nss(band_cap, &eht_cap->eht_mcs_nss_supp,
+ he_cap_elem, eht_cap_elem);
+
+ if (eht_cap_elem->phy_cap_info[5] &
+ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT)
+ ath12k_mac_copy_eht_ppe_thresh(&band_cap->eht_ppet, eht_cap);
+}
+
+static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar,
+ struct ath12k_pdev_cap *cap,
+ struct ieee80211_sband_iftype_data *data,
+ int band)
+{
+ struct ath12k_band_cap *band_cap = &cap->band[band];
int i, idx = 0;
for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
- struct ath12k_band_cap *band_cap = &cap->band[band];
- struct ieee80211_he_cap_elem *he_cap_elem =
- &he_cap->he_cap_elem;
switch (i) {
case NL80211_IFTYPE_STATION:
@@ -4233,102 +4620,56 @@ static int ath12k_mac_copy_he_cap(struct ath12k *ar,
}
data[idx].types_mask = BIT(i);
- he_cap->has_he = true;
- memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info,
- sizeof(he_cap_elem->mac_cap_info));
- memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info,
- sizeof(he_cap_elem->phy_cap_info));
-
- he_cap_elem->mac_cap_info[1] &=
- IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
-
- he_cap_elem->phy_cap_info[5] &=
- ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
- he_cap_elem->phy_cap_info[5] &=
- ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
- he_cap_elem->phy_cap_info[5] |= ar->num_tx_chains - 1;
-
- switch (i) {
- case NL80211_IFTYPE_AP:
- he_cap_elem->phy_cap_info[3] &=
- ~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK;
- he_cap_elem->phy_cap_info[9] |=
- IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
- break;
- case NL80211_IFTYPE_STATION:
- he_cap_elem->mac_cap_info[0] &=
- ~IEEE80211_HE_MAC_CAP0_TWT_RES;
- he_cap_elem->mac_cap_info[0] |=
- IEEE80211_HE_MAC_CAP0_TWT_REQ;
- he_cap_elem->phy_cap_info[9] |=
- IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
- break;
- case NL80211_IFTYPE_MESH_POINT:
- ath12k_mac_filter_he_cap_mesh(he_cap_elem);
- break;
- }
-
- he_cap->he_mcs_nss_supp.rx_mcs_80 =
- cpu_to_le16(band_cap->he_mcs & 0xffff);
- he_cap->he_mcs_nss_supp.tx_mcs_80 =
- cpu_to_le16(band_cap->he_mcs & 0xffff);
- he_cap->he_mcs_nss_supp.rx_mcs_160 =
- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
- he_cap->he_mcs_nss_supp.tx_mcs_160 =
- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
- he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
- he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
-
- memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
- if (he_cap_elem->phy_cap_info[6] &
- IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
- ath12k_gen_ppe_thresh(&band_cap->he_ppet,
- he_cap->ppe_thres);
+ ath12k_mac_copy_he_cap(band_cap, i, ar->num_tx_chains, he_cap);
if (band == NL80211_BAND_6GHZ) {
data[idx].he_6ghz_capa.capa =
ath12k_mac_setup_he_6ghz_cap(cap, band_cap);
}
+ ath12k_mac_copy_eht_cap(band_cap, &he_cap->he_cap_elem, i,
+ &data[idx].eht_cap);
idx++;
}
return idx;
}
-static void ath12k_mac_setup_he_cap(struct ath12k *ar,
- struct ath12k_pdev_cap *cap)
+static void ath12k_mac_setup_sband_iftype_data(struct ath12k *ar,
+ struct ath12k_pdev_cap *cap)
{
- struct ieee80211_supported_band *band;
+ struct ieee80211_supported_band *sband;
+ enum nl80211_band band;
int count;
if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) {
- count = ath12k_mac_copy_he_cap(ar, cap,
- ar->mac.iftype[NL80211_BAND_2GHZ],
- NL80211_BAND_2GHZ);
- band = &ar->mac.sbands[NL80211_BAND_2GHZ];
- band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ];
- band->n_iftype_data = count;
+ band = NL80211_BAND_2GHZ;
+ count = ath12k_mac_copy_sband_iftype_data(ar, cap,
+ ar->mac.iftype[band],
+ band);
+ sband = &ar->mac.sbands[band];
+ sband->iftype_data = ar->mac.iftype[band];
+ sband->n_iftype_data = count;
}
if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
- count = ath12k_mac_copy_he_cap(ar, cap,
- ar->mac.iftype[NL80211_BAND_5GHZ],
- NL80211_BAND_5GHZ);
- band = &ar->mac.sbands[NL80211_BAND_5GHZ];
- band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
- band->n_iftype_data = count;
+ band = NL80211_BAND_5GHZ;
+ count = ath12k_mac_copy_sband_iftype_data(ar, cap,
+ ar->mac.iftype[band],
+ band);
+ sband = &ar->mac.sbands[band];
+ sband->iftype_data = ar->mac.iftype[band];
+ sband->n_iftype_data = count;
}
if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP &&
ar->supports_6ghz) {
- count = ath12k_mac_copy_he_cap(ar, cap,
- ar->mac.iftype[NL80211_BAND_6GHZ],
- NL80211_BAND_6GHZ);
- band = &ar->mac.sbands[NL80211_BAND_6GHZ];
- band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ];
- band->n_iftype_data = count;
+ band = NL80211_BAND_6GHZ;
+ count = ath12k_mac_copy_sband_iftype_data(ar, cap,
+ ar->mac.iftype[band],
+ band);
+ sband = &ar->mac.sbands[band];
+ sband->iftype_data = ar->mac.iftype[band];
+ sband->n_iftype_data = count;
}
}
@@ -4373,7 +4714,7 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant)
/* Reload HT/VHT/HE capability */
ath12k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL);
- ath12k_mac_setup_he_cap(ar, &ar->pdev->cap);
+ ath12k_mac_setup_sband_iftype_data(ar, &ar->pdev->cap);
return 0;
}
@@ -5201,7 +5542,7 @@ err:
static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif)
{
- struct ath12k_tx_desc_info *tx_desc_info, *tmp1;
+ struct ath12k_tx_desc_info *tx_desc_info;
struct ath12k_skb_cb *skb_cb;
struct sk_buff *skb;
int i;
@@ -5209,8 +5550,8 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) {
spin_lock_bh(&dp->tx_desc_lock[i]);
- list_for_each_entry_safe(tx_desc_info, tmp1, &dp->tx_desc_used_list[i],
- list) {
+ list_for_each_entry(tx_desc_info, &dp->tx_desc_used_list[i],
+ list) {
skb = tx_desc_info->skb;
if (!skb)
continue;
@@ -5319,7 +5660,6 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
- changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
ar->filter_flags = *total_flags;
@@ -5337,8 +5677,8 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
"fail to set monitor filter: %d\n", ret);
}
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
- "changed_flags:0x%x, total_flags:0x%x, reset_flag:%d\n",
- changed_flags, *total_flags, reset_flag);
+ "total_flags:0x%x, reset_flag:%d\n",
+ *total_flags, reset_flag);
mutex_unlock(&ar->conf_mutex);
}
@@ -5466,6 +5806,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
arg.vdev_id = arvif->vdev_id;
arg.dtim_period = arvif->dtim_period;
arg.bcn_intval = arvif->beacon_interval;
+ arg.punct_bitmap = ~arvif->punct_bitmap;
arg.freq = chandef->chan->center_freq;
arg.band_center_freq1 = chandef->center_freq1;
@@ -5508,9 +5849,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
ath12k_dbg(ab, ATH12K_DBG_MAC,
- "mac vdev %d start center_freq %d phymode %s\n",
+ "mac vdev %d start center_freq %d phymode %s punct_bitmap 0x%x\n",
arg.vdev_id, arg.freq,
- ath12k_mac_phymode_str(arg.mode));
+ ath12k_mac_phymode_str(arg.mode), arg.punct_bitmap);
ret = ath12k_wmi_vdev_start(ar, &arg, restart);
if (ret) {
@@ -5837,6 +6178,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
"mac chanctx assign ptr %pK vdev_id %i\n",
ctx, arvif->vdev_id);
+ arvif->punct_bitmap = link_conf->eht_puncturing;
+
/* 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 &&
@@ -6388,6 +6731,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
{
struct ath12k *ar = hw->priv;
struct ath12k_base *ab = ar->ab;
+ struct ath12k_vif *arvif;
int recovery_count;
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
@@ -6416,6 +6760,26 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset success\n");
}
}
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "reconfig cipher %d up %d vdev type %d\n",
+ arvif->key_cipher,
+ arvif->is_up,
+ arvif->vdev_type);
+ /* After trigger disconnect, then upper layer will
+ * trigger connect again, then the PN number of
+ * upper layer will be reset to keep up with AP
+ * 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);
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "restart disconnect\n");
+ }
+ }
}
mutex_unlock(&ar->conf_mutex);
@@ -6854,7 +7218,7 @@ static int __ath12k_mac_register(struct ath12k *ar)
goto err;
ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
- ath12k_mac_setup_he_cap(ar, cap);
+ ath12k_mac_setup_sband_iftype_data(ar, cap);
ret = ath12k_mac_setup_iface_combinations(ar);
if (ret) {
@@ -6943,6 +7307,8 @@ static int __ath12k_mac_register(struct ath12k *ar)
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
}
+ wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
+
ath12k_reg_init(ar);
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 57f4295420bb..7b16b70df4fa 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -33,7 +33,7 @@ struct ath12k_generic_iter {
#define IEEE80211_VHT_MCS_SUPPORT_0_11_MASK GENMASK(23, 16)
#define IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11 BIT(24)
-#define ATH12K_CHAN_WIDTH_NUM 8
+#define ATH12K_CHAN_WIDTH_NUM 14
#define ATH12K_TX_POWER_MAX_VAL 70
#define ATH12K_TX_POWER_MIN_VAL 0
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 5990a55801f0..bd689efa7daa 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1409,5 +1409,5 @@ static void ath12k_pci_exit(void)
module_exit(ath12k_pci_exit);
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11be WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index b510c2de1bd4..b2db0436bdde 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -387,7 +387,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
mlo_capable_valid),
},
{
- .data_type = QMI_OPT_FLAG,
+ .data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(u8),
.array_type = NO_ARRAY,
diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h
index df76149c49f5..15944f5f33ab 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.h
+++ b/drivers/net/wireless/ath/ath12k/qmi.h
@@ -562,8 +562,6 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 {
int ath12k_qmi_firmware_start(struct ath12k_base *ab,
u32 mode);
void ath12k_qmi_firmware_stop(struct ath12k_base *ab);
-void ath12k_qmi_event_work(struct work_struct *work);
-void ath12k_qmi_msg_recv_work(struct work_struct *work);
void ath12k_qmi_deinit_service(struct ath12k_base *ab);
int ath12k_qmi_init_service(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
index f99556a253e5..bfa87cb8d021 100644
--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
@@ -221,7 +221,7 @@ struct rx_mpdu_start_qcn9274 {
* PPE routing even if RXOLE CCE or flow search indicate 'Use_PPE'
* This is set by SW for peers which are being handled by a
* host SW/accelerator subsystem that also handles packet
- * uffer management for WiFi-to-PPE routing.
+ * buffer management for WiFi-to-PPE routing.
*
* This is cleared by SW for peers which are being handled
* by a different subsystem, completely disabling WiFi-to-PPE
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 4928e4e91660..ef0f3cf35cfd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -62,9 +62,27 @@ struct ath12k_wmi_svc_rdy_ext_parse {
bool dma_ring_cap_done;
};
+struct ath12k_wmi_svc_rdy_ext2_arg {
+ u32 reg_db_version;
+ u32 hw_min_max_tx_power_2ghz;
+ u32 hw_min_max_tx_power_5ghz;
+ u32 chwidth_num_peer_caps;
+ u32 preamble_puncture_bw;
+ u32 max_user_per_ppdu_ofdma;
+ u32 max_user_per_ppdu_mumimo;
+ u32 target_cap_flags;
+ u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];
+ u32 max_num_linkview_peers;
+ u32 max_num_msduq_supported_per_tid;
+ u32 default_num_msduq_supported_per_tid;
+};
+
struct ath12k_wmi_svc_rdy_ext2_parse {
+ struct ath12k_wmi_svc_rdy_ext2_arg arg;
struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse;
bool dma_ring_cap_done;
+ bool spectral_bin_scaling_done;
+ bool mac_phy_caps_ext_done;
};
struct ath12k_wmi_rdy_parse {
@@ -445,8 +463,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps;
const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps;
const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps;
+ struct ath12k_base *ab = wmi_handle->wmi_ab->ab;
struct ath12k_band_cap *cap_band;
struct ath12k_pdev_cap *pdev_cap = &pdev->cap;
+ struct ath12k_fw_pdev *fw_pdev;
u32 phy_map;
u32 hw_idx, phy_idx = 0;
int i;
@@ -475,6 +495,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands);
pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);
+ fw_pdev = &ab->fw_pdev[ab->fw_pdev_count];
+ fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands);
+ fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id);
+ fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id);
+ ab->fw_pdev_count++;
+
/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
* band to band for a single radio, need to see how this should be
* handled.
@@ -995,6 +1021,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
cmd->cac_duration_ms = cpu_to_le32(arg->cac_duration_ms);
cmd->regdomain = cpu_to_le32(arg->regdomain);
cmd->he_ops = cpu_to_le32(arg->he_ops);
+ cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);
if (!restart) {
if (arg->ssid) {
@@ -1791,6 +1818,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
bool hw_crypto_disabled)
{
cmd->peer_flags = 0;
+ cmd->peer_flags_ext = 0;
if (arg->is_wme_set) {
if (arg->qos_flag)
@@ -1805,6 +1833,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
cmd->peer_flags |= cpu_to_le32(WMI_PEER_80MHZ);
if (arg->bw_160)
cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ);
+ if (arg->bw_320)
+ cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ);
/* Typically if STBC is enabled for VHT it should be enabled
* for HT as well
@@ -1832,6 +1862,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_REQ);
if (arg->twt_responder)
cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_RESP);
+ if (arg->eht_flag)
+ cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_EHT);
}
/* Suppress authorization for all AUTH modes that need 4-way handshake
@@ -1876,6 +1908,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
struct wmi_peer_assoc_complete_cmd *cmd;
struct ath12k_wmi_vht_rate_set_params *mcs;
struct ath12k_wmi_he_rate_set_params *he_mcs;
+ struct ath12k_wmi_eht_rate_set_params *eht_mcs;
struct sk_buff *skb;
struct wmi_tlv *tlv;
void *ptr;
@@ -1892,7 +1925,9 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) +
TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) +
sizeof(*mcs) + TLV_HDR_SIZE +
- (sizeof(*he_mcs) * arg->peer_he_mcs_count);
+ (sizeof(*he_mcs) * arg->peer_he_mcs_count) +
+ TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) +
+ TLV_HDR_SIZE + TLV_HDR_SIZE;
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
@@ -1908,6 +1943,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_new_assoc = cpu_to_le32(arg->peer_new_assoc);
cmd->peer_associd = cpu_to_le32(arg->peer_associd);
+ cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);
ath12k_wmi_copy_peer_flags(cmd, arg,
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED,
@@ -1939,6 +1975,16 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_ppet.ppet16_ppet8_ru3_ru0[i] =
cpu_to_le32(arg->peer_ppet.ppet16_ppet8_ru3_ru0[i]);
+ /* Update 11be capabilities */
+ memcpy_and_pad(cmd->peer_eht_cap_mac, sizeof(cmd->peer_eht_cap_mac),
+ arg->peer_eht_cap_mac, sizeof(arg->peer_eht_cap_mac),
+ 0);
+ memcpy_and_pad(cmd->peer_eht_cap_phy, sizeof(cmd->peer_eht_cap_phy),
+ arg->peer_eht_cap_phy, sizeof(arg->peer_eht_cap_phy),
+ 0);
+ memcpy_and_pad(&cmd->peer_eht_ppet, sizeof(cmd->peer_eht_ppet),
+ &arg->peer_eht_ppet, sizeof(arg->peer_eht_ppet), 0);
+
/* Update peer legacy rate information */
ptr += sizeof(*cmd);
@@ -2005,8 +2051,36 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
ptr += sizeof(*he_mcs);
}
+ /* MLO header tag with 0 length */
+ len = 0;
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
+ /* Loop through the EHT rate set */
+ len = arg->peer_eht_mcs_count * sizeof(*eht_mcs);
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
+ for (i = 0; i < arg->peer_eht_mcs_count; i++) {
+ eht_mcs = ptr;
+ eht_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HE_RATE_SET,
+ sizeof(*eht_mcs));
+
+ eht_mcs->rx_mcs_set = cpu_to_le32(arg->peer_eht_rx_mcs_set[i]);
+ eht_mcs->tx_mcs_set = cpu_to_le32(arg->peer_eht_tx_mcs_set[i]);
+ ptr += sizeof(*eht_mcs);
+ }
+
+ /* ML partner links tag with 0 length */
+ len = 0;
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
- "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n",
+ "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n",
cmd->vdev_id, cmd->peer_associd, arg->peer_mac,
cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps,
cmd->peer_listen_intval, cmd->peer_ht_caps,
@@ -2016,7 +2090,10 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_he_ops, cmd->peer_he_cap_info_ext,
cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1],
cmd->peer_he_cap_phy[2],
- cmd->peer_bw_rxnss_override);
+ cmd->peer_bw_rxnss_override, cmd->peer_flags_ext,
+ cmd->peer_eht_cap_mac[0], cmd->peer_eht_cap_mac[1],
+ cmd->peer_eht_cap_phy[0], cmd->peer_eht_cap_phy[1],
+ cmd->peer_eht_cap_phy[2]);
ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID);
if (ret) {
@@ -2162,12 +2239,6 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
if (arg->num_bssid)
len += sizeof(*bssid) * arg->num_bssid;
- len += TLV_HDR_SIZE;
- if (arg->extraie.len)
- extraie_len_with_pad =
- roundup(arg->extraie.len, sizeof(u32));
- len += extraie_len_with_pad;
-
if (arg->num_hint_bssid)
len += TLV_HDR_SIZE +
arg->num_hint_bssid * sizeof(*hint_bssid);
@@ -2176,6 +2247,18 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
len += TLV_HDR_SIZE +
arg->num_hint_s_ssid * sizeof(*s_ssid);
+ len += TLV_HDR_SIZE;
+ if (arg->extraie.len)
+ extraie_len_with_pad =
+ roundup(arg->extraie.len, sizeof(u32));
+ if (extraie_len_with_pad <= (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len)) {
+ len += extraie_len_with_pad;
+ } else {
+ ath12k_warn(ar->ab, "discard large size %d bytes extraie for scan start\n",
+ arg->extraie.len);
+ extraie_len_with_pad = 0;
+ }
+
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
@@ -2265,7 +2348,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len);
ptr += TLV_HDR_SIZE;
- if (arg->extraie.len)
+ if (extraie_len_with_pad)
memcpy(ptr, arg->extraie.ptr,
arg->extraie.len);
@@ -3704,6 +3787,10 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) {
hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];
mode = le32_to_cpu(hw_mode_caps->hw_mode_id);
+
+ if (mode >= WMI_HOST_HW_MODE_MAX)
+ continue;
+
pref = soc->wmi_ab.preferred_hw_mode;
if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {
@@ -3810,6 +3897,7 @@ static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc,
soc->num_radios = 0;
phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map);
+ soc->fw_pdev_count = 0;
while (phy_id_map && soc->num_radios < MAX_RADIOS) {
ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle,
@@ -4037,14 +4125,165 @@ err:
return ret;
}
+static int ath12k_pull_svc_ready_ext2(struct ath12k_wmi_pdev *wmi_handle,
+ const void *ptr,
+ struct ath12k_wmi_svc_rdy_ext2_arg *arg)
+{
+ const struct wmi_service_ready_ext2_event *ev = ptr;
+
+ if (!ev)
+ return -EINVAL;
+
+ arg->reg_db_version = le32_to_cpu(ev->reg_db_version);
+ arg->hw_min_max_tx_power_2ghz = le32_to_cpu(ev->hw_min_max_tx_power_2ghz);
+ arg->hw_min_max_tx_power_5ghz = le32_to_cpu(ev->hw_min_max_tx_power_5ghz);
+ arg->chwidth_num_peer_caps = le32_to_cpu(ev->chwidth_num_peer_caps);
+ arg->preamble_puncture_bw = le32_to_cpu(ev->preamble_puncture_bw);
+ arg->max_user_per_ppdu_ofdma = le32_to_cpu(ev->max_user_per_ppdu_ofdma);
+ arg->max_user_per_ppdu_mumimo = le32_to_cpu(ev->max_user_per_ppdu_mumimo);
+ arg->target_cap_flags = le32_to_cpu(ev->target_cap_flags);
+ return 0;
+}
+
+static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
+ const __le32 cap_mac_info[],
+ const __le32 cap_phy_info[],
+ const __le32 supp_mcs[],
+ const struct ath12k_wmi_ppe_threshold_params *ppet,
+ __le32 cap_info_internal)
+{
+ struct ath12k_band_cap *cap_band = &pdev->cap.band[band];
+ u8 i;
+
+ for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++)
+ cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]);
+
+ for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)
+ cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);
+
+ cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);
+ cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);
+ if (band != NL80211_BAND_2GHZ) {
+ cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]);
+ cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]);
+ }
+
+ cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1);
+ cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info);
+ for (i = 0; i < WMI_MAX_NUM_SS; i++)
+ cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] =
+ le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]);
+
+ cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal);
+}
+
+static int
+ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab,
+ const struct ath12k_wmi_caps_ext_params *caps,
+ struct ath12k_pdev *pdev)
+{
+ u32 bands;
+ int i;
+
+ if (ab->hw_params->single_pdev_only) {
+ for (i = 0; i < ab->fw_pdev_count; i++) {
+ struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i];
+
+ if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) &&
+ fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) {
+ bands = fw_pdev->supported_bands;
+ break;
+ }
+ }
+
+ if (i == ab->fw_pdev_count)
+ return -EINVAL;
+ } else {
+ bands = pdev->cap.supported_bands;
+ }
+
+ if (bands & WMI_HOST_WLAN_2G_CAP) {
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_2GHZ,
+ caps->eht_cap_mac_info_2ghz,
+ caps->eht_cap_phy_info_2ghz,
+ caps->eht_supp_mcs_ext_2ghz,
+ &caps->eht_ppet_2ghz,
+ caps->eht_cap_info_internal);
+ }
+
+ if (bands & WMI_HOST_WLAN_5G_CAP) {
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_5GHZ,
+ caps->eht_cap_mac_info_5ghz,
+ caps->eht_cap_phy_info_5ghz,
+ caps->eht_supp_mcs_ext_5ghz,
+ &caps->eht_ppet_5ghz,
+ caps->eht_cap_info_internal);
+
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_6GHZ,
+ caps->eht_cap_mac_info_5ghz,
+ caps->eht_cap_phy_info_5ghz,
+ caps->eht_supp_mcs_ext_5ghz,
+ &caps->eht_ppet_5ghz,
+ caps->eht_cap_info_internal);
+ }
+
+ return 0;
+}
+
+static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag,
+ u16 len, const void *ptr,
+ void *data)
+{
+ const struct ath12k_wmi_caps_ext_params *caps = ptr;
+ int i = 0, ret;
+
+ if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT)
+ return -EPROTO;
+
+ if (ab->hw_params->single_pdev_only) {
+ if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id))
+ return 0;
+ } else {
+ for (i = 0; i < ab->num_radios; i++) {
+ if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id))
+ break;
+ }
+
+ if (i == ab->num_radios)
+ return -EINVAL;
+ }
+
+ ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, &ab->pdevs[i]);
+ if (ret) {
+ ath12k_warn(ab,
+ "failed to parse extended MAC PHY capabilities for pdev %d: %d\n",
+ ret, ab->pdevs[i].pdev_id);
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
+ struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];
struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;
int ret;
switch (tag) {
+ case WMI_TAG_SERVICE_READY_EXT2_EVENT:
+ ret = ath12k_pull_svc_ready_ext2(wmi_handle, ptr,
+ &parse->arg);
+ if (ret) {
+ ath12k_warn(ab,
+ "failed to extract wmi service ready ext2 parameters: %d\n",
+ ret);
+ return ret;
+ }
+ break;
+
case WMI_TAG_ARRAY_STRUCT:
if (!parse->dma_ring_cap_done) {
ret = ath12k_wmi_dma_ring_caps(ab, len, ptr,
@@ -4053,6 +4292,23 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
return ret;
parse->dma_ring_cap_done = true;
+ } else if (!parse->spectral_bin_scaling_done) {
+ /* TODO: This is a place-holder as WMI tag for
+ * spectral scaling is before
+ * WMI_TAG_MAC_PHY_CAPABILITIES_EXT
+ */
+ parse->spectral_bin_scaling_done = true;
+ } else if (!parse->mac_phy_caps_ext_done) {
+ ret = ath12k_wmi_tlv_iter(ab, ptr, len,
+ ath12k_wmi_tlv_mac_phy_caps_ext,
+ parse);
+ if (ret) {
+ ath12k_warn(ab, "failed to parse extended MAC PHY capabilities WMI TLV: %d\n",
+ ret);
+ return ret;
+ }
+
+ parse->mac_phy_caps_ext_done = true;
}
break;
default:
@@ -5222,7 +5478,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ar = ab->pdevs[pdev_idx].ar;
kfree(ab->new_regd[pdev_idx]);
ab->new_regd[pdev_idx] = regd;
- ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+ queue_work(ab->workqueue, &ar->regd_update_work);
} else {
/* Multiple events for the same *ar is not expected. But we
* can still clear any previously stored default_regd if we
@@ -5697,6 +5953,8 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
ath12k_wmi_event_scan_start_failed(ar);
break;
case WMI_SCAN_EVENT_DEQUEUED:
+ __ath12k_mac_scan_finish(ar);
+ break;
case WMI_SCAN_EVENT_PREEMPTED:
case WMI_SCAN_EVENT_RESTARTED:
case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index d89c12bfb009..c75a6fa1f7e0 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -1167,6 +1167,11 @@ enum wmi_tlv_peer_flags {
};
+enum wmi_tlv_peer_flags_ext {
+ WMI_PEER_EXT_EHT = BIT(0),
+ WMI_PEER_EXT_320MHZ = BIT(1),
+};
+
/** Enum list of TLV Tags for each parameter structure type. */
enum wmi_tlv_tag {
WMI_TAG_LAST_RESERVED = 15,
@@ -1920,10 +1925,12 @@ enum wmi_tlv_tag {
/* TODO add all the missing cmds */
WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301,
WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO,
+ WMI_TAG_SERVICE_READY_EXT2_EVENT = 0x334,
WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344,
WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
+ WMI_TAG_EHT_RATE_SET = 0x3C4,
WMI_TAG_MAX
};
@@ -2581,6 +2588,69 @@ struct ath12k_wmi_soc_hal_reg_caps_params {
__le32 num_phy;
} __packed;
+#define WMI_MAX_EHTCAP_MAC_SIZE 2
+#define WMI_MAX_EHTCAP_PHY_SIZE 3
+#define WMI_MAX_EHTCAP_RATE_SET 3
+
+/* Used for EHT MCS-NSS array. Data at each array index follows the format given
+ * in IEEE P802.11be/D2.0, May 20229.4.2.313.4.
+ *
+ * Index interpretation:
+ * 0 - 20 MHz only sta, all 4 bytes valid
+ * 1 - index for bandwidths <= 80 MHz except 20 MHz-only, first 3 bytes valid
+ * 2 - index for 160 MHz, first 3 bytes valid
+ * 3 - index for 320 MHz, first 3 bytes valid
+ */
+#define WMI_MAX_EHT_SUPP_MCS_2G_SIZE 2
+#define WMI_MAX_EHT_SUPP_MCS_5G_SIZE 4
+
+#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_80 0
+#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_160 1
+#define WMI_EHTCAP_TXRX_MCS_NSS_IDX_320 2
+
+#define WMI_EHT_MCS_NSS_0_7 GENMASK(3, 0)
+#define WMI_EHT_MCS_NSS_8_9 GENMASK(7, 4)
+#define WMI_EHT_MCS_NSS_10_11 GENMASK(11, 8)
+#define WMI_EHT_MCS_NSS_12_13 GENMASK(15, 12)
+
+struct wmi_service_ready_ext2_event {
+ __le32 reg_db_version;
+ __le32 hw_min_max_tx_power_2ghz;
+ __le32 hw_min_max_tx_power_5ghz;
+ __le32 chwidth_num_peer_caps;
+ __le32 preamble_puncture_bw;
+ __le32 max_user_per_ppdu_ofdma;
+ __le32 max_user_per_ppdu_mumimo;
+ __le32 target_cap_flags;
+ __le32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];
+ __le32 max_num_linkview_peers;
+ __le32 max_num_msduq_supported_per_tid;
+ __le32 default_num_msduq_supported_per_tid;
+} __packed;
+
+struct ath12k_wmi_caps_ext_params {
+ __le32 hw_mode_id;
+ union {
+ struct {
+ __le16 pdev_id;
+ __le16 hw_link_id;
+ } __packed ath12k_wmi_pdev_to_link_map;
+ __le32 pdev_id;
+ };
+ __le32 phy_id;
+ __le32 wireless_modes_ext;
+ __le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE];
+ __le32 eht_cap_mac_info_5ghz[WMI_MAX_EHTCAP_MAC_SIZE];
+ __le32 rsvd0[2];
+ __le32 eht_cap_phy_info_2ghz[WMI_MAX_EHTCAP_PHY_SIZE];
+ __le32 eht_cap_phy_info_5ghz[WMI_MAX_EHTCAP_PHY_SIZE];
+ struct ath12k_wmi_ppe_threshold_params eht_ppet_2ghz;
+ struct ath12k_wmi_ppe_threshold_params eht_ppet_5ghz;
+ __le32 eht_cap_info_internal;
+ __le32 eht_supp_mcs_ext_2ghz[WMI_MAX_EHT_SUPP_MCS_2G_SIZE];
+ __le32 eht_supp_mcs_ext_5ghz[WMI_MAX_EHT_SUPP_MCS_5G_SIZE];
+} __packed;
+
/* 2 word representation of MAC addr */
struct ath12k_wmi_mac_addr_params {
u8 addr[ETH_ALEN];
@@ -2705,6 +2775,11 @@ struct wmi_vdev_start_request_cmd {
__le32 he_ops;
__le32 cac_duration_ms;
__le32 regdomain;
+ __le32 min_data_rate;
+ __le32 mbssid_flags;
+ __le32 mbssid_tx_vdev_id;
+ __le32 eht_ops;
+ __le32 punct_bitmap;
} __packed;
#define MGMT_TX_DL_FRM_LEN 64
@@ -2758,8 +2833,17 @@ enum wmi_phy_mode {
MODE_11AX_HE20_2G = 21,
MODE_11AX_HE40_2G = 22,
MODE_11AX_HE80_2G = 23,
- MODE_UNKNOWN = 24,
- MODE_MAX = 24
+ MODE_11BE_EHT20 = 24,
+ MODE_11BE_EHT40 = 25,
+ MODE_11BE_EHT80 = 26,
+ MODE_11BE_EHT80_80 = 27,
+ MODE_11BE_EHT160 = 28,
+ MODE_11BE_EHT160_160 = 29,
+ MODE_11BE_EHT320 = 30,
+ MODE_11BE_EHT20_2G = 31,
+ MODE_11BE_EHT40_2G = 32,
+ MODE_UNKNOWN = 33,
+ MODE_MAX = 33,
};
struct wmi_vdev_start_req_arg {
@@ -2795,6 +2879,10 @@ struct wmi_vdev_start_req_arg {
u32 pref_rx_streams;
u32 pref_tx_streams;
u32 num_noa_descriptors;
+ u32 min_data_rate;
+ u32 mbssid_flags;
+ u32 mbssid_tx_vdev_id;
+ u32 punct_bitmap;
};
struct ath12k_wmi_peer_create_arg {
@@ -3034,7 +3122,6 @@ enum scan_dwelltime_adaptive_mode {
#define WLAN_SCAN_MAX_NUM_SSID 10
#define WLAN_SCAN_MAX_NUM_BSSID 10
-#define WLAN_SCAN_MAX_NUM_CHANNELS 40
struct ath12k_wmi_element_info_arg {
u32 len;
@@ -3243,7 +3330,7 @@ struct ath12k_wmi_scan_req_arg {
u32 num_bssid;
u32 num_ssids;
u32 n_probes;
- u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS];
+ u32 *chan_list;
u32 notify_scan_events;
struct cfg80211_ssid ssid[WLAN_SCAN_MAX_NUM_SSID];
struct ath12k_wmi_mac_addr_params bssid_list[WLAN_SCAN_MAX_NUM_BSSID];
@@ -3491,6 +3578,7 @@ struct ath12k_wmi_peer_assoc_arg {
bool bw_40;
bool bw_80;
bool bw_160;
+ bool bw_320;
bool stbc_flag;
bool ldpc_flag;
bool static_mimops_flag;
@@ -3518,6 +3606,14 @@ struct ath12k_wmi_peer_assoc_arg {
bool twt_responder;
bool twt_requester;
struct ath12k_wmi_ppe_threshold_arg peer_ppet;
+ bool eht_flag;
+ u32 peer_eht_cap_mac[WMI_MAX_EHTCAP_MAC_SIZE];
+ u32 peer_eht_cap_phy[WMI_MAX_EHTCAP_PHY_SIZE];
+ u32 peer_eht_mcs_count;
+ u32 peer_eht_rx_mcs_set[WMI_MAX_EHTCAP_RATE_SET];
+ u32 peer_eht_tx_mcs_set[WMI_MAX_EHTCAP_RATE_SET];
+ struct ath12k_wmi_ppe_threshold_arg peer_eht_ppet;
+ u32 punct_bitmap;
};
struct wmi_peer_assoc_complete_cmd {
@@ -3549,6 +3645,15 @@ struct wmi_peer_assoc_complete_cmd {
__le32 peer_he_cap_info_internal;
__le32 min_data_rate;
__le32 peer_he_caps_6ghz;
+ __le32 sta_type;
+ __le32 bss_max_idle_option;
+ __le32 auth_mode;
+ __le32 peer_flags_ext;
+ __le32 punct_bitmap;
+ __le32 peer_eht_cap_mac[WMI_MAX_EHTCAP_MAC_SIZE];
+ __le32 peer_eht_cap_phy[WMI_MAX_EHTCAP_PHY_SIZE];
+ __le32 peer_eht_ops;
+ struct ath12k_wmi_ppe_threshold_params peer_eht_ppet;
} __packed;
struct wmi_stop_scan_cmd {
@@ -3776,6 +3881,12 @@ struct ath12k_wmi_he_rate_set_params {
__le32 tx_mcs_set;
} __packed;
+struct ath12k_wmi_eht_rate_set_params {
+ __le32 tlv_header;
+ __le32 rx_mcs_set;
+ __le32 tx_mcs_set;
+} __packed;
+
#define MAX_REG_RULES 10
#define REG_ALPHA2_LEN 2
#define MAX_6G_REG_RULES 5
@@ -4744,8 +4855,6 @@ int ath12k_wmi_vdev_install_key(struct ath12k *ar,
struct wmi_vdev_install_key_arg *arg);
int ath12k_wmi_pdev_bss_chan_info_request(struct ath12k *ar,
enum wmi_bss_chan_info_req_type type);
-int ath12k_wmi_send_stats_request_cmd(struct ath12k *ar, u32 stats_id,
- u32 vdev_id, u32 pdev_id);
int ath12k_wmi_send_pdev_temperature_cmd(struct ath12k *ar);
int ath12k_wmi_send_peer_flush_tids_cmd(struct ath12k *ar,
u8 peer_addr[ETH_ALEN],
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 28a1e5eff204..08bd5d3b00f1 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -115,7 +115,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq);
ret = irq;
goto err_iounmap;
}
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4b41160e5d38..ec130510aeb2 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -982,8 +982,6 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
ah->debug.level = ath5k_debug;
phydir = debugfs_create_dir("ath5k", ah->hw->wiphy->debugfsdir);
- if (!phydir)
- return;
debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 11ed30d6b595..c630343ca4f9 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -382,7 +382,6 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
mfilt[1] = multicast >> 32;
/* Only deal with supported flags */
- changed_flags &= SUPPORTED_FIF_FLAGS;
*new_flags &= SUPPORTED_FIF_FLAGS;
/* If HW detects any phy or radar errors, leave those filters on.
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 5797ef9c73d7..7ee4e1616f45 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sort.h>
#include <asm/unaligned.h>
#include "ath5k.h"
@@ -1554,6 +1555,11 @@ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
hist->nfval[hist->index] = noise_floor;
}
+static int cmps16(const void *a, const void *b)
+{
+ return *(s16 *)a - *(s16 *)b;
+}
+
/**
* ath5k_hw_get_median_noise_floor() - Get median NF from history buffer
* @ah: The &struct ath5k_hw
@@ -1561,25 +1567,16 @@ static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
static s16
ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
{
- s16 sort[ATH5K_NF_CAL_HIST_MAX];
- s16 tmp;
- int i, j;
-
- memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
- for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
- for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
- if (sort[j] > sort[j - 1]) {
- tmp = sort[j];
- sort[j] = sort[j - 1];
- sort[j - 1] = tmp;
- }
- }
- }
+ s16 sorted_nfval[ATH5K_NF_CAL_HIST_MAX];
+ int i;
+
+ memcpy(sorted_nfval, ah->ah_nfcal_hist.nfval, sizeof(sorted_nfval));
+ sort(sorted_nfval, ATH5K_NF_CAL_HIST_MAX, sizeof(s16), cmps16, NULL);
for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
- "cal %d:%d\n", i, sort[i]);
+ "cal %d:%d\n", i, sorted_nfval[i]);
}
- return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2];
+ return sorted_nfval[(ATH5K_NF_CAL_HIST_MAX - 1) / 2];
}
/**
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 433a047f3747..b837d31416df 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -1793,8 +1793,6 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
{
ar->debugfs_phy = debugfs_create_dir("ath6kl",
ar->wiphy->debugfsdir);
- if (!ar->debugfs_phy)
- return -ENOMEM;
debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,
&fops_tgt_stats);
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 9cd12b20b18d..9bfaadfa6c00 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -132,8 +132,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
ah = sc->sc_ah;
ath9k_hw_name(ah, hw_name, sizeof(hw_name));
- wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
- hw_name, (unsigned long)mem, irq);
+ wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n",
+ hw_name, mem, irq);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 2cc23605c9fc..668fc07b3073 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -1129,7 +1129,6 @@ void ath_restart_work(struct ath_softc *sc);
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops);
void ath9k_deinit_device(struct ath_softc *sc);
-void ath9k_reload_chainmask_settings(struct ath_softc *sc);
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
void ath_start_rfkill_poll(struct ath_softc *sc);
void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index e055adfb5361..a5349c72c332 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -855,16 +855,11 @@ static ssize_t write_file_spectral_short_repeat(struct file *file,
{
struct ath_spec_scan_priv *spec_priv = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val > 1)
return -EINVAL;
@@ -903,17 +898,11 @@ static ssize_t write_file_spectral_count(struct file *file,
{
struct ath_spec_scan_priv *spec_priv = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ssize_t ret;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val > 255)
return -EINVAL;
@@ -951,16 +940,11 @@ static ssize_t write_file_spectral_period(struct file *file,
{
struct ath_spec_scan_priv *spec_priv = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val > 255)
return -EINVAL;
@@ -999,16 +983,11 @@ static ssize_t write_file_spectral_fft_period(struct file *file,
{
struct ath_spec_scan_priv *spec_priv = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val > 15)
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index f0ab6f9955e4..12204cf86fcf 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -85,8 +85,6 @@ struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
struct ath_hw *ah,
struct cfg80211_chan_def *chandef);
int ath9k_cmn_count_streams(unsigned int chainmask, int max);
-void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
- enum ath_stomp_type stomp_type);
void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
u16 new_txpow, u16 *txpower);
void ath9k_cmn_init_crypto(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index fb7a2952d0ce..9bc57c5a89bf 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -96,21 +96,16 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
}
static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long mask;
- char buf[32];
- ssize_t len;
+ ssize_t ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &mask))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &mask);
+ if (ret)
+ return ret;
common->debug_mask = mask;
return count;
@@ -191,16 +186,11 @@ static ssize_t write_file_ani(struct file *file,
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long ani;
- char buf[32];
- ssize_t len;
+ ssize_t ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &ani))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &ani);
+ if (ret)
+ return ret;
if (ani > 1)
return -EINVAL;
@@ -248,20 +238,15 @@ static ssize_t write_file_bt_ant_diversity(struct file *file,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps;
unsigned long bt_ant_diversity;
- char buf[32];
- ssize_t len;
+ ssize_t ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ret = kstrtoul_from_user(user_buf, count, 0, &bt_ant_diversity);
+ if (ret)
+ return ret;
if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV))
goto exit;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &bt_ant_diversity))
- return -EINVAL;
-
common->bt_ant_diversity = !!bt_ant_diversity;
ath9k_ps_wakeup(sc);
ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity);
@@ -792,16 +777,11 @@ static ssize_t write_file_reset(struct file *file,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val != 1)
return -EINVAL;
@@ -886,16 +866,11 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
{
struct ath_softc *sc = file->private_data;
unsigned long regidx;
- char buf[32];
- ssize_t len;
+ ssize_t ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &regidx))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &regidx);
+ if (ret)
+ return ret;
sc->debug.regidx = regidx;
return count;
@@ -931,16 +906,11 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
struct ath_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah;
unsigned long regval;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &regval))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &regval);
+ if (ret)
+ return ret;
ath9k_ps_wakeup(sc);
REG_WRITE_D(ah, sc->debug.regidx, regval);
@@ -1128,16 +1098,11 @@ static ssize_t write_file_wow(struct file *file, const char __user *user_buf,
{
struct ath_softc *sc = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val != 1)
return -EINVAL;
@@ -1191,17 +1156,12 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf,
struct ath_softc *sc = file->private_data;
struct ath_hw *ah = sc->sc_ah;
unsigned long val;
- char buf[32];
- ssize_t len;
+ ssize_t ret;
bool tpc_enabled;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val > 1)
return -EINVAL;
@@ -1420,7 +1380,7 @@ int ath9k_init_debug(struct ath_hw *ah)
sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
sc->hw->wiphy->debugfsdir);
- if (!sc->debug.debugfs_phy)
+ if (IS_ERR(sc->debug.debugfs_phy))
return -ENOMEM;
#ifdef CONFIG_ATH_DEBUG
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 2a79c2fa8415..8e18e9b4ef48 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -99,17 +99,11 @@ static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
{
struct ath_softc *sc = file->private_data;
unsigned long val;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &val))
- return -EINVAL;
+ ssize_t ret;
+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
+ if (ret)
+ return ret;
if (val == DFS_STATS_RESET_MAGIC)
memset(&sc->debug.stats.dfs_stats, 0,
sizeof(sc->debug.stats.dfs_stats));
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 3caa149b1013..fd5312c2a7e3 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -572,8 +572,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
}
for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode =
- (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
+ bool isHt40CtlMode = pCtlMode[ctlMode] == CTL_2GHT40;
if (isHt40CtlMode)
freq = centers.synth_center;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 27ff1ca2631f..e5414435b141 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1432,7 +1432,7 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
- bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
+ bool unplugged = udev->state == USB_STATE_NOTATTACHED;
if (!hif_dev)
return;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index b3ed65e5c4da..c549ff3abcdc 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -375,16 +375,11 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
struct ath9k_htc_priv *priv = file->private_data;
struct ath_common *common = ath9k_hw_common(priv->ah);
unsigned long mask;
- char buf[32];
- ssize_t len;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
+ ssize_t ret;
- buf[len] = '\0';
- if (kstrtoul(buf, 0, &mask))
- return -EINVAL;
+ ret = kstrtoul_from_user(user_buf, count, 0, &mask);
+ if (ret)
+ return ret;
common->debug_mask = mask;
return count;
@@ -491,7 +486,7 @@ int ath9k_htc_init_debug(struct ath_hw *ah)
priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
priv->hw->wiphy->debugfsdir);
- if (!priv->debug.debugfs_phy)
+ if (IS_ERR(priv->debug.debugfs_phy))
return -ENOMEM;
ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 51766de5ec3b..9a9b5212051a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -719,7 +719,7 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
aggr.sta_index = ista->index;
aggr.tidno = tid & 0xf;
- aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
+ aggr.aggr_enable = action == IEEE80211_AMPDU_TX_START;
WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
if (ret)
@@ -1264,7 +1264,6 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
u32 rfilt;
mutex_lock(&priv->mutex);
- changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index af44b33814dd..f03d792732da 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -115,8 +115,10 @@ struct ath_tx_status {
u8 qid;
u16 desc_id;
u8 tid;
- u32 ba_low;
- u32 ba_high;
+ struct_group(ba,
+ u32 ba_low;
+ u32 ba_high;
+ );
u32 evm0;
u32 evm1;
u32 evm2;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 6360d3356e25..1494feedb27d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1571,7 +1571,6 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
struct ath_chanctx *ctx;
u32 rfilt;
- changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
spin_lock_bh(&sc->chan_lock);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index a09f9d223f3d..0633589b85c2 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -988,8 +988,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->sc_ah->msi_reg = 0;
ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
- wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n",
- hw_name, (unsigned long)sc->mem, pdev->irq);
+ wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n",
+ hw_name, sc->mem, pdev->irq);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index 8a996ed9a3be..f2144fd39093 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -172,9 +172,8 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
{
struct ath_softc *sc = file->private_data;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- char buf[32];
bool start;
- ssize_t len;
+ ssize_t ret;
int r;
if (count < 1)
@@ -183,14 +182,9 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
if (sc->cur_chan->nvifs > 1)
return -EOPNOTSUPP;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
-
- buf[len] = '\0';
-
- if (kstrtobool(buf, &start))
- return -EINVAL;
+ ret = kstrtobool_from_user(user_buf, count, &start);
+ if (ret)
+ return ret;
mutex_lock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index d652c647d56b..1476b42b52a9 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -242,10 +242,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
goto free_skb;
}
- spin_unlock_irqrestore(&wmi->wmi_lock, flags);
/* WMI command response */
ath9k_wmi_rsp_callback(wmi, skb);
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
free_skb:
kfree_skb(skb);
@@ -283,7 +283,8 @@ int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
static int ath9k_wmi_cmd_issue(struct wmi *wmi,
struct sk_buff *skb,
- enum wmi_cmd_id cmd, u16 len)
+ enum wmi_cmd_id cmd, u16 len,
+ u8 *rsp_buf, u32 rsp_len)
{
struct wmi_cmd_hdr *hdr;
unsigned long flags;
@@ -293,6 +294,11 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
spin_lock_irqsave(&wmi->wmi_lock, flags);
+
+ /* record the rsp buffer and length */
+ wmi->cmd_rsp_buf = rsp_buf;
+ wmi->cmd_rsp_len = rsp_len;
+
wmi->last_seq_id = wmi->tx_seq_id;
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
@@ -308,8 +314,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
struct ath_common *common = ath9k_hw_common(ah);
u16 headroom = sizeof(struct htc_frame_hdr) +
sizeof(struct wmi_cmd_hdr);
+ unsigned long time_left, flags;
struct sk_buff *skb;
- unsigned long time_left;
int ret = 0;
if (ah->ah_flags & AH_UNPLUGGED)
@@ -333,11 +339,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
goto out;
}
- /* record the rsp buffer and length */
- wmi->cmd_rsp_buf = rsp_buf;
- wmi->cmd_rsp_len = rsp_len;
-
- ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
+ ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len);
if (ret)
goto out;
@@ -345,7 +347,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
if (!time_left) {
ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
wmi_cmd_to_name(cmd_id));
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
wmi->last_seq_id = 0;
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
mutex_unlock(&wmi->op_mutex);
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index f6f2ab7a63ff..4e939dcac1c9 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -466,9 +466,11 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
*nframes = 0;
isaggr = bf_isaggr(bf);
+ memset(ba, 0, WME_BA_BMP_SIZE >> 3);
+
if (isaggr) {
seq_st = ts->ts_seqnum;
- memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
+ memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3);
}
while (bf) {
@@ -551,7 +553,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (isaggr && txok) {
if (ts->ts_flags & ATH9K_TX_BA) {
seq_st = ts->ts_seqnum;
- memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
+ memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3);
} else {
/*
* AR5416 can become deaf/mute when BA
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index b7b61d4f02ba..21a93fec284d 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -104,7 +104,7 @@ bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
* Not setting this bit allows the hardware to use the key
* for multicast frame decryption.
*/
- if (mac[0] & 0x01)
+ if (is_multicast_ether_addr(mac))
unicast_flag = 0;
macLo = get_unaligned_le32(mac);
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 8dbd115a393c..2bd1163177f0 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -19,9 +19,8 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/rpmsg.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/soc/qcom/wcnss_ctrl.h>
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 237cbd5c5060..f29ac6de7139 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -666,7 +666,7 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
struct wil_tid_crypto_rx *c = mc ? &s->group_crypto_rx :
&s->tid_crypto_rx[tid];
struct wil_tid_crypto_rx_single *cc = &c->key_id[key_id];
- const u8 *pn = (u8 *)&d->mac.pn_15_0;
+ const u8 *pn = (u8 *)&d->mac.pn;
if (!cc->key_set) {
wil_err_ratelimited(wil,
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 1ae1bec1b97f..689f68d89a44 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -343,8 +343,10 @@ struct vring_rx_mac {
u32 d0;
u32 d1;
u16 w4;
- u16 pn_15_0;
- u32 pn_47_16;
+ struct_group_attr(pn, __packed,
+ u16 pn_15_0;
+ u32 pn_47_16;
+ );
} __packed;
/* Rx descriptor - DMA part
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c
index 201c8c35e0c9..1ba1f21ebea2 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.c
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c
@@ -548,7 +548,7 @@ static int wil_rx_crypto_check_edma(struct wil6210_priv *wil,
s = &wil->sta[cid];
c = mc ? &s->group_crypto_rx : &s->tid_crypto_rx[tid];
cc = &c->key_id[key_id];
- pn = (u8 *)&st->ext.pn_15_0;
+ pn = (u8 *)&st->ext.pn;
if (!cc->key_set) {
wil_err_ratelimited(wil,
diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h
index c736f7413a35..ee90e225bb05 100644
--- a/drivers/net/wireless/ath/wil6210/txrx_edma.h
+++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h
@@ -330,8 +330,10 @@ struct wil_rx_status_extension {
u32 d0;
u32 d1;
__le16 seq_num; /* only lower 12 bits */
- u16 pn_15_0;
- u32 pn_47_16;
+ struct_group_attr(pn, __packed,
+ u16 pn_15_0;
+ u32 pn_47_16;
+ );
} __packed;
struct wil_rx_status_extended {
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 009bca34ece3..447b51cff8f9 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -10,7 +10,7 @@
* Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
* Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net>
*
- * This file is part of the Berlios driver for WLAN USB devices based on the
+ * This file is part of the Berlios driver for USB WLAN devices based on the
* Atmel AT76C503A/505/505A.
*
* Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
@@ -143,7 +143,7 @@ static const struct usb_device_id dev_table[] = {
{ USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
/* Dynalink/Askey WLL013 (intersil) */
{ USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },
- /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
+ /* EZ connect 11Mpbs USB Wireless Adapter SMC2662W v1 */
{ USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
/* BenQ AWL300 */
{ USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },
@@ -195,7 +195,7 @@ static const struct usb_device_id dev_table[] = {
{ USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },
/* 3Com 3CRSHEW696 */
{ USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },
- /* Siemens Santis ADSL WLAN USB adapter WLL 013 */
+ /* Siemens Santis ADSL USB WLAN adapter WLL 013 */
{ USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },
/* Belkin F5D6050, version 2 */
{ USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },
@@ -238,7 +238,7 @@ static const struct usb_device_id dev_table[] = {
{ USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },
/* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
{ USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },
- /* Corega WLAN USB Stick 11 */
+ /* Corega USB WLAN Stick 11 */
{ USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
/* Microstar MSI Box MS6978 */
{ USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.h
index 2d08c155c23b..90b6e3982d2c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.h
@@ -145,14 +145,6 @@ struct si_pub {
struct pci_dev;
-struct gpioh_item {
- void *arg;
- bool level;
- void (*handler) (u32 stat, void *arg);
- u32 event;
- struct gpioh_item *next;
-};
-
/* misc si info needed by some of the routines */
struct si_info {
struct si_pub pub; /* back plane public state (must be first) */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
index e24228e60027..e859075db716 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/ampdu.c
@@ -476,11 +476,9 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
void
brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
- u8 ba_wsize, /* negotiated ba window size (in pdu) */
uint max_rx_ampdu_bytes) /* from ht_cap in beacon */
{
struct scb_ampdu *scb_ampdu;
- struct scb_ampdu_tid_ini *ini;
struct ampdu_info *ampdu = wlc->ampdu;
struct scb *scb = &wlc->pri_scb;
scb_ampdu = &scb->scb_ampdu;
@@ -491,10 +489,6 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
return;
}
- ini = &scb_ampdu->ini[tid];
- ini->tid = tid;
- ini->scb = scb_ampdu->scb;
- ini->ba_wsize = ba_wsize;
scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
index 0bd4e679a359..543e93ec49d2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
@@ -810,7 +810,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
brcms_c_init_scb(scb);
wl->pub->global_ampdu = &(scb->scb_ampdu);
- wl->pub->global_ampdu->scb = scb;
wl->pub->global_ampdu->max_pdu = 16;
/*
@@ -831,7 +830,6 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta = params->sta;
enum ieee80211_ampdu_mlme_action action = params->action;
u16 tid = params->tid;
- u8 buf_size = params->buf_size;
if (WARN_ON(scb->magic != SCB_MAGIC))
return -EIDRM;
@@ -863,11 +861,11 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
/*
* BA window size from ADDBA response ('buf_size') defines how
* many outstanding MPDUs are allowed for the BA stream by
- * recipient and traffic class. 'ampdu_factor' gives maximum
- * AMPDU size.
+ * recipient and traffic class (this is actually unused by the
+ * rest of the driver). 'ampdu_factor' gives maximum AMPDU size.
*/
spin_lock_bh(&wl->lock);
- brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size,
+ brcms_c_ampdu_tx_operational(wl->wlc, tid,
(1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->deflink.ht_cap.ampdu_factor)) - 1);
spin_unlock_bh(&wl->lock);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
index 11b33e78127c..b3663c5ef382 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
@@ -3147,10 +3147,8 @@ void brcms_c_init_scb(struct scb *scb)
scb->flags = SCB_WMECAP | SCB_HTCAP;
for (i = 0; i < NUMPRIO; i++) {
scb->seqnum[i] = 0;
- scb->seqctl[i] = 0xFFFF;
}
- scb->seqctl_nonqos = 0xFFFF;
scb->magic = SCB_MAGIC;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h
index 2e6a3d454ee8..1efc92fd1671 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h
@@ -141,11 +141,6 @@ struct tx_power {
u8 target[WL_TX_POWER_RATES];
};
-struct tx_inst_power {
- u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */
- u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */
-};
-
struct brcms_chanvec {
u8 vec[MAXCHANNEL / NBBY];
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/pub.h
index 4da38cb4f318..bfc63b2f0537 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/pub.h
@@ -297,7 +297,7 @@ struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc);
void brcms_c_ampdu_flush(struct brcms_c_info *wlc, struct ieee80211_sta *sta,
u16 tid);
void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
- u8 ba_wsize, uint max_rx_ampdu_bytes);
+ uint max_rx_ampdu_bytes);
int brcms_c_module_register(struct brcms_pub *pub, const char *name,
struct brcms_info *hdl,
int (*down_fn)(void *handle));
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/scb.h
index 3a3d73699f83..d65561227da0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/scb.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/scb.h
@@ -36,19 +36,13 @@
/* structure to store per-tid state for the ampdu initiator */
struct scb_ampdu_tid_ini {
- u8 tid; /* initiator tid for easy lookup */
/* tx retry count; indexed by seq modulo */
u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
- struct scb *scb; /* backptr for easy lookup */
- u8 ba_wsize; /* negotiated ba window size (in pdu) */
};
struct scb_ampdu {
- struct scb *scb; /* back pointer for easy reference */
- u8 mpdu_density; /* mpdu density */
u8 max_pdu; /* max pdus allowed in ampdu */
u8 release; /* # of mpdus released at a time */
- u16 min_len; /* min mpdu len to support the density */
u32 max_rx_ampdu_bytes; /* max ampdu rcv length; 8k, 16k, 32k, 64k */
/*
@@ -64,15 +58,7 @@ struct scb_ampdu {
struct scb {
u32 magic;
u32 flags; /* various bit flags as defined below */
- u32 flags2; /* various bit flags2 as defined below */
- u8 state; /* current state bitfield of auth/assoc process */
- u8 ea[ETH_ALEN]; /* station address */
- uint fragresid[NUMPRIO];/* #bytes unused in frag buffer per prio */
-
u16 seqctl[NUMPRIO]; /* seqctl of last received frame (for dups) */
- /* seqctl of last received frame (for dups) for non-QoS data and
- * management */
- u16 seqctl_nonqos;
u16 seqnum[NUMPRIO];/* WME: driver maintained sw seqnum per priority */
struct scb_ampdu scb_ampdu; /* AMPDU state including per tid info */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/types.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/types.h
index 2b0df07ced74..12a0df5b4e98 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/types.h
@@ -288,15 +288,6 @@ struct tx_status;
struct d11rxhdr;
struct txpwr_limits;
-/* iovar structure */
-struct brcmu_iovar {
- const char *name; /* name for lookup and display */
- u16 varid; /* id for switch */
- u16 flags; /* driver-specific flag bits */
- u16 type; /* base type of argument */
- u16 minlen; /* min length for buffer vars */
-};
-
/* brcm_msg_level is a bit vector with defs in defs.h */
extern u32 brcm_msg_level;
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index dfe0f74369e6..820100cac491 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -1176,23 +1176,20 @@ static ssize_t debug_level_show(struct device_driver *d, char *buf)
static ssize_t debug_level_store(struct device_driver *d, const char *buf,
size_t count)
{
- char *p = (char *)buf;
- u32 val;
+ unsigned long val;
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- p++;
- if (p[0] == 'x' || p[0] == 'X')
- p++;
- val = simple_strtoul(p, &p, 16);
- } else
- val = simple_strtoul(p, &p, 10);
- if (p == buf)
+ int result = kstrtoul(buf, 0, &val);
+
+ if (result == -EINVAL)
printk(KERN_INFO DRV_NAME
": %s is not in hex or decimal form.\n", buf);
+ else if (result == -ERANGE)
+ printk(KERN_INFO DRV_NAME
+ ": %s has overflowed.\n", buf);
else
ipw_debug_level = val;
- return strnlen(buf, count);
+ return count;
}
static DRIVER_ATTR_RW(debug_level);
@@ -1461,25 +1458,13 @@ static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
{
struct ipw_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
- char buffer[] = "00000000";
- unsigned long len =
- (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
- unsigned long val;
- char *p = buffer;
IPW_DEBUG_INFO("enter\n");
- strncpy(buffer, buf, len);
- buffer[len] = 0;
+ unsigned long val;
+ int result = kstrtoul(buf, 0, &val);
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- p++;
- if (p[0] == 'x' || p[0] == 'X')
- p++;
- val = simple_strtoul(p, &p, 16);
- } else
- val = simple_strtoul(p, &p, 10);
- if (p == buffer) {
+ if (result == -EINVAL || result == -ERANGE) {
IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
} else {
priv->ieee->scan_age = val;
@@ -1487,7 +1472,7 @@ static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
}
IPW_DEBUG_INFO("exit\n");
- return len;
+ return count;
}
static DEVICE_ATTR_RW(scan_age);
diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig
index b20409f8c13a..20971304fdef 100644
--- a/drivers/net/wireless/intel/iwlwifi/Kconfig
+++ b/drivers/net/wireless/intel/iwlwifi/Kconfig
@@ -66,6 +66,7 @@ config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support"
select WANT_DEV_COREDUMP
depends on MAC80211
+ depends on PTP_1588_CLOCK_OPTIONAL
help
This is the driver that supports the MVM firmware. The list
of the devices that use this firmware is available here:
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index dfe8357036eb..b26f90e52256 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -69,6 +69,11 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
},
},
+ { .ident = "RAZER",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
+ },
+ },
{}
};
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
index 8fef38139bf6..90ce8d9b6ad3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -30,6 +30,11 @@ enum iwl_debug_cmds {
*/
HOST_EVENT_CFG = 0x3,
/**
+ * @INVALID_WR_PTR_CMD: invalid write pointer, set in the TFD
+ * when it's not in use
+ */
+ INVALID_WR_PTR_CMD = 0x6,
+ /**
* @DBGC_SUSPEND_RESUME:
* DBGC suspend/resume commad. Uses a single dword as data:
* 0 - resume DBGC recording
@@ -377,7 +382,7 @@ struct iwl_buf_alloc_cmd {
#define DRAM_INFO_SECOND_MAGIC_WORD 0x89ABCDEF
/**
- * struct iwL_dram_info - DRAM fragments allocation struct
+ * struct iwl_dram_info - DRAM fragments allocation struct
*
* Driver will fill in the first 1K(+) of the pointed DRAM fragment
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
index 5876f917e536..8f107ceec407 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -182,8 +182,7 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu
base = fwrt->fw->inst_errlog_ptr;
}
- if ((fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && !base) ||
- (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ && base < 0x400000)) {
+ if (!base) {
IWL_ERR(fwrt,
"Not valid error log pointer 0x%08X for %s uCode\n",
base,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
index 4e4a60ddf9b2..41ab5a6e2dd3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h
@@ -565,6 +565,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
#define RX_QUEUE_MASK 255
#define RX_QUEUE_SIZE_LOG 8
+#define IWL_DEFAULT_RX_QUEUE 0
+
/**
* struct iwl_rb_status - reserve buffer status
* host memory mapped FH registers
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 8c23f57f5c89..31176897b746 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -990,6 +990,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
case IWL_CFG_RF_TYPE_GF:
case IWL_CFG_RF_TYPE_MR:
case IWL_CFG_RF_TYPE_MS:
+ case IWL_CFG_RF_TYPE_FM:
+ case IWL_CFG_RF_TYPE_WH:
iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
if (!is_ap)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index d02943d0ea62..3b6b0e03037f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -1069,6 +1069,7 @@ struct iwl_trans_txqs {
* @mbx_addr_1_step: step address data 1
* @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*),
* only valid for discrete (not integrated) NICs
+ * @invalid_tx_cmd: invalid TX command buffer
*/
struct iwl_trans {
bool csme_own;
@@ -1133,6 +1134,8 @@ struct iwl_trans {
u8 pcie_link_speed;
+ struct iwl_dma_ptr invalid_tx_cmd;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[] __aligned(sizeof(void *));
@@ -1490,7 +1493,7 @@ static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr)
{
u32 value;
- if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1)))
+ if (iwl_trans_read_mem(trans, addr, &value, 1))
return 0xa5a5a5a5;
return value;
diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c
index 54445f39fd55..1dd9106c6513 100644
--- a/drivers/net/wireless/intel/iwlwifi/mei/main.c
+++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2021-2022 Intel Corporation
+ * Copyright (C) 2021-2023 Intel Corporation
*/
#include <linux/etherdevice.h>
@@ -774,9 +774,13 @@ static void iwl_mei_set_init_conf(struct iwl_mei *mei)
iwl_mei_send_sap_msg_payload(mei->cldev, &sar_msg.hdr);
}
- ether_addr_copy(nic_info_msg.mac_address, iwl_mei_cache.mac_address);
- ether_addr_copy(nic_info_msg.nvm_address, iwl_mei_cache.nvm_address);
- iwl_mei_send_sap_msg_payload(mei->cldev, &nic_info_msg.hdr);
+ if (is_valid_ether_addr(iwl_mei_cache.mac_address)) {
+ ether_addr_copy(nic_info_msg.mac_address,
+ iwl_mei_cache.mac_address);
+ ether_addr_copy(nic_info_msg.nvm_address,
+ iwl_mei_cache.nvm_address);
+ iwl_mei_send_sap_msg_payload(mei->cldev, &nic_info_msg.hdr);
+ }
iwl_mei_send_sap_msg_payload(mei->cldev, &rfkill_msg.hdr);
}
@@ -1532,7 +1536,7 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1561,7 +1565,7 @@ void iwl_mei_host_disassociated(void)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1597,7 +1601,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1626,7 +1630,7 @@ void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1654,7 +1658,7 @@ void iwl_mei_set_country_code(u16 mcc)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@@ -1680,7 +1684,7 @@ void iwl_mei_set_power_limit(const __le16 *power_limit)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
- if (!mei && !mei->amt_enabled)
+ if (!mei || !mei->amt_enabled)
goto out;
memcpy(msg.sar_chain_info_table, power_limit, sizeof(msg.sar_chain_info_table));
@@ -1832,7 +1836,9 @@ void iwl_mei_unregister_complete(void)
struct iwl_mei *mei =
mei_cldev_get_drvdata(iwl_mei_global_cldev);
- iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WIFIDR_DOWN);
+ if (mei->amt_enabled)
+ iwl_mei_send_sap_msg(mei->cldev,
+ SAP_MSG_NOTIF_WIFIDR_DOWN);
mei->got_ownership = false;
}
@@ -2070,33 +2076,29 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
mutex_lock(&iwl_mei_mutex);
- if (mei->amt_enabled) {
- /*
- * Tell CSME that we are going down so that it won't access the
- * memory anymore, make sure this message goes through immediately.
- */
- mei->csa_throttled = false;
- iwl_mei_send_sap_msg(mei->cldev,
- SAP_MSG_NOTIF_HOST_GOES_DOWN);
-
- for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
- if (!iwl_mei_host_to_me_data_pending(mei))
- break;
+ /* Tell CSME that we are going down so that it won't access the
+ * memory anymore, make sure this message goes through immediately.
+ */
+ mei->csa_throttled = false;
+ iwl_mei_send_sap_msg(mei->cldev,
+ SAP_MSG_NOTIF_HOST_GOES_DOWN);
- msleep(20);
- }
+ for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
+ if (!iwl_mei_host_to_me_data_pending(mei))
+ break;
- /*
- * If we couldn't make sure that CSME saw the HOST_GOES_DOWN
- * message, it means that it will probably keep reading memory
- * that we are going to unmap and free, expect IOMMU error
- * messages.
- */
- if (i == SEND_SAP_MAX_WAIT_ITERATION)
- dev_err(&mei->cldev->dev,
- "Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
+ msleep(20);
}
+ /* If we couldn't make sure that CSME saw the HOST_GOES_DOWN
+ * message, it means that it will probably keep reading memory
+ * that we are going to unmap and free, expect IOMMU error
+ * messages.
+ */
+ if (i == SEND_SAP_MAX_WAIT_ITERATION)
+ dev_err(&mei->cldev->dev,
+ "Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
+
mutex_unlock(&iwl_mei_mutex);
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index ce7905faa08f..5918c1f2b10c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -315,8 +315,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, STA_MMPDU_TXQ);
/* Set this early since we need to have it for the check below */
- if (mvm->mld_api_is_used &&
- mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+ if (mvm->mld_api_is_used && mvm->nvm_data->sku_cap_11be_enable &&
+ !iwlwifi_mod_params.disable_11ax &&
+ !iwlwifi_mod_params.disable_11be)
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
/* With MLD FW API, it tracks timing by itself,
@@ -5604,9 +5605,6 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return;
}
- if (vif->type != NL80211_IFTYPE_STATION)
- return;
-
/* Make sure we're done with the deferred traffic before flushing */
flush_work(&mvm->add_stream_wk);
@@ -5630,9 +5628,6 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ap_sta_done = true;
}
- /* make sure only TDLS peers or the AP are flushed */
- WARN_ON_ONCE(sta != mvmvif->ap_sta && !sta->tdls);
-
if (drop) {
if (iwl_mvm_flush_sta(mvm, mvmsta, false))
IWL_ERR(mvm, "flush request fail\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 73c1fb3c0c5e..bc83d2ba55c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -1132,12 +1132,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
else
sd_reg_ver_addr = SD_REG_VER;
- if (!iwl_trans_grab_nic_access(iwl_trans)) {
- IWL_ERR(iwl_trans, "Failed to grab nic access before reading crf id\n");
- ret = -EIO;
- goto out;
- }
-
/* Enable access to peripheral registers */
val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG);
val |= ENABLE_WFPM;
@@ -1157,9 +1151,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
iwl_trans->hw_crf_id, iwl_trans->hw_cnv_id,
iwl_trans->hw_wfpm_id);
- iwl_trans_release_nic_access(iwl_trans);
-
-out:
return ret;
}
@@ -1351,6 +1342,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_free_trans;
if (iwl_trans_grab_nic_access(iwl_trans)) {
+ get_crf_id(iwl_trans);
/* all good */
iwl_trans_release_nic_access(iwl_trans);
} else {
@@ -1360,7 +1352,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
iwl_trans->hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID);
- get_crf_id(iwl_trans);
/*
* The RF_ID is set to zero in blank OTP so read version to
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 0adcf0e13e85..0f6493dab8cb 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2003-2015, 2018-2022 Intel Corporation
+ * Copyright (C) 2003-2015, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -315,7 +315,6 @@ enum iwl_pcie_imr_status {
* @ucode_write_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load
* @cmd_queue - command queue number
- * @def_rx_queue - default rx queue number
* @rx_buf_size: Rx buffer size
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @rx_page_order: page order for receive buffer size
@@ -398,7 +397,6 @@ struct iwl_trans_pcie {
wait_queue_head_t ucode_write_waitq;
wait_queue_head_t sx_waitq;
- u8 def_rx_queue;
u8 n_no_reclaim_cmds;
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
u16 num_rx_bufs;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index f87b28edc267..4614acee9f7b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1373,7 +1373,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
}
}
- if (rxq->id == trans_pcie->def_rx_queue)
+ if (rxq->id == IWL_DEFAULT_RX_QUEUE)
iwl_op_mode_rx(trans->op_mode, &rxq->napi,
&rxcb);
else
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 3e988da44973..198933f853c5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -2018,6 +2018,30 @@ void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions
memset(desc_dram, 0, sizeof(*desc_dram));
}
+static void iwl_pcie_free_invalid_tx_cmd(struct iwl_trans *trans)
+{
+ iwl_pcie_free_dma_ptr(trans, &trans->invalid_tx_cmd);
+}
+
+static int iwl_pcie_alloc_invalid_tx_cmd(struct iwl_trans *trans)
+{
+ struct iwl_cmd_header_wide bad_cmd = {
+ .cmd = INVALID_WR_PTR_CMD,
+ .group_id = DEBUG_GROUP,
+ .sequence = cpu_to_le16(0xffff),
+ .length = cpu_to_le16(0),
+ .version = 0,
+ };
+ int ret;
+
+ ret = iwl_pcie_alloc_dma_ptr(trans, &trans->invalid_tx_cmd,
+ sizeof(bad_cmd));
+ if (ret)
+ return ret;
+ memcpy(trans->invalid_tx_cmd.addr, &bad_cmd, sizeof(bad_cmd));
+ return 0;
+}
+
void iwl_trans_pcie_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -2048,6 +2072,8 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iwl_pcie_free_ict(trans);
}
+ iwl_pcie_free_invalid_tx_cmd(trans);
+
iwl_pcie_free_fw_monitor(trans);
iwl_trans_pcie_free_pnvm_dram_regions(&trans_pcie->pnvm_data,
@@ -3617,8 +3643,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
PCIE_LINK_STATE_CLKPM);
}
- trans_pcie->def_rx_queue = 0;
-
pci_set_master(pdev);
addr_size = trans->txqs.tfd.addr_size;
@@ -3686,6 +3710,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
init_waitqueue_head(&trans_pcie->sx_waitq);
+ ret = iwl_pcie_alloc_invalid_tx_cmd(trans);
+ if (ret)
+ goto out_no_pci;
if (trans_pcie->msix_enabled) {
ret = iwl_pcie_init_msix_handler(pdev, trans_pcie);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 790e5b124740..2f39b639c43f 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -132,22 +132,6 @@ void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans)
}
}
-static inline void iwl_pcie_tfd_set_tb(struct iwl_trans *trans, void *tfd,
- u8 idx, dma_addr_t addr, u16 len)
-{
- struct iwl_tfd *tfd_fh = (void *)tfd;
- struct iwl_tfd_tb *tb = &tfd_fh->tbs[idx];
-
- u16 hi_n_len = len << 4;
-
- put_unaligned_le32(addr, &tb->lo);
- hi_n_len |= iwl_get_dma_hi_addr(addr);
-
- tb->hi_n_len = cpu_to_le16(hi_n_len);
-
- tfd_fh->num_tbs = idx + 1;
-}
-
static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
dma_addr_t addr, u16 len, bool reset)
{
@@ -172,7 +156,7 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
"Unaligned address = %llx\n", (unsigned long long)addr))
return -EINVAL;
- iwl_pcie_tfd_set_tb(trans, tfd, num_tbs, addr, len);
+ iwl_pcie_gen1_tfd_set_tb(trans, tfd, num_tbs, addr, len);
return num_tbs;
}
@@ -1203,7 +1187,11 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
group_id = cmd->hdr.group_id;
cmd_id = WIDE_ID(group_id, cmd->hdr.cmd);
- iwl_txq_gen1_tfd_unmap(trans, meta, txq, index);
+ if (trans->trans_cfg->gen2)
+ iwl_txq_gen2_tfd_unmap(trans, meta,
+ iwl_txq_get_tfd(trans, txq, index));
+ else
+ iwl_txq_gen1_tfd_unmap(trans, meta, txq, index);
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c
index 5bb3cc3367c9..340240b8954f 100644
--- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c
@@ -10,6 +10,7 @@
#include "fw/api/commands.h"
#include "fw/api/tx.h"
#include "fw/api/datapath.h"
+#include "fw/api/debug.h"
#include "queue/tx.h"
#include "iwl-fh.h"
#include "iwl-scd.h"
@@ -84,6 +85,50 @@ static u8 iwl_txq_gen2_get_num_tbs(struct iwl_trans *trans,
return le16_to_cpu(tfd->num_tbs) & 0x1f;
}
+int iwl_txq_gen2_set_tb(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd,
+ dma_addr_t addr, u16 len)
+{
+ int idx = iwl_txq_gen2_get_num_tbs(trans, tfd);
+ struct iwl_tfh_tb *tb;
+
+ /* Only WARN here so we know about the issue, but we mess up our
+ * unmap path because not every place currently checks for errors
+ * returned from this function - it can only return an error if
+ * there's no more space, and so when we know there is enough we
+ * don't always check ...
+ */
+ WARN(iwl_txq_crosses_4g_boundary(addr, len),
+ "possible DMA problem with iova:0x%llx, len:%d\n",
+ (unsigned long long)addr, len);
+
+ if (WARN_ON(idx >= IWL_TFH_NUM_TBS))
+ return -EINVAL;
+ tb = &tfd->tbs[idx];
+
+ /* Each TFD can point to a maximum max_tbs Tx buffers */
+ if (le16_to_cpu(tfd->num_tbs) >= trans->txqs.tfd.max_tbs) {
+ IWL_ERR(trans, "Error can not send more than %d chunks\n",
+ trans->txqs.tfd.max_tbs);
+ return -EINVAL;
+ }
+
+ put_unaligned_le64(addr, &tb->addr);
+ tb->tb_len = cpu_to_le16(len);
+
+ tfd->num_tbs = cpu_to_le16(idx + 1);
+
+ return idx;
+}
+
+static void iwl_txq_set_tfd_invalid_gen2(struct iwl_trans *trans,
+ struct iwl_tfh_tfd *tfd)
+{
+ tfd->num_tbs = 0;
+
+ iwl_txq_gen2_set_tb(trans, tfd, trans->invalid_tx_cmd.dma,
+ trans->invalid_tx_cmd.size);
+}
+
void iwl_txq_gen2_tfd_unmap(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
struct iwl_tfh_tfd *tfd)
{
@@ -111,7 +156,7 @@ void iwl_txq_gen2_tfd_unmap(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
DMA_TO_DEVICE);
}
- tfd->num_tbs = 0;
+ iwl_txq_set_tfd_invalid_gen2(trans, tfd);
}
void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
@@ -142,42 +187,6 @@ void iwl_txq_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
}
}
-int iwl_txq_gen2_set_tb(struct iwl_trans *trans, struct iwl_tfh_tfd *tfd,
- dma_addr_t addr, u16 len)
-{
- int idx = iwl_txq_gen2_get_num_tbs(trans, tfd);
- struct iwl_tfh_tb *tb;
-
- /*
- * Only WARN here so we know about the issue, but we mess up our
- * unmap path because not every place currently checks for errors
- * returned from this function - it can only return an error if
- * there's no more space, and so when we know there is enough we
- * don't always check ...
- */
- WARN(iwl_txq_crosses_4g_boundary(addr, len),
- "possible DMA problem with iova:0x%llx, len:%d\n",
- (unsigned long long)addr, len);
-
- if (WARN_ON(idx >= IWL_TFH_NUM_TBS))
- return -EINVAL;
- tb = &tfd->tbs[idx];
-
- /* Each TFD can point to a maximum max_tbs Tx buffers */
- if (le16_to_cpu(tfd->num_tbs) >= trans->txqs.tfd.max_tbs) {
- IWL_ERR(trans, "Error can not send more than %d chunks\n",
- trans->txqs.tfd.max_tbs);
- return -EINVAL;
- }
-
- put_unaligned_le64(addr, &tb->addr);
- tb->tb_len = cpu_to_le16(len);
-
- tfd->num_tbs = cpu_to_le16(idx + 1);
-
- return idx;
-}
-
static struct page *get_workaround_page(struct iwl_trans *trans,
struct sk_buff *skb)
{
@@ -1026,11 +1035,21 @@ static void iwl_txq_stuck_timer(struct timer_list *t)
iwl_force_nmi(trans);
}
+static void iwl_txq_set_tfd_invalid_gen1(struct iwl_trans *trans,
+ struct iwl_tfd *tfd)
+{
+ tfd->num_tbs = 0;
+
+ iwl_pcie_gen1_tfd_set_tb(trans, tfd, 0, trans->invalid_tx_cmd.dma,
+ trans->invalid_tx_cmd.size);
+}
+
int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num,
bool cmd_queue)
{
- size_t tfd_sz = trans->txqs.tfd.size *
- trans->trans_cfg->base_params->max_tfd_queue_size;
+ size_t num_entries = trans->trans_cfg->gen2 ?
+ slots_num : trans->trans_cfg->base_params->max_tfd_queue_size;
+ size_t tfd_sz;
size_t tb0_buf_sz;
int i;
@@ -1040,8 +1059,7 @@ int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num,
if (WARN_ON(txq->entries || txq->tfds))
return -EINVAL;
- if (trans->trans_cfg->gen2)
- tfd_sz = trans->txqs.tfd.size * slots_num;
+ tfd_sz = trans->txqs.tfd.size * num_entries;
timer_setup(&txq->stuck_timer, iwl_txq_stuck_timer, 0);
txq->trans = trans;
@@ -1081,6 +1099,15 @@ int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num,
if (!txq->first_tb_bufs)
goto err_free_tfds;
+ for (i = 0; i < num_entries; i++) {
+ void *tfd = iwl_txq_get_tfd(trans, txq, i);
+
+ if (trans->trans_cfg->gen2)
+ iwl_txq_set_tfd_invalid_gen2(trans, tfd);
+ else
+ iwl_txq_set_tfd_invalid_gen1(trans, tfd);
+ }
+
return 0;
err_free_tfds:
dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->dma_addr);
@@ -1340,22 +1367,12 @@ error:
}
static inline dma_addr_t iwl_txq_gen1_tfd_tb_get_addr(struct iwl_trans *trans,
- void *_tfd, u8 idx)
+ struct iwl_tfd *tfd, u8 idx)
{
- struct iwl_tfd *tfd;
- struct iwl_tfd_tb *tb;
+ struct iwl_tfd_tb *tb = &tfd->tbs[idx];
dma_addr_t addr;
dma_addr_t hi_len;
- if (trans->trans_cfg->gen2) {
- struct iwl_tfh_tfd *tfh_tfd = _tfd;
- struct iwl_tfh_tb *tfh_tb = &tfh_tfd->tbs[idx];
-
- return (dma_addr_t)(le64_to_cpu(tfh_tb->addr));
- }
-
- tfd = _tfd;
- tb = &tfd->tbs[idx];
addr = get_unaligned_le32(&tb->lo);
if (sizeof(dma_addr_t) <= sizeof(u32))
@@ -1376,7 +1393,7 @@ void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans,
struct iwl_txq *txq, int index)
{
int i, num_tbs;
- void *tfd = iwl_txq_get_tfd(trans, txq, index);
+ struct iwl_tfd *tfd = iwl_txq_get_tfd(trans, txq, index);
/* Sanity check on number of chunks */
num_tbs = iwl_txq_gen1_tfd_get_num_tbs(trans, tfd);
@@ -1408,15 +1425,7 @@ void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans,
meta->tbs = 0;
- if (trans->trans_cfg->gen2) {
- struct iwl_tfh_tfd *tfd_fh = (void *)tfd;
-
- tfd_fh->num_tbs = 0;
- } else {
- struct iwl_tfd *tfd_fh = (void *)tfd;
-
- tfd_fh->num_tbs = 0;
- }
+ iwl_txq_set_tfd_invalid_gen1(trans, tfd);
}
#define IWL_TX_CRC_SIZE 4
@@ -1520,7 +1529,12 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
/* We have only q->n_window txq->entries, but we use
* TFD_QUEUE_SIZE_MAX tfds
*/
- iwl_txq_gen1_tfd_unmap(trans, &txq->entries[idx].meta, txq, rd_ptr);
+ if (trans->trans_cfg->gen2)
+ iwl_txq_gen2_tfd_unmap(trans, &txq->entries[idx].meta,
+ iwl_txq_get_tfd(trans, txq, rd_ptr));
+ else
+ iwl_txq_gen1_tfd_unmap(trans, &txq->entries[idx].meta,
+ txq, rd_ptr);
/* free SKB */
skb = txq->entries[idx].skb;
diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.h b/drivers/net/wireless/intel/iwlwifi/queue/tx.h
index 1e4a24ab9bab..b7d3808588bf 100644
--- a/drivers/net/wireless/intel/iwlwifi/queue/tx.h
+++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.h
@@ -131,17 +131,8 @@ struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len,
struct sk_buff *skb);
#endif
static inline u8 iwl_txq_gen1_tfd_get_num_tbs(struct iwl_trans *trans,
- void *_tfd)
+ struct iwl_tfd *tfd)
{
- struct iwl_tfd *tfd;
-
- if (trans->trans_cfg->gen2) {
- struct iwl_tfh_tfd *tfh_tfd = _tfd;
-
- return le16_to_cpu(tfh_tfd->num_tbs) & 0x1f;
- }
-
- tfd = (struct iwl_tfd *)_tfd;
return tfd->num_tbs & 0x1f;
}
@@ -164,6 +155,21 @@ static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans,
return le16_to_cpu(tb->hi_n_len) >> 4;
}
+static inline void iwl_pcie_gen1_tfd_set_tb(struct iwl_trans *trans,
+ struct iwl_tfd *tfd,
+ u8 idx, dma_addr_t addr, u16 len)
+{
+ struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+ u16 hi_n_len = len << 4;
+
+ put_unaligned_le32(addr, &tb->lo);
+ hi_n_len |= iwl_get_dma_hi_addr(addr);
+
+ tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+ tfd->num_tbs = idx + 1;
+}
+
void iwl_txq_gen1_tfd_unmap(struct iwl_trans *trans,
struct iwl_cmd_meta *meta,
struct iwl_txq *txq, int index);
diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c
index a890bfa0d5cc..45ac00fdafa5 100644
--- a/drivers/net/wireless/intersil/orinoco/airport.c
+++ b/drivers/net/wireless/intersil/orinoco/airport.c
@@ -18,7 +18,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <asm/pmac_feature.h>
#include "orinoco.h"
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
index dd31929261ab..866e0230df25 100644
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
@@ -129,18 +129,18 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
#define USB_AVAYA8_VENDOR_ID 0x0D98
#define USB_AVAYAE_VENDOR_ID 0x0D9E
-#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya Wireless USB Card */
+#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */
#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */
-#define USB_AGERE_MODEL0801_ID 0x1000 /* Wireless USB Card Model 0801 */
-#define USB_AGERE_MODEL0802_ID 0x1001 /* Wireless USB Card Model 0802 */
-#define USB_AGERE_REBRANDED_ID 0x047A /* WLAN USB Card */
+#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */
#define USB_ELSA_VENDOR_ID 0x05CC
#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */
#define USB_LEGEND_VENDOR_ID 0x0E7C
-#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet WLAN USB Card */
+#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */
#define USB_SAMSUNG_VENDOR_ID 0x04E8
#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
@@ -154,7 +154,7 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */
#define USB_2WIRE_VENDOR_ID 0x1630
-#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire Wireless USB adapter */
+#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */
#define EZUSB_REQUEST_FW_TRANS 0xA0
diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c
index 712038d46bdb..e7fea7ded6d5 100644
--- a/drivers/net/wireless/legacy/rndis_wlan.c
+++ b/drivers/net/wireless/legacy/rndis_wlan.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Driver for RNDIS based wireless USB devices.
+ * Driver for RNDIS based USB wireless devices.
*
* Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
* Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@iki.fi>
diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c
index a63c5e622ee3..524034699972 100644
--- a/drivers/net/wireless/marvell/libertas/if_sdio.c
+++ b/drivers/net/wireless/marvell/libertas/if_sdio.c
@@ -101,7 +101,7 @@ MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
struct if_sdio_packet {
- struct if_sdio_packet *next;
+ struct list_head list;
u16 nb;
u8 buffer[] __aligned(4);
};
@@ -119,10 +119,11 @@ struct if_sdio_card {
u8 buffer[65536] __attribute__((aligned(4)));
spinlock_t lock;
- struct if_sdio_packet *packets;
+ struct list_head packets;
struct workqueue_struct *workqueue;
struct work_struct packet_worker;
+ struct work_struct reset_worker;
u8 rx_unit;
};
@@ -404,9 +405,10 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
while (1) {
spin_lock_irqsave(&card->lock, flags);
- packet = card->packets;
+ packet = list_first_entry_or_null(&card->packets,
+ struct if_sdio_packet, list);
if (packet)
- card->packets = packet->next;
+ list_del(&packet->list);
spin_unlock_irqrestore(&card->lock, flags);
if (!packet)
@@ -909,7 +911,7 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
{
int ret;
struct if_sdio_card *card;
- struct if_sdio_packet *packet, *cur;
+ struct if_sdio_packet *packet;
u16 size;
unsigned long flags;
@@ -934,7 +936,6 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
goto out;
}
- packet->next = NULL;
packet->nb = size;
/*
@@ -949,14 +950,7 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
spin_lock_irqsave(&card->lock, flags);
- if (!card->packets)
- card->packets = packet;
- else {
- cur = card->packets;
- while (cur->next)
- cur = cur->next;
- cur->next = packet;
- }
+ list_add_tail(&packet->list, &card->packets);
switch (type) {
case MVMS_CMD:
@@ -1029,10 +1023,19 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
}
-static struct mmc_host *reset_host;
-
static void if_sdio_reset_card_worker(struct work_struct *work)
{
+ int ret;
+ const char *name;
+ struct device *dev;
+ struct if_sdio_card *card;
+ struct mmc_host *reset_host;
+
+ card = container_of(work, struct if_sdio_card, reset_worker);
+ reset_host = card->func->card->host;
+ name = card->priv->dev->name;
+ dev = &card->func->dev;
+
/*
* The actual reset operation must be run outside of lbs_thread. This
* is because mmc_remove_host() will cause the device to be instantly
@@ -1043,21 +1046,19 @@ static void if_sdio_reset_card_worker(struct work_struct *work)
* instance for that reason.
*/
- pr_info("Resetting card...");
+ dev_info(dev, "resetting card %s...", name);
mmc_remove_host(reset_host);
- mmc_add_host(reset_host);
+ ret = mmc_add_host(reset_host);
+ if (ret)
+ dev_err(dev, "%s: can't add mmc host, error %d\n", name, ret);
}
-static DECLARE_WORK(card_reset_work, if_sdio_reset_card_worker);
static void if_sdio_reset_card(struct lbs_private *priv)
{
struct if_sdio_card *card = priv->card;
- if (work_pending(&card_reset_work))
- return;
-
- reset_host = card->func->card->host;
- schedule_work(&card_reset_work);
+ if (!work_pending(&card->reset_worker))
+ schedule_work(&card->reset_worker);
}
static int if_sdio_power_save(struct lbs_private *priv)
@@ -1137,7 +1138,7 @@ static int if_sdio_probe(struct sdio_func *func,
struct lbs_private *priv;
int ret, i;
unsigned int model;
- struct if_sdio_packet *packet;
+ struct if_sdio_packet *packet, *tmp;
for (i = 0;i < func->card->num_info;i++) {
if (sscanf(func->card->info[i],
@@ -1178,11 +1179,15 @@ static int if_sdio_probe(struct sdio_func *func,
}
spin_lock_init(&card->lock);
+ INIT_LIST_HEAD(&card->packets);
+
card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0);
if (unlikely(!card->workqueue)) {
ret = -ENOMEM;
goto err_queue;
}
+
+ INIT_WORK(&card->reset_worker, if_sdio_reset_card_worker);
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
init_waitqueue_head(&card->pwron_waitq);
@@ -1233,13 +1238,12 @@ err_activate_card:
flush_workqueue(card->workqueue);
lbs_remove_card(priv);
free:
+ cancel_work_sync(&card->packet_worker);
+ cancel_work_sync(&card->reset_worker);
destroy_workqueue(card->workqueue);
err_queue:
- while (card->packets) {
- packet = card->packets;
- card->packets = card->packets->next;
+ list_for_each_entry_safe(packet, tmp, &card->packets, list)
kfree(packet);
- }
kfree(card);
@@ -1249,7 +1253,7 @@ err_queue:
static void if_sdio_remove(struct sdio_func *func)
{
struct if_sdio_card *card;
- struct if_sdio_packet *packet;
+ struct if_sdio_packet *packet, *tmp;
card = sdio_get_drvdata(func);
@@ -1277,13 +1281,12 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
+ cancel_work_sync(&card->packet_worker);
+ cancel_work_sync(&card->reset_worker);
destroy_workqueue(card->workqueue);
- while (card->packets) {
- packet = card->packets;
- card->packets = card->packets->next;
+ list_for_each_entry_safe(packet, tmp, &card->packets, list)
kfree(packet);
- }
kfree(card);
}
@@ -1403,8 +1406,6 @@ static void __exit if_sdio_exit_module(void)
/* Set the flag as user is removing this module. */
user_rmmod = 1;
- cancel_work_sync(&card_reset_work);
-
sdio_unregister_driver(&if_sdio_driver);
}
diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c
index 1225fc0e3352..8690b0114e23 100644
--- a/drivers/net/wireless/marvell/libertas/if_spi.c
+++ b/drivers/net/wireless/marvell/libertas/if_spi.c
@@ -76,16 +76,13 @@ struct if_spi_card {
static void free_if_spi_card(struct if_spi_card *card)
{
- struct list_head *cursor, *next;
- struct if_spi_packet *packet;
+ struct if_spi_packet *packet, *tmp;
- list_for_each_safe(cursor, next, &card->cmd_packet_list) {
- packet = container_of(cursor, struct if_spi_packet, list);
+ list_for_each_entry_safe(packet, tmp, &card->cmd_packet_list, list) {
list_del(&packet->list);
kfree(packet);
}
- list_for_each_safe(cursor, next, &card->data_packet_list) {
- packet = container_of(cursor, struct if_spi_packet, list);
+ list_for_each_entry_safe(packet, tmp, &card->data_packet_list, list) {
list_del(&packet->list);
kfree(packet);
}
@@ -829,11 +826,16 @@ static void if_spi_e2h(struct if_spi_card *card)
goto out;
/* re-enable the card event interrupt */
- spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
- ~IF_SPI_HICU_CARD_EVENT);
+ err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
+ ~IF_SPI_HICU_CARD_EVENT);
+ if (err)
+ goto out;
/* generate a card interrupt */
- spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT);
+ err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
+ IF_SPI_CIC_HOST_EVENT);
+ if (err)
+ goto out;
lbs_queue_event(priv, cause & 0xff);
out:
diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c
index 90ffe8d1e0e8..2dd635935448 100644
--- a/drivers/net/wireless/marvell/libertas/mesh.c
+++ b/drivers/net/wireless/marvell/libertas/mesh.c
@@ -188,8 +188,11 @@ static ssize_t anycast_mask_store(struct device *dev,
uint32_t datum;
int ret;
+ ret = kstrtouint(buf, 16, &datum);
+ if (ret)
+ return ret;
+
memset(&mesh_access, 0, sizeof(mesh_access));
- sscanf(buf, "%x", &datum);
mesh_access.data[0] = cpu_to_le32(datum);
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
@@ -241,15 +244,14 @@ static ssize_t prb_rsp_limit_store(struct device *dev,
int ret;
unsigned long retry_limit;
- memset(&mesh_access, 0, sizeof(mesh_access));
- mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
-
ret = kstrtoul(buf, 10, &retry_limit);
if (ret)
return ret;
if (retry_limit > 15)
return -ENOTSUPP;
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
mesh_access.data[1] = cpu_to_le32(retry_limit);
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
@@ -285,9 +287,12 @@ static ssize_t lbs_mesh_store(struct device *dev,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
- int enable;
+ int ret, enable;
+
+ ret = kstrtoint(buf, 16, &enable);
+ if (ret)
+ return ret;
- sscanf(buf, "%x", &enable);
enable = !!enable;
if (enable == !!priv->mesh_dev)
return count;
@@ -387,11 +392,13 @@ static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
uint32_t datum;
int ret;
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 1))
+ ret = kstrtouint(buf, 10, &datum);
+ if (ret)
+ return ret;
+ if (datum > 1)
return -EINVAL;
+ memset(&cmd, 0, sizeof(cmd));
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
cmd.length = cpu_to_le16(sizeof(uint32_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
@@ -438,11 +445,14 @@ static ssize_t boottime_store(struct device *dev,
uint32_t datum;
int ret;
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
+ ret = kstrtouint(buf, 10, &datum);
+ if (ret)
+ return ret;
+ if (datum > 255)
return -EINVAL;
+ memset(&cmd, 0, sizeof(cmd));
+
/* A too small boot time will result in the device booting into
* standalone (no-host) mode before the host can take control of it,
* so the change will be hard to revert. This may be a desired
@@ -497,11 +507,13 @@ static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
uint32_t datum;
int ret;
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if (ret != 1 || datum < 1 || datum > 11)
+ ret = kstrtouint(buf, 10, &datum);
+ if (ret)
+ return ret;
+ if (datum < 1 || datum > 11)
return -EINVAL;
+ memset(&cmd, 0, sizeof(cmd));
*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
cmd.length = cpu_to_le16(sizeof(uint16_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
@@ -626,11 +638,14 @@ static ssize_t protocol_id_store(struct device *dev,
uint32_t datum;
int ret;
- memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%d", &datum);
- if ((ret != 1) || (datum > 255))
+ ret = kstrtouint(buf, 10, &datum);
+ if (ret)
+ return ret;
+ if (datum > 255)
return -EINVAL;
+ memset(&cmd, 0, sizeof(cmd));
+
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 813d1cbebe19..ba4e29713a8c 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4395,6 +4395,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_HAS_CHANNEL_SWITCH |
+ WIPHY_FLAG_NETNS_OK |
WIPHY_FLAG_PS_ON_BY_DEFAULT;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c
index 52b18f4a774b..f9c9fec7c792 100644
--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c
+++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c
@@ -253,8 +253,11 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf,
if (!p)
return -ENOMEM;
- if (!priv || !priv->hist_data)
- return -EFAULT;
+ if (!priv || !priv->hist_data) {
+ ret = -EFAULT;
+ goto free_and_exit;
+ }
+
phist_data = priv->hist_data;
p += sprintf(p, "\n"
@@ -309,6 +312,8 @@ mwifiex_histogram_read(struct file *file, char __user *ubuf,
ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
(unsigned long)p - page);
+free_and_exit:
+ free_page(page);
return ret;
}
@@ -420,7 +425,10 @@ mwifiex_regrdwr_write(struct file *file,
if (IS_ERR(buf))
return PTR_ERR(buf);
- sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
+ if (sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value) != 3) {
+ ret = -EINVAL;
+ goto done;
+ }
if (reg_type == 0 || reg_offset == 0) {
ret = -EINVAL;
@@ -686,7 +694,10 @@ mwifiex_rdeeprom_write(struct file *file,
if (IS_ERR(buf))
return PTR_ERR(buf);
- sscanf(buf, "%d %d", &offset, &bytes);
+ if (sscanf(buf, "%d %d", &offset, &bytes) != 2) {
+ ret = -EINVAL;
+ goto done;
+ }
if (offset == -1 || bytes == -1) {
ret = -EINVAL;
diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h
index 88648c062713..326ffb05d791 100644
--- a/drivers/net/wireless/marvell/mwifiex/decl.h
+++ b/drivers/net/wireless/marvell/mwifiex/decl.h
@@ -180,7 +180,6 @@ struct mwifiex_rxinfo {
};
struct mwifiex_txinfo {
- u32 status_code;
u8 flags;
u8 bss_num;
u8 bss_type;
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 7dddb4b5dea1..c9c58419c37b 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -282,14 +282,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM);
sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED);
- memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
adapter->tx_lock_flag = false;
adapter->null_pkt_interval = 0;
adapter->fw_bands = 0;
adapter->config_bands = 0;
adapter->adhoc_start_band = 0;
- adapter->scan_channels = NULL;
adapter->fw_release_number = 0;
adapter->fw_cap_info = 0;
memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 1cd9d20cca16..d99127dc466e 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -724,14 +724,9 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter,
/* Override default firmware with manufacturing one if
* manufacturing mode is enabled
*/
- if (mfg_mode) {
- if (strlcpy(adapter->fw_name, MFG_FIRMWARE,
- sizeof(adapter->fw_name)) >=
- sizeof(adapter->fw_name)) {
- pr_err("%s: fw_name too long!\n", __func__);
- return -1;
- }
- }
+ if (mfg_mode)
+ strscpy(adapter->fw_name, MFG_FIRMWARE,
+ sizeof(adapter->fw_name));
if (req_fw_nowait) {
ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index b95886e1413e..7bdec6c62248 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -444,15 +444,6 @@ struct mwifiex_current_bss_params {
u8 data_rates[MWIFIEX_SUPPORTED_RATES];
};
-struct mwifiex_sleep_params {
- u16 sp_error;
- u16 sp_offset;
- u16 sp_stable_time;
- u8 sp_cal_control;
- u8 sp_ext_sleep_clk;
- u16 sp_reserved;
-};
-
struct mwifiex_sleep_period {
u16 period;
u16 reserved;
@@ -681,7 +672,6 @@ struct mwifiex_private {
struct cfg80211_chan_def dfs_chandef;
struct workqueue_struct *dfs_cac_workqueue;
struct delayed_work dfs_cac_work;
- struct timer_list dfs_chan_switch_timer;
struct workqueue_struct *dfs_chan_sw_workqueue;
struct delayed_work dfs_chan_sw_work;
struct cfg80211_beacon_data beacon_after;
@@ -888,8 +878,6 @@ struct mwifiex_adapter {
struct work_struct main_work;
struct workqueue_struct *rx_workqueue;
struct work_struct rx_work;
- struct workqueue_struct *dfs_workqueue;
- struct work_struct dfs_work;
bool rx_work_enabled;
bool rx_processing;
bool delay_main_work;
@@ -953,9 +941,7 @@ struct mwifiex_adapter {
u8 fw_bands;
u8 adhoc_start_band;
u8 config_bands;
- struct mwifiex_chan_scan_param_set *scan_channels;
u8 tx_lock_flag;
- struct mwifiex_sleep_params sleep_params;
struct mwifiex_sleep_period sleep_period;
u16 ps_mode;
u32 ps_state;
@@ -1155,8 +1141,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *);
void mwifiex_delete_all_station_list(struct mwifiex_private *priv);
void mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv,
const u8 *ra_addr);
-void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
-void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb);
+void mwifiex_process_sta_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb);
+void mwifiex_process_uap_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb);
int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta, bool init);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
struct mwifiex_scan_cmd_config *scan_cfg);
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 9a698a16a8f3..6697132ecc97 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -189,6 +189,8 @@ static int mwifiex_pcie_probe_of(struct device *dev)
}
static void mwifiex_pcie_work(struct work_struct *work);
+static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter);
+static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter);
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
@@ -792,14 +794,15 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
if (!skb) {
mwifiex_dbg(adapter, ERROR,
"Unable to allocate skb for RX ring.\n");
- kfree(card->rxbd_ring_vbase);
return -ENOMEM;
}
if (mwifiex_map_pci_memory(adapter, skb,
MWIFIEX_RX_DATA_BUF_SIZE,
- DMA_FROM_DEVICE))
- return -1;
+ DMA_FROM_DEVICE)) {
+ kfree_skb(skb);
+ return -ENOMEM;
+ }
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
@@ -849,7 +852,6 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
if (!skb) {
mwifiex_dbg(adapter, ERROR,
"Unable to allocate skb for EVENT buf.\n");
- kfree(card->evtbd_ring_vbase);
return -ENOMEM;
}
skb_put(skb, MAX_EVENT_SIZE);
@@ -857,8 +859,7 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
DMA_FROM_DEVICE)) {
kfree_skb(skb);
- kfree(card->evtbd_ring_vbase);
- return -1;
+ return -ENOMEM;
}
buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
@@ -1058,6 +1059,7 @@ static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
{
+ int ret;
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
@@ -1096,7 +1098,10 @@ static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
(u32)((u64)card->rxbd_ring_pbase >> 32),
card->rxbd_ring_size);
- return mwifiex_init_rxq_ring(adapter);
+ ret = mwifiex_init_rxq_ring(adapter);
+ if (ret)
+ mwifiex_pcie_delete_rxbd_ring(adapter);
+ return ret;
}
/*
@@ -1127,6 +1132,7 @@ static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
*/
static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
{
+ int ret;
struct pcie_service_card *card = adapter->card;
const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
@@ -1161,7 +1167,10 @@ static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
(u32)((u64)card->evtbd_ring_pbase >> 32),
card->evtbd_ring_size);
- return mwifiex_pcie_init_evt_ring(adapter);
+ ret = mwifiex_pcie_init_evt_ring(adapter);
+ if (ret)
+ mwifiex_pcie_delete_evtbd_ring(adapter);
+ return ret;
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 644b1e134b01..72904c275461 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -612,7 +612,6 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
int ret = 0;
struct mwifiex_chan_scan_param_set *tmp_chan_list;
- struct mwifiex_chan_scan_param_set *start_chan;
u32 tlv_idx, rates_size, cmd_no;
u32 total_scan_time;
u32 done_early;
@@ -643,7 +642,6 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
total_scan_time = 0;
radio_type = 0;
chan_tlv_out->header.len = 0;
- start_chan = tmp_chan_list;
done_early = false;
/*
@@ -750,8 +748,6 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out,
radio_type);
- priv->adapter->scan_channels = start_chan;
-
/* Send the scan command to the firmware with the specified
cfg */
if (priv->adapter->ext_scan)
@@ -828,7 +824,6 @@ mwifiex_config_scan(struct mwifiex_private *priv,
u8 ssid_filter;
struct mwifiex_ie_types_htcap *ht_cap;
struct mwifiex_ie_types_bss_mode *bss_mode;
- const u8 zero_mac[6] = {0, 0, 0, 0, 0, 0};
/* The tlv_buf_len is calculated for each scan command. The TLVs added
in this routine will be preserved since the routine that sends the
@@ -966,7 +961,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
sizeof(struct mwifiex_ie_types_scan_chan_gap);
}
- if (!ether_addr_equal(user_scan_in->random_mac, zero_mac)) {
+ if (!is_zero_ether_addr(user_scan_in->random_mac)) {
random_mac_tlv = (void *)tlv_pos;
random_mac_tlv->header.type =
cpu_to_le16(TLV_TYPE_RANDOM_MAC);
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index a24bd40dd41a..774858cfe86f 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -1083,17 +1083,17 @@ cont:
"info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
/* Set Host interrupt reset to read to clear */
- if (!mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, &reg))
- mwifiex_write_reg(adapter, card->reg->host_int_rsr_reg,
- reg | card->reg->sdio_int_mask);
- else
+ if (mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, &reg))
+ return -1;
+ if (mwifiex_write_reg(adapter, card->reg->host_int_rsr_reg,
+ reg | card->reg->sdio_int_mask))
return -1;
/* Dnld/Upld ready set to auto reset */
- if (!mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, &reg))
- mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg,
- reg | AUTO_RE_ENABLE_INT);
- else
+ if (mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, &reg))
+ return -1;
+ if (mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg,
+ reg | AUTO_RE_ENABLE_INT))
return -1;
return 0;
@@ -1556,7 +1556,7 @@ done:
}
/*
- * This function decode sdio aggreation pkt.
+ * This function decodes sdio aggregation pkt.
*
* Based on the data block size and pkt_len,
* skb data will be decoded to few packets.
@@ -2266,7 +2266,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
card->mpa_tx.buf_len, mport);
- /* Save the last multi port tx aggreagation info to debug log */
+ /* Save the last multi port tx aggregation info to debug log. */
index = adapter->dbg.last_sdio_mp_index;
index = (index + 1) % MWIFIEX_DBG_SDIO_MP_NUM;
adapter->dbg.last_sdio_mp_index = index;
@@ -2525,7 +2525,8 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg);
/* Get SDIO ioport */
- mwifiex_init_sdio_ioport(adapter);
+ if (mwifiex_init_sdio_ioport(adapter))
+ return -EIO;
/* Initialize SDIO variables in card */
card->mp_rd_bitmap = 0;
@@ -3141,7 +3142,8 @@ static void mwifiex_sdio_up_dev(struct mwifiex_adapter *adapter)
*/
mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg);
- mwifiex_init_sdio_ioport(adapter);
+ if (mwifiex_init_sdio_ioport(adapter))
+ dev_err(&card->func->dev, "error enabling SDIO port\n");
}
static struct mwifiex_if_ops sdio_ops = {
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
index 13659b02ba88..65420ad67416 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c
@@ -86,6 +86,15 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length);
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off;
+ if (sizeof(*rx_pkt_hdr) + rx_pkt_off > skb->len) {
+ mwifiex_dbg(priv->adapter, ERROR,
+ "wrong rx packet offset: len=%d, rx_pkt_off=%d\n",
+ skb->len, rx_pkt_off);
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ return -1;
+ }
+
if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
sizeof(bridge_tunnel_header))) ||
(!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
@@ -194,7 +203,8 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
- if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
+ if ((rx_pkt_offset + rx_pkt_length) > skb->len ||
+ sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) {
mwifiex_dbg(adapter, ERROR,
"wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
skb->len, rx_pkt_offset, rx_pkt_length);
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c
index 13c0e67ededf..70c2790b8e35 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c
@@ -29,8 +29,8 @@
* - Priority specific Tx control
* - Flags
*/
-void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
- struct sk_buff *skb)
+void mwifiex_process_sta_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct txpd *local_tx_pd;
@@ -39,15 +39,6 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
u16 pkt_type, pkt_offset;
int hroom = adapter->intf_hdr_len;
- if (!skb->len) {
- mwifiex_dbg(adapter, ERROR,
- "Tx: bad packet length: %d\n", skb->len);
- tx_info->status_code = -1;
- return skb->data;
- }
-
- BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
-
pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
pad = ((uintptr_t)skb->data - (sizeof(*local_tx_pd) + hroom)) &
@@ -109,8 +100,6 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
if (!local_tx_pd->tx_control)
/* TxCtrl set by user or default */
local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
-
- return skb->data;
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index 97bb87c3676b..6c60621b6ccc 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -735,6 +735,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
int ret;
u16 capab;
struct ieee80211_ht_cap *ht_cap;
+ unsigned int extra;
u8 radio, *pos;
capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
@@ -753,7 +754,10 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
- skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
+ /* See the layout of 'struct ieee80211_mgmt'. */
+ extra = sizeof(mgmt->u.action.u.tdls_discover_resp) +
+ sizeof(mgmt->u.action.category);
+ skb_put(skb, extra);
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.u.tdls_discover_resp.action_code =
WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
@@ -762,8 +766,7 @@ mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(capab);
/* move back for addr4 */
- memmove(pos + ETH_ALEN, &mgmt->u.action.category,
- sizeof(mgmt->u.action.u.tdls_discover_resp));
+ memmove(pos + ETH_ALEN, &mgmt->u.action, extra);
/* init address 4 */
eth_broadcast_addr(pos);
diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c
index 54c204608dab..bd91678d26b4 100644
--- a/drivers/net/wireless/marvell/mwifiex/txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/txrx.c
@@ -72,13 +72,18 @@ EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
struct mwifiex_tx_param *tx_param)
{
- int hroom, ret = -1;
+ int hroom, ret;
struct mwifiex_adapter *adapter = priv->adapter;
- u8 *head_ptr;
struct txpd *local_tx_pd = NULL;
struct mwifiex_sta_node *dest_node;
struct ethhdr *hdr = (void *)skb->data;
+ if (unlikely(!skb->len ||
+ skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
hroom = adapter->intf_hdr_len;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
@@ -88,33 +93,31 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
dest_node->stats.tx_packets++;
}
- head_ptr = mwifiex_process_uap_txpd(priv, skb);
+ mwifiex_process_uap_txpd(priv, skb);
} else {
- head_ptr = mwifiex_process_sta_txpd(priv, skb);
+ mwifiex_process_sta_txpd(priv, skb);
}
- if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
+ if (adapter->data_sent || adapter->tx_lock_flag) {
skb_queue_tail(&adapter->tx_data_q, skb);
atomic_inc(&adapter->tx_queued);
return 0;
}
- if (head_ptr) {
- if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
- local_tx_pd = (struct txpd *)(head_ptr + hroom);
- if (adapter->iface_type == MWIFIEX_USB) {
- ret = adapter->if_ops.host_to_card(adapter,
- priv->usb_port,
- skb, tx_param);
- } else {
- ret = adapter->if_ops.host_to_card(adapter,
- MWIFIEX_TYPE_DATA,
- skb, tx_param);
- }
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
+ local_tx_pd = (struct txpd *)(skb->data + hroom);
+ if (adapter->iface_type == MWIFIEX_USB) {
+ ret = adapter->if_ops.host_to_card(adapter,
+ priv->usb_port,
+ skb, tx_param);
+ } else {
+ ret = adapter->if_ops.host_to_card(adapter,
+ MWIFIEX_TYPE_DATA,
+ skb, tx_param);
}
mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
-
+out:
switch (ret) {
case -ENOSR:
mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n");
@@ -137,6 +140,11 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
break;
case -EINPROGRESS:
break;
+ case -EINVAL:
+ mwifiex_dbg(adapter, ERROR,
+ "malformed skb (length: %u, headroom: %u)\n",
+ skb->len, skb_headroom(skb));
+ fallthrough;
case 0:
mwifiex_write_data_complete(adapter, skb, 0, ret);
break;
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
index e495f7eaea03..318bd4ed8399 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c
@@ -103,6 +103,16 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
return;
}
+ if (sizeof(*rx_pkt_hdr) +
+ le16_to_cpu(uap_rx_pd->rx_pkt_offset) > skb->len) {
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet offset: len=%d,rx_pkt_offset=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
sizeof(bridge_tunnel_header))) ||
(!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
@@ -243,7 +253,15 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
if (is_multicast_ether_addr(ra)) {
skb_uap = skb_copy(skb, GFP_ATOMIC);
- mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
+ if (likely(skb_uap)) {
+ mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
+ } else {
+ mwifiex_dbg(adapter, ERROR,
+ "failed to copy skb for uAP\n");
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ return -1;
+ }
} else {
if (mwifiex_get_sta_entry(priv, ra)) {
/* Requeue Intra-BSS packet */
@@ -367,6 +385,16 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+ if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
+ sizeof(rx_pkt_hdr->eth803_hdr) > skb->len) {
+ mwifiex_dbg(adapter, ERROR,
+ "wrong rx packet for struct ethhdr: len=%d, offset=%d\n",
+ skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ return 0;
+ }
+
ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
@@ -442,8 +470,8 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_private *priv,
* - Priority specific Tx control
* - Flags
*/
-void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
- struct sk_buff *skb)
+void mwifiex_process_uap_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct uap_txpd *txpd;
@@ -452,15 +480,6 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
u16 pkt_type, pkt_offset;
int hroom = adapter->intf_hdr_len;
- if (!skb->len) {
- mwifiex_dbg(adapter, ERROR,
- "Tx: bad packet length: %d\n", skb->len);
- tx_info->status_code = -1;
- return skb->data;
- }
-
- BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
-
pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
pad = ((uintptr_t)skb->data - (sizeof(*txpd) + hroom)) &
@@ -508,6 +527,4 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
if (!txpd->tx_control)
/* TxCtrl set by user or default */
txpd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
-
- return skb->data;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index 94c2d219835d..745b1d925b21 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -393,11 +393,15 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
}
rx_pd = (struct rxpd *)skb->data;
+ pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
+ if (pkt_len < sizeof(struct ieee80211_hdr) + sizeof(pkt_len)) {
+ mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length");
+ return -1;
+ }
skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
skb_pull(skb, sizeof(pkt_len));
-
- pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
+ pkt_len -= sizeof(pkt_len);
ieee_hdr = (void *)skb->data;
if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
@@ -410,7 +414,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
skb->data + sizeof(struct ieee80211_hdr),
pkt_len - sizeof(struct ieee80211_hdr));
- pkt_len -= ETH_ALEN + sizeof(pkt_len);
+ pkt_len -= ETH_ALEN;
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
index 18152c16c36f..7eb1b0b63d11 100644
--- a/drivers/net/wireless/mediatek/mt76/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/Kconfig
@@ -29,6 +29,14 @@ config MT76_CONNAC_LIB
tristate
select MT76_CORE
+config MT792x_LIB
+ tristate
+ select MT76_CONNAC_LIB
+
+config MT792x_USB
+ tristate
+ select MT76_USB
+
source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 84c99b7e57f9..85c4799be954 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -5,6 +5,8 @@ obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o
obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
obj-$(CONFIG_MT76_CONNAC_LIB) += mt76-connac-lib.o
+obj-$(CONFIG_MT792x_LIB) += mt792x-lib.o
+obj-$(CONFIG_MT792x_USB) += mt792x-usb.o
mt76-y := \
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
@@ -19,6 +21,7 @@ mt76-sdio-y := sdio.o sdio_txrx.o
CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src)
CFLAGS_mt76x02_trace.o := -I$(src)
+CFLAGS_mt792x_trace.o := -I$(src)
mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \
@@ -27,7 +30,12 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
-mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o mt76_connac3_mac.o
+
+mt792x-lib-y := mt792x_core.o mt792x_mac.o mt792x_trace.o \
+ mt792x_debugfs.o mt792x_dma.o
+mt792x-lib-$(CONFIG_ACPI) += mt792x_acpi_sar.o
+mt792x-usb-y := mt792x_usb.o
obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 465190ebaf1c..05d9ab3ce819 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -466,6 +466,9 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf buf = {};
dma_addr_t addr;
+ if (test_bit(MT76_MCU_RESET, &dev->phy.state))
+ goto error;
+
if (q->queued + 1 >= q->ndesc - 1)
goto error;
@@ -507,6 +510,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
dma_addr_t addr;
u8 *txwi;
+ if (test_bit(MT76_RESET, &dev->phy.state))
+ goto free_skb;
+
t = mt76_get_txwi(dev);
if (!t)
goto free_skb;
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index dce851d42e08..36564930aef1 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -6,34 +6,39 @@
#include <linux/of_net.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/nvmem-consumer.h>
#include <linux/etherdevice.h>
#include "mt76.h"
-int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
+static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
{
-#if defined(CONFIG_OF) && defined(CONFIG_MTD)
struct device_node *np = dev->dev->of_node;
- struct mtd_info *mtd;
- const __be32 *list;
const void *data;
- const char *part;
- phandle phandle;
int size;
- size_t retlen;
- int ret;
- if (!np)
+ data = of_get_property(np, "mediatek,eeprom-data", &size);
+ if (!data)
return -ENOENT;
- data = of_get_property(np, "mediatek,eeprom-data", &size);
- if (data) {
- if (size > len)
- return -EINVAL;
+ if (size > len)
+ return -EINVAL;
- memcpy(eep, data, size);
+ memcpy(eep, data, size);
- return 0;
- }
+ return 0;
+}
+
+static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
+{
+#ifdef CONFIG_MTD
+ struct device_node *np = dev->dev->of_node;
+ struct mtd_info *mtd;
+ const __be32 *list;
+ const char *part;
+ phandle phandle;
+ size_t retlen;
+ int size;
+ int ret;
list = of_get_property(np, "mediatek,mtd-eeprom", &size);
if (!list)
@@ -100,6 +105,56 @@ out_put_node:
return -ENOENT;
#endif
}
+
+static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len)
+{
+ struct device_node *np = dev->dev->of_node;
+ struct nvmem_cell *cell;
+ const void *data;
+ size_t retlen;
+ int ret = 0;
+
+ cell = of_nvmem_cell_get(np, "eeprom");
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ data = nvmem_cell_read(cell, &retlen);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (retlen < len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(eep, data, len);
+
+exit:
+ kfree(data);
+
+ return ret;
+}
+
+int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
+{
+ struct device_node *np = dev->dev->of_node;
+ int ret;
+
+ if (!np)
+ return -ENOENT;
+
+ ret = mt76_get_of_eeprom_data(dev, eep, len);
+ if (!ret)
+ return 0;
+
+ ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len);
+ if (!ret)
+ return 0;
+
+ return mt76_get_of_epprom_from_nvmem(dev, eep, len);
+}
EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);
void
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 467afef98ba2..d158320bc15d 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -4,7 +4,6 @@
*/
#include <linux/sched.h>
#include <linux/of.h>
-#include <net/page_pool.h>
#include "mt76.h"
#define CHAN2G(_idx, _freq) { \
@@ -76,6 +75,7 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
CHAN5G(165, 5825),
CHAN5G(169, 5845),
CHAN5G(173, 5865),
+ CHAN5G(177, 5885),
};
static const struct ieee80211_channel mt76_channels_6ghz[] = {
@@ -660,6 +660,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
idr_init(&dev->rx_token);
INIT_LIST_HEAD(&dev->wcid_list);
+ INIT_LIST_HEAD(&dev->sta_poll_list);
+ spin_lock_init(&dev->sta_poll_lock);
INIT_LIST_HEAD(&dev->txwi_cache);
INIT_LIST_HEAD(&dev->rxwi_cache);
@@ -1743,6 +1745,9 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
for (i = 0; i < (eht ? 14 : 12); i++)
data[ei++] += stats->tx_mcs[i];
+ for (i = 0; i < 4; i++)
+ data[ei++] += stats->tx_nss[i];
+
wi->worker_stat_count = ei - wi->initial_stat_idx;
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 6b07b8fafec2..e8757865a3d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -15,6 +15,7 @@
#include <linux/average.h>
#include <linux/soc/mediatek/mtk_wed.h>
#include <net/mac80211.h>
+#include <net/page_pool/helpers.h>
#include "util.h"
#include "testmode.h"
@@ -277,7 +278,7 @@ struct mt76_sta_stats {
u64 tx_mcs[16]; /* mcs idx */
u64 tx_bytes;
/* WED TX */
- u32 tx_packets;
+ u32 tx_packets; /* unit: MSDU */
u32 tx_retries;
u32 tx_failed;
/* WED RX */
@@ -316,6 +317,7 @@ struct mt76_wcid {
int inactive_count;
struct rate_info rate;
+ unsigned long ampdu_state;
u16 idx;
u8 hw_key_idx;
@@ -336,6 +338,8 @@ struct mt76_wcid {
struct idr pktid;
struct mt76_sta_stats stats;
+
+ struct list_head poll_list;
};
struct mt76_txq {
@@ -702,6 +706,9 @@ struct mt76_vif {
u8 wmm_idx;
u8 scan_seq_num;
u8 cipher;
+ u8 basic_rates_idx;
+ u8 mcast_rates_idx;
+ u8 beacon_rates_idx;
};
struct mt76_phy {
@@ -823,6 +830,9 @@ struct mt76_dev {
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
struct list_head wcid_list;
+ struct list_head sta_poll_list;
+ spinlock_t sta_poll_lock;
+
u32 rev;
struct tasklet_struct pre_tbtt_tasklet;
@@ -857,6 +867,101 @@ struct mt76_dev {
};
};
+/* per-phy stats. */
+struct mt76_mib_stats {
+ u32 ack_fail_cnt;
+ u32 fcs_err_cnt;
+ u32 rts_cnt;
+ u32 rts_retries_cnt;
+ u32 ba_miss_cnt;
+ u32 tx_bf_cnt;
+ u32 tx_mu_bf_cnt;
+ u32 tx_mu_mpdu_cnt;
+ u32 tx_mu_acked_mpdu_cnt;
+ u32 tx_su_acked_mpdu_cnt;
+ u32 tx_bf_ibf_ppdu_cnt;
+ u32 tx_bf_ebf_ppdu_cnt;
+
+ u32 tx_bf_rx_fb_all_cnt;
+ u32 tx_bf_rx_fb_eht_cnt;
+ u32 tx_bf_rx_fb_he_cnt;
+ u32 tx_bf_rx_fb_vht_cnt;
+ u32 tx_bf_rx_fb_ht_cnt;
+
+ u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
+ u32 tx_bf_rx_fb_nc_cnt;
+ u32 tx_bf_rx_fb_nr_cnt;
+ u32 tx_bf_fb_cpl_cnt;
+ u32 tx_bf_fb_trig_cnt;
+
+ u32 tx_ampdu_cnt;
+ u32 tx_stop_q_empty_cnt;
+ u32 tx_mpdu_attempts_cnt;
+ u32 tx_mpdu_success_cnt;
+ u32 tx_pkt_ebf_cnt;
+ u32 tx_pkt_ibf_cnt;
+
+ u32 tx_rwp_fail_cnt;
+ u32 tx_rwp_need_cnt;
+
+ /* rx stats */
+ u32 rx_fifo_full_cnt;
+ u32 channel_idle_cnt;
+ u32 primary_cca_busy_time;
+ u32 secondary_cca_busy_time;
+ u32 primary_energy_detect_time;
+ u32 cck_mdrdy_time;
+ u32 ofdm_mdrdy_time;
+ u32 green_mdrdy_time;
+ u32 rx_vector_mismatch_cnt;
+ u32 rx_delimiter_fail_cnt;
+ u32 rx_mrdy_cnt;
+ u32 rx_len_mismatch_cnt;
+ u32 rx_mpdu_cnt;
+ u32 rx_ampdu_cnt;
+ u32 rx_ampdu_bytes_cnt;
+ u32 rx_ampdu_valid_subframe_cnt;
+ u32 rx_ampdu_valid_subframe_bytes_cnt;
+ u32 rx_pfdrop_cnt;
+ u32 rx_vec_queue_overflow_drop_cnt;
+ u32 rx_ba_cnt;
+
+ u32 tx_amsdu[8];
+ u32 tx_amsdu_cnt;
+
+ /* mcu_muru_stats */
+ u32 dl_cck_cnt;
+ u32 dl_ofdm_cnt;
+ u32 dl_htmix_cnt;
+ u32 dl_htgf_cnt;
+ u32 dl_vht_su_cnt;
+ u32 dl_vht_2mu_cnt;
+ u32 dl_vht_3mu_cnt;
+ u32 dl_vht_4mu_cnt;
+ u32 dl_he_su_cnt;
+ u32 dl_he_ext_su_cnt;
+ u32 dl_he_2ru_cnt;
+ u32 dl_he_2mu_cnt;
+ u32 dl_he_3ru_cnt;
+ u32 dl_he_3mu_cnt;
+ u32 dl_he_4ru_cnt;
+ u32 dl_he_4mu_cnt;
+ u32 dl_he_5to8ru_cnt;
+ u32 dl_he_9to16ru_cnt;
+ u32 dl_he_gtr16ru_cnt;
+
+ u32 ul_hetrig_su_cnt;
+ u32 ul_hetrig_2ru_cnt;
+ u32 ul_hetrig_3ru_cnt;
+ u32 ul_hetrig_4ru_cnt;
+ u32 ul_hetrig_5to8ru_cnt;
+ u32 ul_hetrig_9to16ru_cnt;
+ u32 ul_hetrig_gtr16ru_cnt;
+ u32 ul_hetrig_2mu_cnt;
+ u32 ul_hetrig_3mu_cnt;
+ u32 ul_hetrig_4mu_cnt;
+};
+
struct mt76_power_limits {
s8 cck[4];
s8 ofdm[8];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
index 6a0080f1d91c..dd16acfd9735 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
@@ -5,7 +5,7 @@ config MT7603E
depends on MAC80211
depends on PCI
help
- This adds support for MT7603E wireless PCIe devices and the WLAN core
+ This adds support for MT7603E PCIe wireless devices and the WLAN core
on MT7628/MT7688 SoC devices. This family supports IEEE 802.11n 2x2
to 300Mbps PHY rate
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
index b65b0a88c1de..888678732f29 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
@@ -161,7 +161,8 @@ void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval)
return;
}
- dev->mt76.beacon_int = intval;
+ if (intval)
+ dev->mt76.beacon_int = intval;
mt76_wr(dev, MT_TBTT,
FIELD_PREP(MT_TBTT_PERIOD, intval) | MT_TBTT_CAL_ENABLE);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 9a2e632d577a..0762de3ce5ac 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -500,8 +500,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
bus_ops->rmw = mt7603_rmw;
dev->mt76.bus = bus_ops;
- INIT_LIST_HEAD(&dev->sta_poll_list);
- spin_lock_init(&dev->sta_poll_lock);
spin_lock_init(&dev->ps_lock);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7603_mac_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index 12e0af52082a..99ae080502d8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -178,8 +178,9 @@ mt7603_wtbl_set_skip_tx(struct mt7603_dev *dev, int idx, bool enabled)
mt76_wr(dev, addr + 3 * 4, val);
}
-void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort)
+void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort)
{
+ u32 flush_mask;
int i, port, queue;
if (abort) {
@@ -195,6 +196,18 @@ void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort)
mt76_wr(dev, MT_TX_ABORT, MT_TX_ABORT_EN |
FIELD_PREP(MT_TX_ABORT_WCID, idx));
+ flush_mask = MT_WF_ARB_TX_FLUSH_AC0 |
+ MT_WF_ARB_TX_FLUSH_AC1 |
+ MT_WF_ARB_TX_FLUSH_AC2 |
+ MT_WF_ARB_TX_FLUSH_AC3;
+ flush_mask <<= mac_idx;
+
+ mt76_wr(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask);
+ mt76_poll(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask, 0, 20000);
+ mt76_wr(dev, MT_WF_ARB_TX_START_0, flush_mask);
+
+ mt76_wr(dev, MT_TX_ABORT, 0);
+
for (i = 0; i < 4; i++) {
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, idx) |
@@ -202,13 +215,11 @@ void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort)
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, port) |
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, queue));
- mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 15000);
+ mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000);
}
WARN_ON_ONCE(mt76_rr(dev, MT_DMA_FQCR0) & MT_DMA_FQCR0_BUSY);
- mt76_wr(dev, MT_TX_ABORT, 0);
-
mt7603_wtbl_set_skip_tx(dev, idx, false);
}
@@ -245,7 +256,7 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000);
if (enabled)
- mt7603_filter_tx(dev, idx, false);
+ mt7603_filter_tx(dev, sta->vif->idx, idx, false);
addr = mt7603_wtbl1_addr(idx);
mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
@@ -412,16 +423,16 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
while (1) {
bool clear = false;
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&dev->sta_poll_list)) {
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&dev->mt76.sta_poll_list)) {
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
break;
}
- msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
- poll_list);
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ msta = list_first_entry(&dev->mt76.sta_poll_list,
+ struct mt7603_sta, wcid.poll_list);
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
addr = mt7603_wtbl4_addr(msta->wcid.idx);
for (i = 0; i < 4; i++) {
@@ -1267,10 +1278,10 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
msta = container_of(wcid, struct mt7603_sta, wcid);
sta = wcid_to_sta(wcid);
- if (list_empty(&msta->poll_list)) {
- spin_lock_bh(&dev->sta_poll_lock);
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list)) {
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 1b1358c6bb46..c213fd2a5216 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -66,9 +66,10 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
dev->mt76.vif_mask |= BIT_ULL(mvif->idx);
- INIT_LIST_HEAD(&mvif->sta.poll_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1;
+ mvif->sta.vif = mvif;
mt76_packet_id_init(&mvif->sta.wcid);
eth_broadcast_addr(bc_addr);
@@ -100,10 +101,10 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
mutex_lock(&dev->mt76.mutex);
dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx);
@@ -351,12 +352,13 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
- INIT_LIST_HEAD(&msta->poll_list);
+ INIT_LIST_HEAD(&msta->wcid.poll_list);
__skb_queue_head_init(&msta->psq);
msta->ps = ~0;
msta->smps = ~0;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
+ msta->vif = mvif;
mt7603_wtbl_init(dev, idx, mvif->idx, sta->addr);
mt7603_wtbl_set_ps(dev, msta, false);
@@ -380,18 +382,19 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
+ struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
spin_lock_bh(&dev->ps_lock);
__skb_queue_purge(&msta->psq);
- mt7603_filter_tx(dev, wcid->idx, true);
+ mt7603_filter_tx(dev, mvif->idx, wcid->idx, true);
spin_unlock_bh(&dev->ps_lock);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
mt7603_wtbl_clear(dev, wcid->idx);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index 7c3be596da09..9e58df7042ad 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -64,7 +64,6 @@ struct mt7603_sta {
struct mt7603_vif *vif;
- struct list_head poll_list;
u32 tx_airtime_ac[4];
struct sk_buff_head psq;
@@ -110,9 +109,6 @@ struct mt7603_dev {
u32 rxfilter;
- struct list_head sta_poll_list;
- spinlock_t sta_poll_lock;
-
struct mt7603_sta global_sta;
u32 agc0, agc3;
@@ -234,7 +230,7 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
bool enabled);
void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
bool enabled);
-void mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort);
+void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort);
int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
index 3b901090b29c..a39c9a0fcb1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h
@@ -309,6 +309,13 @@ enum {
#define MT_WF_ARB_TX_STOP_0 MT_WF_ARB(0x110)
#define MT_WF_ARB_TX_STOP_1 MT_WF_ARB(0x114)
+#define MT_WF_ARB_TX_FLUSH_AC0 BIT(0)
+#define MT_WF_ARB_TX_FLUSH_AC1 BIT(5)
+#define MT_WF_ARB_TX_FLUSH_AC2 BIT(10)
+#define MT_WF_ARB_TX_FLUSH_AC3 BIT(16)
+#define MT_WF_ARB_TX_FLUSH_AC4 BIT(21)
+#define MT_WF_ARB_TX_FLUSH_AC5 BIT(26)
+
#define MT_WF_ARB_BCN_START MT_WF_ARB(0x118)
#define MT_WF_ARB_BCN_START_BSSn(n) BIT(0 + (n))
#define MT_WF_ARB_BCN_START_T_PRE_TTTT BIT(10)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
index 30fba36ff46b..1ab1439143f4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -11,7 +11,7 @@ config MT7615E
depends on MAC80211
depends on PCI
help
- This adds support for MT7615-based wireless PCIe devices,
+ This adds support for MT7615-based PCIe wireless devices,
which support concurrent dual-band operation at both 5GHz
and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2
MU-MIMO up to 4 users/group and 160MHz channels.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 621e69f07e3c..18a50ccff106 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -397,6 +397,8 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+ if (!is_mt7622(&phy->dev->mt76))
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
@@ -626,8 +628,6 @@ void mt7615_init_device(struct mt7615_dev *dev)
INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work);
skb_queue_head_init(&dev->phy.scan_event_list);
skb_queue_head_init(&dev->coredump.msg_list);
- INIT_LIST_HEAD(&dev->sta_poll_list);
- spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
init_waitqueue_head(&dev->phy.roc_wait);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 64002484ccad..7ba789834e8d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -387,10 +387,11 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
struct mt7615_sta *msta;
msta = container_of(status->wcid, struct mt7615_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask &&
@@ -905,19 +906,19 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
int i;
INIT_LIST_HEAD(&sta_poll_list);
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&dev->sta_poll_list, &sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
while (!list_empty(&sta_poll_list)) {
bool clear = false;
msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
- poll_list);
+ wcid.poll_list);
- spin_lock_bh(&dev->sta_poll_lock);
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
@@ -1514,10 +1515,10 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
msta = container_of(wcid, struct mt7615_sta, wcid);
sta = wcid_to_sta(wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index dadb13f2ca09..200b1752ca77 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -222,7 +222,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
idx = MT7615_WTBL_RESERVED - mvif->mt76.idx;
- INIT_LIST_HEAD(&mvif->sta.poll_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
mvif->sta.wcid.hw_key_idx = -1;
@@ -274,10 +274,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt7615_mutex_release(dev);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
}
@@ -552,6 +552,32 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
mt7615_mutex_release(dev);
}
+static void
+mt7615_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt7615_dev *dev = mt7615_hw_dev(hw);
+ u8 i, band = mvif->mt76.band_idx;
+ u32 *mu;
+
+ mu = (u32 *)info->mu_group.membership;
+ for (i = 0; i < WLAN_MEMBERSHIP_LEN / sizeof(*mu); i++) {
+ if (is_mt7663(&dev->mt76))
+ mt76_wr(dev, MT7663_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
+ else
+ mt76_wr(dev, MT_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
+ }
+
+ mu = (u32 *)info->mu_group.position;
+ for (i = 0; i < WLAN_USER_POSITION_LEN / sizeof(*mu); i++) {
+ if (is_mt7663(&dev->mt76))
+ mt76_wr(dev, MT7663_WF_PHY_GID_TAB_POS(band, i), mu[i]);
+ else
+ mt76_wr(dev, MT_WF_PHY_GID_TAB_POS(band, i), mu[i]);
+ }
+}
+
static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -600,6 +626,9 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC)
mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc);
+ if (changed & BSS_CHANGED_MU_GROUPS)
+ mt7615_update_mu_group(hw, vif, info);
+
mt7615_mutex_release(dev);
}
@@ -628,7 +657,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
- INIT_LIST_HEAD(&msta->poll_list);
+ INIT_LIST_HEAD(&msta->wcid.poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
@@ -676,10 +705,10 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
mt7615_mcu_add_bss_info(phy, vif, sta, false);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
mt76_connac_power_save_sched(phy->mt76, &dev->pm);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 582d1b5b7cb3..a20322aae967 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -125,7 +125,6 @@ struct mt7615_sta {
struct mt7615_vif *vif;
- struct list_head poll_list;
u32 airtime_ac[8];
struct ieee80211_tx_rate rates[4];
@@ -262,9 +261,6 @@ struct mt7615_dev {
wait_queue_head_t reset_wait;
u32 reset_state;
- struct list_head sta_poll_list;
- spinlock_t sta_poll_lock;
-
struct {
u8 n_pulses;
u32 period;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615_trace.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615_trace.h
index d3eb49d83b98..9be5a58a4e6d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615_trace.h
@@ -14,7 +14,7 @@
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \
wiphy_name(mt76_hw(dev)->wiphy), MAXNAME)
#define DEV_PR_FMT "%s"
#define DEV_PR_ARG __entry->wiphy_name
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 7cecb22c569e..806b3887c541 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -212,6 +212,15 @@ enum mt7615_reg_base {
#define MT7663_WF_PHY_R0_PHYCTRL_STS5(_phy) MT_WF_PHY(0x0224 + ((_phy) << 12))
+#define MT_WF_PHY_GID_TAB_VLD(_phy, i) MT_WF_PHY(0x0254 + (i) * 4 + \
+ ((_phy) << 9))
+#define MT7663_WF_PHY_GID_TAB_VLD(_phy, i) MT_WF_PHY(0x0254 + (i) * 4 + \
+ ((_phy) << 12))
+#define MT_WF_PHY_GID_TAB_POS(_phy, i) MT_WF_PHY(0x025c + (i) * 4 + \
+ ((_phy) << 9))
+#define MT7663_WF_PHY_GID_TAB_POS(_phy, i) MT_WF_PHY(0x025c + (i) * 4 + \
+ ((_phy) << 12))
+
#define MT_WF_PHY_MIN_PRI_PWR(_phy) MT_WF_PHY((_phy) ? 0x084 : 0x229c)
#define MT_WF_PHY_PD_OFDM_MASK(_phy) ((_phy) ? GENMASK(24, 16) : \
GENMASK(28, 20))
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 15653b274f83..22878f088804 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -197,11 +197,21 @@ static inline bool is_mt7916(struct mt76_dev *dev)
return mt76_chip(dev) == 0x7906;
}
+static inline bool is_mt7981(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7981;
+}
+
static inline bool is_mt7986(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7986;
}
+static inline bool is_mt798x(struct mt76_dev *dev)
+{
+ return is_mt7981(dev) || is_mt7986(dev);
+}
+
static inline bool is_mt7996(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7990;
@@ -409,5 +419,13 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
struct mt76_rx_status *status,
struct ieee80211_supported_band *sband,
__le32 *rxv, u8 *mode);
-
+void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
+void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
+ struct ieee80211_sta *sta,
+ struct list_head *free_list);
+void mt76_connac2_tx_token_put(struct mt76_dev *dev);
+
+/* connac3 */
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,
+ u8 mode);
#endif /* __MT76_CONNAC_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h
index fabf637bdf7f..bd2a92467a97 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac2_mac.h
@@ -34,7 +34,7 @@ enum {
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
-#define MT_TX_FREE_LATENCY GENMASK(12, 0)
+#define MT_TX_FREE_COUNT GENMASK(12, 0)
/* 0: success, others: dropped */
#define MT_TX_FREE_STATUS GENMASK(14, 13)
#define MT_TX_FREE_MSDU_ID GENMASK(30, 16)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
new file mode 100644
index 000000000000..73e9f283d0ae
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt76_connac.h"
+#include "mt76_connac3_mac.h"
+#include "dma.h"
+
+#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
+ IEEE80211_RADIOTAP_HE_##f)
+
+static void
+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
+ struct ieee80211_radiotap_he *he,
+ __le32 *rxv)
+{
+ u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
+
+ status->bw = RATE_INFO_BW_HE_RU;
+
+ switch (ru) {
+ case 0 ... 36:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
+ offs = ru;
+ break;
+ case 37 ... 52:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
+ offs = ru - 37;
+ break;
+ case 53 ... 60:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ offs = ru - 53;
+ break;
+ case 61 ... 64:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
+ offs = ru - 61;
+ break;
+ case 65 ... 66:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
+ offs = ru - 65;
+ break;
+ case 67:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
+ break;
+ case 68:
+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+ break;
+ }
+
+ he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+ he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
+ le16_encode_bits(offs,
+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
+}
+
+#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
+static void
+mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
+{
+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ static const struct ieee80211_radiotap_he_mu mu_known = {
+ .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+ HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+ HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+ HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+ .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+ };
+ struct ieee80211_radiotap_he_mu *he_mu;
+
+ status->flag |= RX_FLAG_RADIOTAP_HE_MU;
+
+ he_mu = skb_push(skb, sizeof(mu_known));
+ memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+ if (status->he_dcm)
+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
+
+ he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+ le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
+
+ he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
+
+ if (status->bw >= RATE_INFO_BW_40) {
+ he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+ he_mu->ru_ch2[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU1) & 0xff;
+ }
+
+ if (status->bw >= RATE_INFO_BW_80) {
+ u32 ru_h, ru_l;
+
+ he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
+
+ ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
+ ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
+ he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
+ }
+}
+
+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,
+ u8 mode)
+{
+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ static const struct ieee80211_radiotap_he known = {
+ .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
+ HE_BITS(DATA1_STBC_KNOWN) |
+ HE_BITS(DATA1_CODING_KNOWN) |
+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
+ HE_BITS(DATA1_DOPPLER_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
+ .data2 = HE_BITS(DATA2_GI_KNOWN) |
+ HE_BITS(DATA2_TXBF_KNOWN) |
+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
+ HE_BITS(DATA2_TXOP_KNOWN),
+ };
+ u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
+ struct ieee80211_radiotap_he *he;
+
+ status->flag |= RX_FLAG_RADIOTAP_HE;
+
+ he = skb_push(skb, sizeof(known));
+ memcpy(he, &known, sizeof(known));
+
+ he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
+ HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
+ he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
+ he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
+ le16_encode_bits(ltf_size,
+ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+ he->data5 |= HE_BITS(DATA5_TXBF);
+ he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
+ HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
+
+ switch (mode) {
+ case MT_PHY_TYPE_HE_SU:
+ he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
+ HE_BITS(DATA1_UL_DL_KNOWN) |
+ HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+ he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
+ HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+ break;
+ case MT_PHY_TYPE_HE_EXT_SU:
+ he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
+ HE_BITS(DATA1_UL_DL_KNOWN) |
+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
+
+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+ break;
+ case MT_PHY_TYPE_HE_MU:
+ he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
+ HE_BITS(DATA1_UL_DL_KNOWN);
+
+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
+ he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
+
+ mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
+ mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv);
+ break;
+ case MT_PHY_TYPE_HE_TB:
+ he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
+ HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
+
+ he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
+
+ mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
new file mode 100644
index 000000000000..68ca0844cbbf
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
@@ -0,0 +1,339 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#ifndef __MT76_CONNAC3_MAC_H
+#define __MT76_CONNAC3_MAC_H
+
+enum {
+ MT_CTX0,
+ MT_HIF0 = 0x0,
+
+ MT_LMAC_AC00 = 0x0,
+ MT_LMAC_AC01,
+ MT_LMAC_AC02,
+ MT_LMAC_AC03,
+ MT_LMAC_ALTX0 = 0x10,
+ MT_LMAC_BMC0,
+ MT_LMAC_BCN0,
+ MT_LMAC_PSMP0,
+};
+
+#define MT_CT_PARSE_LEN 72
+#define MT_CT_DMA_BUF_NUM 2
+
+#define MT_RXD0_LENGTH GENMASK(15, 0)
+#define MT_RXD0_PKT_FLAG GENMASK(19, 16)
+#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
+
+#define MT_RXD0_MESH BIT(18)
+#define MT_RXD0_MHCP BIT(19)
+#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
+#define MT_RXD0_NORMAL_IP_SUM BIT(23)
+#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
+
+#define MT_RXD0_SW_PKT_TYPE_MASK GENMASK(31, 16)
+#define MT_RXD0_SW_PKT_TYPE_MAP 0x380F
+#define MT_RXD0_SW_PKT_TYPE_FRAME 0x3801
+
+/* RXD DW1 */
+#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(11, 0)
+#define MT_RXD1_NORMAL_GROUP_1 BIT(16)
+#define MT_RXD1_NORMAL_GROUP_2 BIT(17)
+#define MT_RXD1_NORMAL_GROUP_3 BIT(18)
+#define MT_RXD1_NORMAL_GROUP_4 BIT(19)
+#define MT_RXD1_NORMAL_GROUP_5 BIT(20)
+#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21)
+#define MT_RXD1_NORMAL_CM BIT(23)
+#define MT_RXD1_NORMAL_CLM BIT(24)
+#define MT_RXD1_NORMAL_ICV_ERR BIT(25)
+#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26)
+#define MT_RXD1_NORMAL_BAND_IDX GENMASK(28, 27)
+#define MT_RXD1_NORMAL_SPP_EN BIT(29)
+#define MT_RXD1_NORMAL_ADD_OM BIT(30)
+#define MT_RXD1_NORMAL_SEC_DONE BIT(31)
+
+/* RXD DW2 */
+#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0)
+#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8)
+#define MT_RXD2_NORMAL_HDR_TRANS BIT(7)
+#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 13)
+#define MT_RXD2_NORMAL_SEC_MODE GENMASK(20, 16)
+#define MT_RXD2_NORMAL_MU_BAR BIT(21)
+#define MT_RXD2_NORMAL_SW_BIT BIT(22)
+#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23)
+#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24)
+#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25)
+#define MT_RXD2_NORMAL_INT_FRAME BIT(26)
+#define MT_RXD2_NORMAL_FRAG BIT(27)
+#define MT_RXD2_NORMAL_NULL_FRAME BIT(28)
+#define MT_RXD2_NORMAL_NDATA BIT(29)
+#define MT_RXD2_NORMAL_NON_AMPDU BIT(30)
+#define MT_RXD2_NORMAL_BF_REPORT BIT(31)
+
+/* RXD DW3 */
+#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0)
+#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8)
+#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16)
+#define MT_RXD3_NORMAL_U2M BIT(0)
+#define MT_RXD3_NORMAL_HTC_VLD BIT(18)
+#define MT_RXD3_NORMAL_BEACON_MC BIT(20)
+#define MT_RXD3_NORMAL_BEACON_UC BIT(21)
+#define MT_RXD3_NORMAL_CO_ANT BIT(22)
+#define MT_RXD3_NORMAL_FCS_ERR BIT(24)
+#define MT_RXD3_NORMAL_VLAN2ETH BIT(31)
+
+/* RXD DW4 */
+#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0)
+#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0)
+#define MT_RXD4_MID_AMSDU_FRAME BIT(1)
+#define MT_RXD4_LAST_AMSDU_FRAME BIT(0)
+
+#define MT_RXV_HDR_BAND_IDX BIT(24)
+
+/* RXD GROUP4 */
+#define MT_RXD8_FRAME_CONTROL GENMASK(15, 0)
+
+#define MT_RXD10_SEQ_CTRL GENMASK(15, 0)
+#define MT_RXD10_QOS_CTL GENMASK(31, 16)
+
+#define MT_RXD11_HT_CONTROL GENMASK(31, 0)
+
+/* P-RXV */
+#define MT_PRXV_TX_RATE GENMASK(6, 0)
+#define MT_PRXV_TX_DCM BIT(4)
+#define MT_PRXV_TX_ER_SU_106T BIT(5)
+#define MT_PRXV_NSTS GENMASK(10, 7)
+#define MT_PRXV_TXBF BIT(11)
+#define MT_PRXV_HT_AD_CODE BIT(12)
+#define MT_PRXV_HE_RU_ALLOC GENMASK(30, 22)
+#define MT_PRXV_RCPI3 GENMASK(31, 24)
+#define MT_PRXV_RCPI2 GENMASK(23, 16)
+#define MT_PRXV_RCPI1 GENMASK(15, 8)
+#define MT_PRXV_RCPI0 GENMASK(7, 0)
+#define MT_PRXV_HT_SHORT_GI GENMASK(4, 3)
+#define MT_PRXV_HT_STBC GENMASK(10, 9)
+#define MT_PRXV_TX_MODE GENMASK(14, 11)
+#define MT_PRXV_FRAME_MODE GENMASK(2, 0)
+#define MT_PRXV_DCM BIT(5)
+
+/* C-RXV */
+#define MT_CRXV_HE_NUM_USER GENMASK(26, 20)
+#define MT_CRXV_HE_LTF_SIZE GENMASK(28, 27)
+#define MT_CRXV_HE_LDPC_EXT_SYM BIT(30)
+
+#define MT_CRXV_HE_PE_DISAMBIG BIT(1)
+#define MT_CRXV_HE_UPLINK BIT(2)
+
+#define MT_CRXV_HE_MU_AID GENMASK(27, 17)
+#define MT_CRXV_HE_BEAM_CHNG BIT(29)
+
+#define MT_CRXV_HE_DOPPLER BIT(0)
+#define MT_CRXV_HE_BSS_COLOR GENMASK(15, 10)
+#define MT_CRXV_HE_TXOP_DUR GENMASK(19, 17)
+
+#define MT_CRXV_HE_SR_MASK GENMASK(11, 8)
+#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12)
+#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17)
+#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21)
+
+#define MT_CRXV_HE_RU0 GENMASK(8, 0)
+#define MT_CRXV_HE_RU1 GENMASK(17, 9)
+#define MT_CRXV_HE_RU2 GENMASK(26, 18)
+#define MT_CRXV_HE_RU3_L GENMASK(31, 27)
+#define MT_CRXV_HE_RU3_H GENMASK(3, 0)
+
+enum tx_header_format {
+ MT_HDR_FORMAT_802_3,
+ MT_HDR_FORMAT_CMD,
+ MT_HDR_FORMAT_802_11,
+ MT_HDR_FORMAT_802_11_EXT,
+};
+
+enum tx_pkt_type {
+ MT_TX_TYPE_CT,
+ MT_TX_TYPE_SF,
+ MT_TX_TYPE_CMD,
+ MT_TX_TYPE_FW,
+};
+
+enum tx_port_idx {
+ MT_TX_PORT_IDX_LMAC,
+ MT_TX_PORT_IDX_MCU
+};
+
+enum tx_mcu_port_q_idx {
+ MT_TX_MCU_PORT_RX_Q0 = 0x20,
+ MT_TX_MCU_PORT_RX_Q1,
+ MT_TX_MCU_PORT_RX_Q2,
+ MT_TX_MCU_PORT_RX_Q3,
+ MT_TX_MCU_PORT_RX_FWDL = 0x3e
+};
+
+enum tx_mgnt_type {
+ MT_TX_NORMAL,
+ MT_TX_TIMING,
+ MT_TX_ADDBA,
+};
+
+#define MT_CT_INFO_APPLY_TXD BIT(0)
+#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1)
+#define MT_CT_INFO_MGMT_FRAME BIT(2)
+#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3)
+#define MT_CT_INFO_HSR2_TX BIT(4)
+#define MT_CT_INFO_FROM_HOST BIT(7)
+
+#define MT_TXD_SIZE (8 * 4)
+
+#define MT_TXD0_Q_IDX GENMASK(31, 25)
+#define MT_TXD0_PKT_FMT GENMASK(24, 23)
+#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
+#define MT_TXD0_TX_BYTES GENMASK(15, 0)
+
+#define MT_TXD1_FIXED_RATE BIT(31)
+#define MT_TXD1_OWN_MAC GENMASK(30, 25)
+#define MT_TXD1_TID GENMASK(24, 21)
+#define MT_TXD1_BIP BIT(24)
+#define MT_TXD1_ETH_802_3 BIT(20)
+#define MT_TXD1_HDR_INFO GENMASK(20, 16)
+#define MT_TXD1_HDR_FORMAT GENMASK(15, 14)
+#define MT_TXD1_TGID GENMASK(13, 12)
+#define MT_TXD1_WLAN_IDX GENMASK(11, 0)
+
+#define MT_TXD2_POWER_OFFSET GENMASK(31, 26)
+#define MT_TXD2_MAX_TX_TIME GENMASK(25, 16)
+#define MT_TXD2_FRAG GENMASK(15, 14)
+#define MT_TXD2_HTC_VLD BIT(13)
+#define MT_TXD2_DURATION BIT(12)
+#define MT_TXD2_HDR_PAD GENMASK(11, 10)
+#define MT_TXD2_RTS BIT(9)
+#define MT_TXD2_OWN_MAC_MAP BIT(8)
+#define MT_TXD2_BF_TYPE GENMASK(6, 7)
+#define MT_TXD2_FRAME_TYPE GENMASK(5, 4)
+#define MT_TXD2_SUB_TYPE GENMASK(3, 0)
+
+#define MT_TXD3_SN_VALID BIT(31)
+#define MT_TXD3_PN_VALID BIT(30)
+#define MT_TXD3_SW_POWER_MGMT BIT(29)
+#define MT_TXD3_BA_DISABLE BIT(28)
+#define MT_TXD3_SEQ GENMASK(27, 16)
+#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11)
+#define MT_TXD3_TX_COUNT GENMASK(10, 6)
+#define MT_TXD3_HW_AMSDU BIT(5)
+#define MT_TXD3_BCM BIT(4)
+#define MT_TXD3_EEOSP BIT(3)
+#define MT_TXD3_EMRD BIT(2)
+#define MT_TXD3_PROTECT_FRAME BIT(1)
+#define MT_TXD3_NO_ACK BIT(0)
+
+#define MT_TXD4_PN_LOW GENMASK(31, 0)
+
+#define MT_TXD5_PN_HIGH GENMASK(31, 16)
+#define MT_TXD5_FL BIT(15)
+#define MT_TXD5_BYPASS_TBB BIT(14)
+#define MT_TXD5_BYPASS_RBB BIT(13)
+#define MT_TXD5_BSS_COLOR_ZERO BIT(12)
+#define MT_TXD5_TX_STATUS_HOST BIT(10)
+#define MT_TXD5_TX_STATUS_MCU BIT(9)
+#define MT_TXD5_TX_STATUS_FMT BIT(8)
+#define MT_TXD5_PID GENMASK(7, 0)
+
+#define MT_TXD6_TX_SRC GENMASK(31, 30)
+#define MT_TXD6_VTA BIT(28)
+#define MT_TXD6_BW GENMASK(25, 22)
+#define MT_TXD6_TX_RATE GENMASK(21, 16)
+#define MT_TXD6_TIMESTAMP_OFS_EN BIT(15)
+#define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10)
+#define MT_TXD6_MSDU_CNT GENMASK(9, 4)
+#define MT_TXD6_DIS_MAT BIT(3)
+#define MT_TXD6_DAS BIT(2)
+#define MT_TXD6_AMSDU_CAP BIT(1)
+
+#define MT_TXD7_TXD_LEN GENMASK(31, 30)
+#define MT_TXD7_IP_SUM BIT(29)
+#define MT_TXD7_DROP_BY_SDO BIT(28)
+#define MT_TXD7_MAC_TXD BIT(27)
+#define MT_TXD7_CTXD BIT(26)
+#define MT_TXD7_CTXD_CNT GENMASK(25, 22)
+#define MT_TXD7_UDP_TCP_SUM BIT(15)
+#define MT_TXD7_TX_TIME GENMASK(9, 0)
+
+#define MT_TX_RATE_STBC BIT(14)
+#define MT_TX_RATE_NSS GENMASK(13, 10)
+#define MT_TX_RATE_MODE GENMASK(9, 6)
+#define MT_TX_RATE_SU_EXT_TONE BIT(5)
+#define MT_TX_RATE_DCM BIT(4)
+/* VHT/HE only use bits 0-3 */
+#define MT_TX_RATE_IDX GENMASK(5, 0)
+
+#define MT_TXFREE0_PKT_TYPE GENMASK(31, 27)
+#define MT_TXFREE0_MSDU_CNT GENMASK(25, 16)
+#define MT_TXFREE0_RX_BYTE GENMASK(15, 0)
+
+#define MT_TXFREE1_VER GENMASK(18, 16)
+
+#define MT_TXFREE_INFO_PAIR BIT(31)
+#define MT_TXFREE_INFO_HEADER BIT(30)
+#define MT_TXFREE_INFO_WLAN_ID GENMASK(23, 12)
+#define MT_TXFREE_INFO_MSDU_ID GENMASK(14, 0)
+#define MT_TXFREE_INFO_COUNT GENMASK(27, 24)
+#define MT_TXFREE_INFO_STAT GENMASK(29, 28)
+
+#define MT_TXS0_BW GENMASK(31, 29)
+#define MT_TXS0_TID GENMASK(28, 26)
+#define MT_TXS0_AMPDU BIT(25)
+#define MT_TXS0_TXS_FORMAT GENMASK(24, 23)
+#define MT_TXS0_BA_ERROR BIT(22)
+#define MT_TXS0_PS_FLAG BIT(21)
+#define MT_TXS0_TXOP_TIMEOUT BIT(20)
+#define MT_TXS0_BIP_ERROR BIT(19)
+
+#define MT_TXS0_QUEUE_TIMEOUT BIT(18)
+#define MT_TXS0_RTS_TIMEOUT BIT(17)
+#define MT_TXS0_ACK_TIMEOUT BIT(16)
+#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
+
+#define MT_TXS0_TX_STATUS_HOST BIT(15)
+#define MT_TXS0_TX_STATUS_MCU BIT(14)
+#define MT_TXS0_TX_RATE GENMASK(13, 0)
+
+#define MT_TXS1_SEQNO GENMASK(31, 20)
+#define MT_TXS1_RESP_RATE GENMASK(19, 16)
+#define MT_TXS1_RXV_SEQNO GENMASK(15, 8)
+#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0)
+
+#define MT_TXS2_BF_STATUS GENMASK(31, 30)
+#define MT_TXS2_BAND GENMASK(29, 28)
+#define MT_TXS2_WCID GENMASK(27, 16)
+#define MT_TXS2_TX_DELAY GENMASK(15, 0)
+
+#define MT_TXS3_PID GENMASK(31, 24)
+#define MT_TXS3_RATE_STBC BIT(7)
+#define MT_TXS3_FIXED_RATE BIT(6)
+#define MT_TXS3_SRC GENMASK(5, 4)
+#define MT_TXS3_SHARED_ANTENNA BIT(3)
+#define MT_TXS3_LAST_TX_RATE GENMASK(2, 0)
+
+#define MT_TXS4_TIMESTAMP GENMASK(31, 0)
+
+#define MT_TXS5_F0_FINAL_MPDU BIT(31)
+#define MT_TXS5_F0_QOS BIT(30)
+#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25)
+#define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0)
+#define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24)
+#define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0)
+
+#define MT_TXS6_F0_NOISE_3 GENMASK(31, 24)
+#define MT_TXS6_F0_NOISE_2 GENMASK(23, 16)
+#define MT_TXS6_F0_NOISE_1 GENMASK(15, 8)
+#define MT_TXS6_F0_NOISE_0 GENMASK(7, 0)
+#define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24)
+#define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0)
+
+#define MT_TXS7_F0_RCPI_3 GENMASK(31, 24)
+#define MT_TXS7_F0_RCPI_2 GENMASK(23, 16)
+#define MT_TXS7_F0_RCPI_1 GENMASK(15, 8)
+#define MT_TXS7_F0_RCPI_0 GENMASK(7, 0)
+#define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24)
+#define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0)
+
+#endif /* __MT76_CONNAC3_MAC_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index d39a3cc5e381..ee5177fd6dde 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -495,6 +495,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
BSS_CHANGED_BEACON_ENABLED));
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
BSS_CHANGED_FILS_DISCOVERY));
+ bool amsdu_en = wcid->amsdu;
if (vif) {
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
@@ -521,9 +522,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
- /* counting non-offloading skbs */
- wcid->stats.tx_bytes += skb->len;
- wcid->stats.tx_packets++;
+ /* mt7915 WA only counts WED path */
+ if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed))
+ wcid->stats.tx_packets++;
}
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
@@ -554,12 +555,14 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[4] = 0;
val = FIELD_PREP(MT_TXD5_PID, pid);
- if (pid >= MT_PACKET_ID_FIRST)
+ if (pid >= MT_PACKET_ID_FIRST) {
val |= MT_TXD5_TX_STATUS_HOST;
+ amsdu_en = amsdu_en && !is_mt7921(dev);
+ }
txwi[5] = cpu_to_le32(val);
txwi[6] = 0;
- txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
+ txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
if (is_8023)
mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid);
@@ -606,12 +609,11 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
txs = le32_to_cpu(txs_data[0]);
/* PPDU based reporting */
- if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
stats->tx_bytes +=
le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) -
le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE);
- stats->tx_packets +=
- le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT);
stats->tx_failed +=
le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
stats->tx_retries +=
@@ -729,17 +731,15 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- bool noacked = !(info->flags & IEEE80211_TX_STAT_ACK);
if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK))
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ampdu_len = 1;
- info->status.ampdu_ack_len = !noacked;
+ info->status.ampdu_ack_len =
+ !!(info->flags & IEEE80211_TX_STAT_ACK);
info->status.rates[0].idx = -1;
- wcid->stats.tx_failed += noacked;
-
mt76_connac2_mac_fill_txs(dev, wcid, txs_data);
mt76_tx_status_skb_done(dev, skb, &list);
}
@@ -1112,3 +1112,85 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
return 0;
}
EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate);
+
+void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
+{
+ struct mt76_wcid *wcid;
+ u16 fc, tid;
+ u32 val;
+
+ if (!sta ||
+ !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
+ return;
+
+ tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+ if (tid >= 6) /* skip VO queue */
+ return;
+
+ val = le32_to_cpu(txwi[2]);
+ fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+ FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+ if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
+ return;
+
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+ if (!test_and_set_bit(tid, &wcid->ampdu_state))
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+}
+EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);
+
+void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
+ struct ieee80211_sta *sta,
+ struct list_head *free_list)
+{
+ struct mt76_wcid *wcid;
+ __le32 *txwi;
+ u16 wcid_idx;
+
+ mt76_connac_txp_skb_unmap(dev, t);
+ if (!t->skb)
+ goto out;
+
+ txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
+ if (sta) {
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+ wcid_idx = wcid->idx;
+ } else {
+ wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+ wcid = rcu_dereference(dev->wcid[wcid_idx]);
+
+ if (wcid && wcid->sta) {
+ sta = container_of((void *)wcid, struct ieee80211_sta,
+ drv_priv);
+ spin_lock_bh(&dev->sta_poll_lock);
+ if (list_empty(&wcid->poll_list))
+ list_add_tail(&wcid->poll_list,
+ &dev->sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+ }
+ }
+
+ if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ mt76_connac2_tx_check_aggr(sta, txwi);
+
+ __mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
+out:
+ t->skb = NULL;
+ mt76_put_txwi(dev, t);
+}
+EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free);
+
+void mt76_connac2_tx_token_put(struct mt76_dev *dev)
+{
+ struct mt76_txwi_cache *txwi;
+ int id;
+
+ spin_lock_bh(&dev->token_lock);
+ idr_for_each_entry(&dev->token, txwi, id) {
+ mt76_connac2_txwi_free(dev, txwi, NULL, NULL);
+ dev->token_count--;
+ }
+ spin_unlock_bh(&dev->token_lock);
+ idr_destroy(&dev->token);
+}
+EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index ca1ce97a6d2f..4543e5bf0482 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -22,6 +22,7 @@
#define FW_START_OVERRIDE BIT(0)
#define FW_START_WORKING_PDA_CR4 BIT(2)
+#define FW_START_WORKING_PDA_DSP BIT(3)
#define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0)
#define PATCH_SEC_TYPE_MASK GENMASK(15, 0)
@@ -518,7 +519,8 @@ struct sta_rec_muru {
u8 uo_ra;
u8 he_2x996_tone;
u8 rx_t_frame_11ac;
- u8 rsv[3];
+ u8 rx_ctrl_frame_to_mbss;
+ u8 rsv[2];
} ofdma_ul;
struct {
@@ -998,6 +1000,7 @@ enum {
MCU_EXT_EVENT_ASSERT_DUMP = 0x23,
MCU_EXT_EVENT_RDD_REPORT = 0x3a,
MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
+ MCU_EXT_EVENT_WA_TX_STAT = 0x74,
MCU_EXT_EVENT_BCC_NOTIFY = 0x75,
MCU_EXT_EVENT_MURU_CTRL = 0x9f,
};
@@ -1287,6 +1290,7 @@ enum {
UNI_BSS_INFO_UAPSD = 19,
UNI_BSS_INFO_PS = 21,
UNI_BSS_INFO_BCNFT = 22,
+ UNI_BSS_INFO_IFS_TIME = 23,
UNI_BSS_INFO_OFFLOAD = 25,
UNI_BSS_INFO_MLD = 26,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
index 7c88ed8b8f1e..3ed888782a70 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
@@ -10,7 +10,7 @@ config MT76x0U
depends on MAC80211
depends on USB
help
- This adds support for MT7610U-based wireless USB 2.0 dongles,
+ This adds support for MT7610U-based USB 2.0 wireless dongles,
which comply with IEEE 802.11ac standards and support 1x1
433Mbps PHY rate.
@@ -22,7 +22,7 @@ config MT76x0E
depends on MAC80211
depends on PCI
help
- This adds support for MT7610/MT7630-based wireless PCIe devices,
+ This adds support for MT7610/MT7630-based PCIe wireless devices,
which comply with IEEE 802.11ac standards and support 1x1
433Mbps PHY rate.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 3e41d809ade3..d5db6ffd6d36 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -853,7 +853,8 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
if (WARN_ON_ONCE(len > skb->len))
return -EINVAL;
- pskb_trim(skb, len);
+ if (pskb_trim(skb, len))
+ return -EINVAL;
status->chains = BIT(0);
signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h
index 6a98092e996b..11d119cd0f6f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h
@@ -14,7 +14,7 @@
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \
wiphy_name(mt76_hw(dev)->wiphy), MAXNAME)
#define DEV_PR_FMT "%s"
#define DEV_PR_ARG __entry->wiphy_name
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
index 5fd4973e32df..482a32b70ddf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
@@ -9,7 +9,7 @@ config MT76x2E
depends on MAC80211
depends on PCI
help
- This adds support for MT7612/MT7602/MT7662-based wireless PCIe
+ This adds support for MT7612/MT7602/MT7662-based PCIe wireless
devices, which comply with IEEE 802.11ac standards and support
2SS to 866Mbit/s PHY rate.
@@ -22,7 +22,7 @@ config MT76x2U
depends on MAC80211
depends on USB
help
- This adds support for MT7612U-based wireless USB 3.0 dongles,
+ This adds support for MT7612U-based USB 3.0 wireless dongles,
which comply with IEEE 802.11ac standards and support 2SS to
866Mbit/s PHY rate.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
index d710726d47bf..193112c49bd1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
@@ -7,19 +7,19 @@ config MT7915E
depends on PCI
select RELAY
help
- This adds support for MT7915-based wireless PCIe devices,
+ This adds support for MT7915-based PCIe wireless devices,
which support concurrent dual-band operation at both 5GHz
and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels,
OFDMA, spatial reuse and dual carrier modulation.
To compile this driver as a module, choose M here.
-config MT7986_WMAC
- bool "MT7986 (SoC) WMAC support"
+config MT798X_WMAC
+ bool "MT798x (SoC) WMAC support"
depends on MT7915E
depends on ARCH_MEDIATEK || COMPILE_TEST
select REGMAP
help
- This adds support for the built-in WMAC on MT7986 SoC device
+ This adds support for the built-in WMAC on MT7981 and MT7986 SoC device
which has the same feature set as a MT7915, but enables 6E
support.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
index 797ae49805c3..e0ca638c91a5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
@@ -6,5 +6,5 @@ mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o mmio.o
mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o
-mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
+mt7915e-$(CONFIG_MT798X_WMAC) += soc.o
mt7915e-$(CONFIG_DEV_COREDUMP) += coredump.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c
index d097a56dd33d..5daf2258dfe6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c
@@ -52,7 +52,7 @@ static const struct mt7915_mem_region mt7916_mem_regions[] = {
},
};
-static const struct mt7915_mem_region mt7986_mem_regions[] = {
+static const struct mt7915_mem_region mt798x_mem_regions[] = {
{
.start = 0x00800000,
.len = 0x0005ffff,
@@ -92,9 +92,10 @@ mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num)
case 0x7915:
*num = ARRAY_SIZE(mt7915_mem_regions);
return &mt7915_mem_regions[0];
+ case 0x7981:
case 0x7986:
- *num = ARRAY_SIZE(mt7986_mem_regions);
- return &mt7986_mem_regions[0];
+ *num = ARRAY_SIZE(mt798x_mem_regions);
+ return &mt798x_mem_regions[0];
case 0x7916:
*num = ARRAY_SIZE(mt7916_mem_regions);
return &mt7916_mem_regions[0];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 879884ead660..6c3696c8c700 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -251,7 +251,6 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
{
struct mt7915_phy *phy = file->private;
struct mt7915_dev *dev = phy->dev;
- struct mt7915_mcu_muru_stats mu_stats = {};
static const char * const dl_non_he_type[] = {
"CCK", "OFDM", "HT MIX", "HT GF",
"VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
@@ -275,7 +274,7 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
mutex_lock(&dev->mt76.mutex);
- ret = mt7915_mcu_muru_debug_get(phy, &mu_stats);
+ ret = mt7915_mcu_muru_debug_get(phy);
if (ret)
goto exit;
@@ -285,14 +284,13 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
for (i = 0; i < 5; i++)
seq_printf(file, "%8s | ", dl_non_he_type[i]);
-#define __dl_u32(s) le32_to_cpu(mu_stats.dl.s)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",
- __dl_u32(cck_cnt),
- __dl_u32(ofdm_cnt),
- __dl_u32(htmix_cnt),
- __dl_u32(htgf_cnt),
- __dl_u32(vht_su_cnt));
+ phy->mib.dl_cck_cnt,
+ phy->mib.dl_ofdm_cnt,
+ phy->mib.dl_htmix_cnt,
+ phy->mib.dl_htgf_cnt,
+ phy->mib.dl_vht_su_cnt);
seq_puts(file, "\nDownlink MU-MIMO\nData Type: ");
@@ -301,23 +299,23 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | ",
- __dl_u32(vht_2mu_cnt),
- __dl_u32(vht_3mu_cnt),
- __dl_u32(vht_4mu_cnt));
+ phy->mib.dl_vht_2mu_cnt,
+ phy->mib.dl_vht_3mu_cnt,
+ phy->mib.dl_vht_4mu_cnt);
- sub_total_cnt = __dl_u32(vht_2mu_cnt) +
- __dl_u32(vht_3mu_cnt) +
- __dl_u32(vht_4mu_cnt);
+ sub_total_cnt = phy->mib.dl_vht_2mu_cnt +
+ phy->mib.dl_vht_3mu_cnt +
+ phy->mib.dl_vht_4mu_cnt;
seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
sub_total_cnt);
total_ppdu_cnt = sub_total_cnt +
- __dl_u32(cck_cnt) +
- __dl_u32(ofdm_cnt) +
- __dl_u32(htmix_cnt) +
- __dl_u32(htgf_cnt) +
- __dl_u32(vht_su_cnt);
+ phy->mib.dl_cck_cnt +
+ phy->mib.dl_ofdm_cnt +
+ phy->mib.dl_htmix_cnt +
+ phy->mib.dl_htgf_cnt +
+ phy->mib.dl_vht_su_cnt;
seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
@@ -329,8 +327,7 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | ",
- __dl_u32(he_su_cnt),
- __dl_u32(he_ext_su_cnt));
+ phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);
seq_puts(file, "\nDownlink MU-MIMO\nData Type: ");
@@ -339,9 +336,8 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | ",
- __dl_u32(he_2mu_cnt),
- __dl_u32(he_3mu_cnt),
- __dl_u32(he_4mu_cnt));
+ phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,
+ phy->mib.dl_he_4mu_cnt);
seq_puts(file, "\nDownlink OFDMA\nData Type: ");
@@ -350,37 +346,35 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",
- __dl_u32(he_2ru_cnt),
- __dl_u32(he_3ru_cnt),
- __dl_u32(he_4ru_cnt),
- __dl_u32(he_5to8ru_cnt),
- __dl_u32(he_9to16ru_cnt),
- __dl_u32(he_gtr16ru_cnt));
-
- sub_total_cnt = __dl_u32(he_2mu_cnt) +
- __dl_u32(he_3mu_cnt) +
- __dl_u32(he_4mu_cnt);
+ phy->mib.dl_he_2ru_cnt,
+ phy->mib.dl_he_3ru_cnt,
+ phy->mib.dl_he_4ru_cnt,
+ phy->mib.dl_he_5to8ru_cnt,
+ phy->mib.dl_he_9to16ru_cnt,
+ phy->mib.dl_he_gtr16ru_cnt);
+
+ sub_total_cnt = phy->mib.dl_he_2mu_cnt +
+ phy->mib.dl_he_3mu_cnt +
+ phy->mib.dl_he_4mu_cnt;
total_ppdu_cnt = sub_total_cnt;
seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",
sub_total_cnt);
- sub_total_cnt = __dl_u32(he_2ru_cnt) +
- __dl_u32(he_3ru_cnt) +
- __dl_u32(he_4ru_cnt) +
- __dl_u32(he_5to8ru_cnt) +
- __dl_u32(he_9to16ru_cnt) +
- __dl_u32(he_gtr16ru_cnt);
+ sub_total_cnt = phy->mib.dl_he_2ru_cnt +
+ phy->mib.dl_he_3ru_cnt +
+ phy->mib.dl_he_4ru_cnt +
+ phy->mib.dl_he_5to8ru_cnt +
+ phy->mib.dl_he_9to16ru_cnt +
+ phy->mib.dl_he_gtr16ru_cnt;
total_ppdu_cnt += sub_total_cnt;
seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",
sub_total_cnt);
- total_ppdu_cnt += __dl_u32(he_su_cnt) +
- __dl_u32(he_ext_su_cnt);
+ total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt;
seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
-#undef __dl_u32
/* HE Uplink */
seq_puts(file, "\n\nUplink");
@@ -389,12 +383,11 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
for (i = 0; i < 3; i++)
seq_printf(file, "%8s | ", ul_he_type[i]);
-#define __ul_u32(s) le32_to_cpu(mu_stats.ul.s)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | ",
- __ul_u32(hetrig_2mu_cnt),
- __ul_u32(hetrig_3mu_cnt),
- __ul_u32(hetrig_4mu_cnt));
+ phy->mib.ul_hetrig_2mu_cnt,
+ phy->mib.ul_hetrig_3mu_cnt,
+ phy->mib.ul_hetrig_4mu_cnt);
seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type: ");
@@ -403,37 +396,36 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
seq_puts(file, "\nTotal Count:");
seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u | %7u | ",
- __ul_u32(hetrig_su_cnt),
- __ul_u32(hetrig_2ru_cnt),
- __ul_u32(hetrig_3ru_cnt),
- __ul_u32(hetrig_4ru_cnt),
- __ul_u32(hetrig_5to8ru_cnt),
- __ul_u32(hetrig_9to16ru_cnt),
- __ul_u32(hetrig_gtr16ru_cnt));
-
- sub_total_cnt = __ul_u32(hetrig_2mu_cnt) +
- __ul_u32(hetrig_3mu_cnt) +
- __ul_u32(hetrig_4mu_cnt);
+ phy->mib.ul_hetrig_su_cnt,
+ phy->mib.ul_hetrig_2ru_cnt,
+ phy->mib.ul_hetrig_3ru_cnt,
+ phy->mib.ul_hetrig_4ru_cnt,
+ phy->mib.ul_hetrig_5to8ru_cnt,
+ phy->mib.ul_hetrig_9to16ru_cnt,
+ phy->mib.ul_hetrig_gtr16ru_cnt);
+
+ sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt +
+ phy->mib.ul_hetrig_3mu_cnt +
+ phy->mib.ul_hetrig_4mu_cnt;
total_ppdu_cnt = sub_total_cnt;
seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
sub_total_cnt);
- sub_total_cnt = __ul_u32(hetrig_2ru_cnt) +
- __ul_u32(hetrig_3ru_cnt) +
- __ul_u32(hetrig_4ru_cnt) +
- __ul_u32(hetrig_5to8ru_cnt) +
- __ul_u32(hetrig_9to16ru_cnt) +
- __ul_u32(hetrig_gtr16ru_cnt);
+ sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt +
+ phy->mib.ul_hetrig_3ru_cnt +
+ phy->mib.ul_hetrig_4ru_cnt +
+ phy->mib.ul_hetrig_5to8ru_cnt +
+ phy->mib.ul_hetrig_9to16ru_cnt +
+ phy->mib.ul_hetrig_gtr16ru_cnt;
total_ppdu_cnt += sub_total_cnt;
seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",
sub_total_cnt);
- total_ppdu_cnt += __ul_u32(hetrig_su_cnt);
+ total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;
seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
-#undef __ul_u32
exit:
mutex_unlock(&dev->mt76.mutex);
@@ -719,10 +711,10 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
static void
mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
{
+ struct mt76_mib_stats *mib = &phy->mib;
static const char * const bw[] = {
"BW20", "BW40", "BW80", "BW160"
};
- struct mib_stats *mib = &phy->mib;
/* Tx Beamformer monitor */
seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
@@ -768,7 +760,7 @@ mt7915_tx_stats_show(struct seq_file *file, void *data)
{
struct mt7915_phy *phy = file->private;
struct mt7915_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
+ struct mt76_mib_stats *mib = &phy->mib;
int i;
mutex_lock(&dev->mt76.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 43a5456d4b97..59a44d79aaed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -11,7 +11,7 @@ mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base
struct mt7915_dev *dev = phy->dev;
if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
- if (is_mt7986(&dev->mt76))
+ if (is_mt798x(&dev->mt76))
ring_base += MT_TXQ_ID(0) * MT_RING_SIZE;
else
ring_base = MT_WED_TX_RING_BASE;
@@ -250,7 +250,7 @@ static void mt7915_dma_disable(struct mt7915_dev *dev, bool rst)
}
}
-static int mt7915_dma_enable(struct mt7915_dev *dev)
+int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset)
{
struct mt76_dev *mdev = &dev->mt76;
u32 hif1_ofs = 0;
@@ -259,6 +259,84 @@ static int mt7915_dma_enable(struct mt7915_dev *dev)
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+ /* enable wpdma tx/rx */
+ if (!reset) {
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ if (is_mt7915(mdev))
+ mt76_set(dev, MT_WFDMA1_GLO_CFG,
+ MT_WFDMA1_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
+
+ if (dev->hif2) {
+ mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ if (is_mt7915(mdev))
+ mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
+ MT_WFDMA1_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
+
+ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+ MT_WFDMA_HOST_CONFIG_PDMA_BAND);
+ }
+ }
+
+ /* enable interrupts for TX/RX rings */
+ irq_mask = MT_INT_RX_DONE_MCU |
+ MT_INT_TX_DONE_MCU |
+ MT_INT_MCU_CMD;
+
+ if (!dev->phy.mt76->band_idx)
+ irq_mask |= MT_INT_BAND0_RX_DONE;
+
+ if (dev->dbdc_support || dev->phy.mt76->band_idx)
+ irq_mask |= MT_INT_BAND1_RX_DONE;
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) {
+ u32 wed_irq_mask = irq_mask;
+ int ret;
+
+ wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
+ if (!is_mt798x(&dev->mt76))
+ mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask);
+ else
+ mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
+
+ ret = mt7915_mcu_wed_enable_rx_stats(dev);
+ if (ret)
+ return ret;
+
+ mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask);
+ }
+
+ irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
+
+ mt7915_irq_enable(dev, irq_mask);
+ mt7915_irq_disable(dev, 0);
+
+ return 0;
+}
+
+static int mt7915_dma_enable(struct mt7915_dev *dev, bool reset)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 hif1_ofs = 0;
+
+ if (dev->hif2)
+ hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+
/* reset dma idx */
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
if (is_mt7915(mdev))
@@ -322,69 +400,7 @@ static int mt7915_dma_enable(struct mt7915_dev *dev)
mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
- /* set WFDMA Tx/Rx */
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- if (is_mt7915(mdev))
- mt76_set(dev, MT_WFDMA1_GLO_CFG,
- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
- MT_WFDMA1_GLO_CFG_RX_DMA_EN |
- MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
-
- if (dev->hif2) {
- mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- if (is_mt7915(mdev))
- mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
- MT_WFDMA1_GLO_CFG_RX_DMA_EN |
- MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
-
- mt76_set(dev, MT_WFDMA_HOST_CONFIG,
- MT_WFDMA_HOST_CONFIG_PDMA_BAND);
- }
-
- /* enable interrupts for TX/RX rings */
- irq_mask = MT_INT_RX_DONE_MCU |
- MT_INT_TX_DONE_MCU |
- MT_INT_MCU_CMD;
-
- if (!dev->phy.mt76->band_idx)
- irq_mask |= MT_INT_BAND0_RX_DONE;
-
- if (dev->dbdc_support || dev->phy.mt76->band_idx)
- irq_mask |= MT_INT_BAND1_RX_DONE;
-
- if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
- u32 wed_irq_mask = irq_mask;
- int ret;
-
- wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
- if (!is_mt7986(&dev->mt76))
- mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask);
- else
- mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
-
- ret = mt7915_mcu_wed_enable_rx_stats(dev);
- if (ret)
- return ret;
-
- mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask);
- }
-
- mt7915_irq_enable(dev, irq_mask);
-
- return 0;
+ return mt7915_dma_start(dev, reset, true);
}
int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
@@ -404,7 +420,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
mt7915_dma_disable(dev, true);
if (mtk_wed_device_active(&mdev->mmio.wed)) {
- if (!is_mt7986(mdev)) {
+ if (!is_mt798x(mdev)) {
u8 wed_control_rx1 = is_mt7915(mdev) ? 1 : 2;
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
@@ -560,7 +576,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
mt7915_poll_tx);
napi_enable(&dev->mt76.tx_napi);
- mt7915_dma_enable(dev);
+ mt7915_dma_enable(dev, false);
return 0;
}
@@ -642,7 +658,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP,
MT_WFDMA0_EXT0_RXWB_KEEP);
- mt7915_dma_enable(dev);
+ mt7915_dma_enable(dev, !force);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index a79628933948..76be7308460b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -39,6 +39,8 @@ static int mt7915_check_eeprom(struct mt7915_dev *dev)
return CHECK_EEPROM_ERR(is_mt7915(&dev->mt76));
case 0x7916:
return CHECK_EEPROM_ERR(is_mt7916(&dev->mt76));
+ case 0x7981:
+ return CHECK_EEPROM_ERR(is_mt7981(&dev->mt76));
case 0x7986:
return CHECK_EEPROM_ERR(is_mt7986(&dev->mt76));
default:
@@ -52,6 +54,9 @@ static char *mt7915_eeprom_name(struct mt7915_dev *dev)
case 0x7915:
return dev->dbdc_support ?
MT7915_EEPROM_DEFAULT_DBDC : MT7915_EEPROM_DEFAULT;
+ case 0x7981:
+ /* mt7981 only supports mt7976 and only in DBDC mode */
+ return MT7981_EEPROM_MT7976_DEFAULT_DBDC;
case 0x7986:
switch (mt7915_check_adie(dev, true)) {
case MT7976_ONE_ADIE_DBDC:
@@ -215,7 +220,7 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev,
eeprom[MT_EE_WIFI_CONF + 2 + band]);
}
- if (!is_mt7986(&dev->mt76))
+ if (!is_mt798x(&dev->mt76))
nss_max = 2;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index ac2049f49bb3..35fdf4f98d80 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -4,6 +4,7 @@
#include <linux/etherdevice.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/of.h>
#include <linux/thermal.h>
#include "mt7915.h"
#include "mac.h"
@@ -414,7 +415,6 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
if (!dev->dbdc_support)
vht_cap->cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
FIELD_PREP(IEEE80211_VHT_CAP_EXT_NSS_BW_MASK, 1);
} else {
vht_cap->cap |=
@@ -499,6 +499,12 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
+
+ /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
+ * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
+ */
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H);
}
static void
@@ -581,6 +587,8 @@ void mt7915_mac_init(struct mt7915_dev *dev)
if (!is_mt7915(&dev->mt76))
mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
+ else
+ mt76_clear(dev, MT_PLE_HOST_RPT0, MT_PLE_HOST_RPT0_TX_LATENCY);
/* enable hardware de-agg */
mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
@@ -732,7 +740,7 @@ void mt7915_wfsys_reset(struct mt7915_dev *dev)
mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE);
msleep(100);
- } else if (is_mt7986(&dev->mt76)) {
+ } else if (is_mt798x(&dev->mt76)) {
mt7986_wmac_disable(dev);
msleep(20);
@@ -753,7 +761,7 @@ static bool mt7915_band_config(struct mt7915_dev *dev)
dev->phy.mt76->band_idx = 0;
- if (is_mt7986(&dev->mt76)) {
+ if (is_mt798x(&dev->mt76)) {
u32 sku = mt7915_check_adie(dev, true);
/*
@@ -1158,11 +1166,11 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
static void mt7915_stop_hardware(struct mt7915_dev *dev)
{
mt7915_mcu_exit(dev);
- mt7915_tx_token_put(dev);
+ mt76_connac2_tx_token_put(&dev->mt76);
mt7915_dma_cleanup(dev);
tasklet_disable(&dev->mt76.irq_tasklet);
- if (is_mt7986(&dev->mt76))
+ if (is_mt798x(&dev->mt76))
mt7986_wmac_disable(dev);
}
@@ -1177,9 +1185,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
INIT_LIST_HEAD(&dev->sta_rc_list);
- INIT_LIST_HEAD(&dev->sta_poll_list);
INIT_LIST_HEAD(&dev->twt_list);
- spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 7df8d95fc3fb..b8b0c0fda752 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -105,9 +105,9 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
LIST_HEAD(sta_poll_list);
int i;
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&dev->sta_poll_list, &sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
rcu_read_lock();
@@ -118,15 +118,15 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
s8 rssi[4];
u8 bw;
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&sta_poll_list)) {
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
break;
}
msta = list_first_entry(&sta_poll_list,
- struct mt7915_sta, poll_list);
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ struct mt7915_sta, wcid.poll_list);
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
idx = msta->wcid.idx;
@@ -326,10 +326,11 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
if (status->wcid) {
msta = container_of(status->wcid, struct mt7915_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
status->freq = mphy->chandef.chan->center_freq;
@@ -842,74 +843,6 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
}
static void
-mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
-{
- struct mt7915_sta *msta;
- u16 fc, tid;
- u32 val;
-
- if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
- return;
-
- tid = le32_get_bits(txwi[1], MT_TXD1_TID);
- if (tid >= 6) /* skip VO queue */
- return;
-
- val = le32_to_cpu(txwi[2]);
- fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
- FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
- if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
- return;
-
- msta = (struct mt7915_sta *)sta->drv_priv;
- if (!test_and_set_bit(tid, &msta->ampdu_state))
- ieee80211_start_tx_ba_session(sta, tid, 0);
-}
-
-static void
-mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, struct list_head *free_list)
-{
- struct mt76_dev *mdev = &dev->mt76;
- struct mt7915_sta *msta;
- struct mt76_wcid *wcid;
- __le32 *txwi;
- u16 wcid_idx;
-
- mt76_connac_txp_skb_unmap(mdev, t);
- if (!t->skb)
- goto out;
-
- txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
- if (sta) {
- wcid = (struct mt76_wcid *)sta->drv_priv;
- wcid_idx = wcid->idx;
- } else {
- wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
- wcid = rcu_dereference(dev->mt76.wcid[wcid_idx]);
-
- if (wcid && wcid->sta) {
- msta = container_of(wcid, struct mt7915_sta, wcid);
- sta = container_of((void *)msta, struct ieee80211_sta,
- drv_priv);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
- }
- }
-
- if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7915_tx_check_aggr(sta, txwi);
-
- __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
-
-out:
- t->skb = NULL;
- mt76_put_txwi(mdev, t);
-}
-
-static void
mt7915_mac_tx_free_prepare(struct mt7915_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
@@ -951,6 +884,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
struct mt76_dev *mdev = &dev->mt76;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid = NULL;
LIST_HEAD(free_list);
void *end = data + len;
bool v3, wake = false;
@@ -977,7 +911,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
info = le32_to_cpu(*cur_info);
if (info & MT_TX_FREE_PAIR) {
struct mt7915_sta *msta;
- struct mt76_wcid *wcid;
u16 idx;
idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
@@ -987,14 +920,33 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
continue;
msta = container_of(wcid, struct mt7915_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &mdev->sta_poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
continue;
}
- if (v3 && (info & MT_TX_FREE_MPDU_HEADER))
+ if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) {
+ u32 tx_retries = 0, tx_failed = 0;
+
+ if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) {
+ tx_retries =
+ FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1;
+ tx_failed = tx_retries +
+ !!FIELD_GET(MT_TX_FREE_STAT_V3, info);
+ } else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) {
+ tx_retries =
+ FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
+ tx_failed = tx_retries +
+ !!FIELD_GET(MT_TX_FREE_STAT, info);
+ }
+ wcid->stats.tx_retries += tx_retries;
+ wcid->stats.tx_failed += tx_failed;
+ }
+
+ if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3))
continue;
for (i = 0; i < 1 + v3; i++) {
@@ -1010,7 +962,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
if (!txwi)
continue;
- mt7915_txwi_free(dev, txwi, sta, &free_list);
+ mt76_connac2_txwi_free(mdev, txwi, sta, &free_list);
}
}
@@ -1042,7 +994,7 @@ mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len)
if (!txwi)
continue;
- mt7915_txwi_free(dev, txwi, NULL, &free_list);
+ mt76_connac2_txwi_free(mdev, txwi, NULL, &free_list);
}
mt7915_mac_tx_free_done(dev, &free_list, wake);
@@ -1081,10 +1033,10 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
if (!wcid->sta)
goto out;
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
out:
rcu_read_unlock();
@@ -1357,20 +1309,6 @@ mt7915_update_beacons(struct mt7915_dev *dev)
mt7915_update_vif_beacon, mphy_ext->hw);
}
-void mt7915_tx_token_put(struct mt7915_dev *dev)
-{
- struct mt76_txwi_cache *txwi;
- int id;
-
- spin_lock_bh(&dev->mt76.token_lock);
- idr_for_each_entry(&dev->mt76.token, txwi, id) {
- mt7915_txwi_free(dev, txwi, NULL, NULL);
- dev->mt76.token_count--;
- }
- spin_unlock_bh(&dev->mt76.token_lock);
- idr_destroy(&dev->mt76.token);
-}
-
static int
mt7915_mac_restart(struct mt7915_dev *dev)
{
@@ -1389,8 +1327,12 @@ mt7915_mac_restart(struct mt7915_dev *dev)
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
- if (dev->hif2)
- mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
+ if (dev->hif2) {
+ if (is_mt7915(mdev))
+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
+ else
+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0x0);
+ }
}
set_bit(MT76_RESET, &dev->mphy.state);
@@ -1415,7 +1357,7 @@ mt7915_mac_restart(struct mt7915_dev *dev)
napi_disable(&dev->mt76.tx_napi);
/* token reinit */
- mt7915_tx_token_put(dev);
+ mt76_connac2_tx_token_put(&dev->mt76);
idr_init(&dev->mt76.token);
mt7915_dma_reset(dev, true);
@@ -1440,8 +1382,12 @@ mt7915_mac_restart(struct mt7915_dev *dev)
}
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
- if (dev->hif2)
- mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
+ if (dev->hif2) {
+ if (is_mt7915(mdev))
+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
+ else
+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff);
+ }
}
/* load firmware */
@@ -1576,7 +1522,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
mtk_wed_device_stop(&dev->mt76.mmio.wed);
- if (!is_mt7986(&dev->mt76))
+ if (!is_mt798x(&dev->mt76))
mt76_wr(dev, MT_INT_WED_MASK_CSR, 0);
}
@@ -1604,13 +1550,19 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7915_dma_reset(dev, false);
- mt7915_tx_token_put(dev);
+ mt76_connac2_tx_token_put(&dev->mt76);
idr_init(&dev->mt76.token);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
}
+ mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
+ mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
+
+ /* enable DMA Tx/Rx and interrupt */
+ mt7915_dma_start(dev, false, false);
+
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
if (phy2)
@@ -1625,9 +1577,6 @@ void mt7915_mac_reset_work(struct work_struct *work)
tasklet_schedule(&dev->mt76.irq_tasklet);
- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
- mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
-
mt76_worker_enable(&dev->mt76.tx_worker);
local_bh_disable();
@@ -1747,8 +1696,8 @@ void mt7915_reset(struct mt7915_dev *dev)
void mt7915_mac_update_stats(struct mt7915_phy *phy)
{
+ struct mt76_mib_stats *mib = &phy->mib;
struct mt7915_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
int i, aggr0 = 0, aggr1, cnt;
u8 band = phy->mt76->band_idx;
u32 val;
@@ -2010,7 +1959,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
u32 changed;
LIST_HEAD(list);
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
list_splice_init(&dev->sta_rc_list, &list);
while (!list_empty(&list)) {
@@ -2018,7 +1967,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
list_del_init(&msta->rc_list);
changed = msta->changed;
msta->changed = 0;
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
@@ -2031,10 +1980,10 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
if (changed & IEEE80211_RC_SMPS_CHANGED)
mt7915_mcu_add_smps(dev, vif, sta);
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
}
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
void mt7915_mac_work(struct work_struct *work)
@@ -2054,6 +2003,9 @@ void mt7915_mac_work(struct work_struct *work)
mt7915_mac_update_stats(phy);
mt7915_mac_severe_check(phy);
+
+ if (phy->dev->muru_debug)
+ mt7915_mcu_muru_debug_get(phy);
}
mutex_unlock(&mphy->dev->mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
index ce94f87e2042..448b1b380190 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
@@ -9,7 +9,12 @@
#define MT_TX_FREE_VER GENMASK(18, 16)
#define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0)
/* 0: success, others: dropped */
-#define MT_TX_FREE_MPDU_HEADER BIT(30)
+#define MT_TX_FREE_COUNT GENMASK(12, 0)
+#define MT_TX_FREE_COUNT_V3 GENMASK(27, 24)
+#define MT_TX_FREE_STAT GENMASK(14, 13)
+#define MT_TX_FREE_STAT_V3 GENMASK(29, 28)
+#define MT_TX_FREE_MPDU_HEADER BIT(15)
+#define MT_TX_FREE_MPDU_HEADER_V3 BIT(30)
#define MT_TX_FREE_MSDU_ID_V3 GENMASK(14, 0)
#define MT_TXS5_F0_FINAL_MPDU BIT(31)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 1b361199c061..8ebbf186fab2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -248,7 +248,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
idx = MT7915_WTBL_RESERVED - mvif->mt76.idx;
INIT_LIST_HEAD(&mvif->sta.rc_list);
- INIT_LIST_HEAD(&mvif->sta.poll_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.phy_idx = ext_phy;
mvif->sta.wcid.hw_key_idx = -1;
@@ -269,6 +269,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
mt7915_init_bitrate_mask(vif);
+ memset(&mvif->cap, -1, sizeof(mvif->cap));
mt7915_mcu_add_bss_info(phy, vif, true);
mt7915_mcu_add_sta(dev, vif, NULL, true);
@@ -308,10 +309,10 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
mutex_unlock(&dev->mt76.mutex);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_packet_id_flush(&dev->mt76, &msta->wcid);
}
@@ -470,7 +471,8 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw);
}
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
ret = mt7915_mcu_set_txpower_sku(phy);
if (ret)
return ret;
@@ -599,6 +601,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ int set_bss_info = -1, set_sta = -1;
mutex_lock(&dev->mt76.mutex);
@@ -607,15 +610,18 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
* and then peer references bss_info_rfch to set bandwidth cap.
*/
if (changed & BSS_CHANGED_BSSID &&
- vif->type == NL80211_IFTYPE_STATION) {
- bool join = !is_zero_ether_addr(info->bssid);
-
- mt7915_mcu_add_bss_info(phy, vif, join);
- mt7915_mcu_add_sta(dev, vif, NULL, join);
- }
-
+ vif->type == NL80211_IFTYPE_STATION)
+ set_bss_info = set_sta = !is_zero_ether_addr(info->bssid);
if (changed & BSS_CHANGED_ASSOC)
- mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc);
+ set_bss_info = vif->cfg.assoc;
+ if (changed & BSS_CHANGED_BEACON_ENABLED &&
+ vif->type != NL80211_IFTYPE_AP)
+ set_bss_info = set_sta = info->enable_beacon;
+
+ if (set_bss_info == 1)
+ mt7915_mcu_add_bss_info(phy, vif, true);
+ if (set_sta == 1)
+ mt7915_mcu_add_sta(dev, vif, NULL, true);
if (changed & BSS_CHANGED_ERP_CTS_PROT)
mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot);
@@ -629,11 +635,6 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
- mt7915_mcu_add_bss_info(phy, vif, true);
- mt7915_mcu_add_sta(dev, vif, NULL, true);
- }
-
/* ensure that enable txcmd_mode after bss_info */
if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
mt7915_mcu_set_tx(dev, vif);
@@ -650,6 +651,62 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
BSS_CHANGED_FILS_DISCOVERY))
mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed);
+ if (set_bss_info == 0)
+ mt7915_mcu_add_bss_info(phy, vif, false);
+ if (set_sta == 0)
+ mt7915_mcu_add_sta(dev, vif, NULL, false);
+
+ mutex_unlock(&dev->mt76.mutex);
+}
+
+static void
+mt7915_vif_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_vif_cap *vc = &mvif->cap;
+
+ vc->ht_ldpc = vif->bss_conf.ht_ldpc;
+ vc->vht_ldpc = vif->bss_conf.vht_ldpc;
+ vc->vht_su_ebfer = vif->bss_conf.vht_su_beamformer;
+ vc->vht_su_ebfee = vif->bss_conf.vht_su_beamformee;
+ vc->vht_mu_ebfer = vif->bss_conf.vht_mu_beamformer;
+ vc->vht_mu_ebfee = vif->bss_conf.vht_mu_beamformee;
+ vc->he_ldpc = vif->bss_conf.he_ldpc;
+ vc->he_su_ebfer = vif->bss_conf.he_su_beamformer;
+ vc->he_su_ebfee = vif->bss_conf.he_su_beamformee;
+ vc->he_mu_ebfer = vif->bss_conf.he_mu_beamformer;
+}
+
+static int
+mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf)
+{
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ int err;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ mt7915_vif_check_caps(phy, vif);
+
+ err = mt7915_mcu_add_bss_info(phy, vif, true);
+ if (err)
+ goto out;
+ err = mt7915_mcu_add_sta(dev, vif, NULL, true);
+out:
+ mutex_unlock(&dev->mt76.mutex);
+
+ return err;
+}
+
+static void
+mt7915_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf)
+{
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mt7915_mcu_add_sta(dev, vif, NULL, false);
mutex_unlock(&dev->mt76.mutex);
}
@@ -679,7 +736,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
return -ENOSPC;
INIT_LIST_HEAD(&msta->rc_list);
- INIT_LIST_HEAD(&msta->poll_list);
+ INIT_LIST_HEAD(&msta->wcid.poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
@@ -714,12 +771,12 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
mt7915_mac_twt_teardown_flow(dev, msta, i);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
if (!list_empty(&msta->rc_list))
list_del_init(&msta->rc_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&mdev->sta_poll_lock);
}
static void mt7915_tx(struct ieee80211_hw *hw,
@@ -801,16 +858,16 @@ mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
ret = mt7915_mcu_add_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
- set_bit(tid, &msta->ampdu_state);
+ set_bit(tid, &msta->wcid.ampdu_state);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
ret = mt7915_mcu_add_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
@@ -842,7 +899,7 @@ mt7915_get_stats(struct ieee80211_hw *hw,
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_dev *dev = mt7915_hw_dev(hw);
- struct mib_stats *mib = &phy->mib;
+ struct mt76_mib_stats *mib = &phy->mib;
mutex_lock(&dev->mt76.mutex);
@@ -1019,21 +1076,20 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
}
- if (!txrate->legacy && !txrate->flags)
- return;
-
- if (txrate->legacy) {
- sinfo->txrate.legacy = txrate->legacy;
- } else {
- sinfo->txrate.mcs = txrate->mcs;
- sinfo->txrate.nss = txrate->nss;
- sinfo->txrate.bw = txrate->bw;
- sinfo->txrate.he_gi = txrate->he_gi;
- sinfo->txrate.he_dcm = txrate->he_dcm;
- sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ if (txrate->legacy || txrate->flags) {
+ if (txrate->legacy) {
+ sinfo->txrate.legacy = txrate->legacy;
+ } else {
+ sinfo->txrate.mcs = txrate->mcs;
+ sinfo->txrate.nss = txrate->nss;
+ sinfo->txrate.bw = txrate->bw;
+ sinfo->txrate.he_gi = txrate->he_gi;
+ sinfo->txrate.he_dcm = txrate->he_dcm;
+ sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ }
+ sinfo->txrate.flags = txrate->flags;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
- sinfo->txrate.flags = txrate->flags;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
/* offloading flows bypass networking stack, so driver counts and
* reports sta statistics via NL80211_STA_INFO when WED is active.
@@ -1042,14 +1098,10 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
sinfo->tx_bytes = msta->wcid.stats.tx_bytes;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
- sinfo->tx_packets = msta->wcid.stats.tx_packets;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
-
- sinfo->tx_failed = msta->wcid.stats.tx_failed;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
-
- sinfo->tx_retries = msta->wcid.stats.tx_retries;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+ if (!mt7915_mcu_wed_wa_tx_stats(phy->dev, msta->wcid.idx)) {
+ sinfo->tx_packets = msta->wcid.stats.tx_packets;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
+ }
if (mtk_wed_get_rx_capa(&phy->dev->mt76.mmio.wed)) {
sinfo->rx_bytes = msta->wcid.stats.rx_bytes;
@@ -1060,6 +1112,12 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
}
}
+ sinfo->tx_failed = msta->wcid.stats.tx_failed;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+
+ sinfo->tx_retries = msta->wcid.stats.tx_retries;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+
sinfo->ack_signal = (s8)msta->ack_signal;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
@@ -1073,11 +1131,11 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
struct mt7915_dev *dev = msta->vif->phy->dev;
u32 *changed = data;
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
msta->changed |= *changed;
if (list_empty(&msta->rc_list))
list_add_tail(&msta->rc_list, &dev->sta_rc_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
@@ -1253,6 +1311,38 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_vec_queue_overflow_drop_cnt",
"rx_ba_cnt",
+ /* muru mu-mimo and ofdma related stats */
+ "dl_cck_cnt",
+ "dl_ofdm_cnt",
+ "dl_htmix_cnt",
+ "dl_htgf_cnt",
+ "dl_vht_su_cnt",
+ "dl_vht_2mu_cnt",
+ "dl_vht_3mu_cnt",
+ "dl_vht_4mu_cnt",
+ "dl_he_su_cnt",
+ "dl_he_ext_su_cnt",
+ "dl_he_2ru_cnt",
+ "dl_he_2mu_cnt",
+ "dl_he_3ru_cnt",
+ "dl_he_3mu_cnt",
+ "dl_he_4ru_cnt",
+ "dl_he_4mu_cnt",
+ "dl_he_5to8ru_cnt",
+ "dl_he_9to16ru_cnt",
+ "dl_he_gtr16ru_cnt",
+
+ "ul_hetrig_su_cnt",
+ "ul_hetrig_2ru_cnt",
+ "ul_hetrig_3ru_cnt",
+ "ul_hetrig_4ru_cnt",
+ "ul_hetrig_5to8ru_cnt",
+ "ul_hetrig_9to16ru_cnt",
+ "ul_hetrig_gtr16ru_cnt",
+ "ul_hetrig_2mu_cnt",
+ "ul_hetrig_3mu_cnt",
+ "ul_hetrig_4mu_cnt",
+
/* per vif counters */
"v_tx_mode_cck",
"v_tx_mode_ofdm",
@@ -1279,6 +1369,10 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
"v_tx_mcs_9",
"v_tx_mcs_10",
"v_tx_mcs_11",
+ "v_tx_nss_1",
+ "v_tx_nss_2",
+ "v_tx_nss_3",
+ "v_tx_nss_4",
};
#define MT7915_SSTATS_LEN ARRAY_SIZE(mt7915_gstrings_stats)
@@ -1326,11 +1420,11 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt76_mib_stats *mib = &phy->mib;
struct mt76_ethtool_worker_info wi = {
.data = data,
.idx = mvif->mt76.idx,
};
- struct mib_stats *mib = &phy->mib;
/* See mt7915_ampdu_stat_read_phy, etc */
int i, ei = 0, stats_size;
@@ -1403,6 +1497,37 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
data[ei++] = mib->rx_vec_queue_overflow_drop_cnt;
data[ei++] = mib->rx_ba_cnt;
+ data[ei++] = mib->dl_cck_cnt;
+ data[ei++] = mib->dl_ofdm_cnt;
+ data[ei++] = mib->dl_htmix_cnt;
+ data[ei++] = mib->dl_htgf_cnt;
+ data[ei++] = mib->dl_vht_su_cnt;
+ data[ei++] = mib->dl_vht_2mu_cnt;
+ data[ei++] = mib->dl_vht_3mu_cnt;
+ data[ei++] = mib->dl_vht_4mu_cnt;
+ data[ei++] = mib->dl_he_su_cnt;
+ data[ei++] = mib->dl_he_ext_su_cnt;
+ data[ei++] = mib->dl_he_2ru_cnt;
+ data[ei++] = mib->dl_he_2mu_cnt;
+ data[ei++] = mib->dl_he_3ru_cnt;
+ data[ei++] = mib->dl_he_3mu_cnt;
+ data[ei++] = mib->dl_he_4ru_cnt;
+ data[ei++] = mib->dl_he_4mu_cnt;
+ data[ei++] = mib->dl_he_5to8ru_cnt;
+ data[ei++] = mib->dl_he_9to16ru_cnt;
+ data[ei++] = mib->dl_he_gtr16ru_cnt;
+
+ data[ei++] = mib->ul_hetrig_su_cnt;
+ data[ei++] = mib->ul_hetrig_2ru_cnt;
+ data[ei++] = mib->ul_hetrig_3ru_cnt;
+ data[ei++] = mib->ul_hetrig_4ru_cnt;
+ data[ei++] = mib->ul_hetrig_5to8ru_cnt;
+ data[ei++] = mib->ul_hetrig_9to16ru_cnt;
+ data[ei++] = mib->ul_hetrig_gtr16ru_cnt;
+ data[ei++] = mib->ul_hetrig_2mu_cnt;
+ data[ei++] = mib->ul_hetrig_3mu_cnt;
+ data[ei++] = mib->ul_hetrig_4mu_cnt;
+
/* Add values for all stations owned by this vif */
wi.initial_stat_idx = ei;
ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi);
@@ -1526,6 +1651,8 @@ const struct ieee80211_ops mt7915_ops = {
.conf_tx = mt7915_conf_tx,
.configure_filter = mt7915_configure_filter,
.bss_info_changed = mt7915_bss_info_changed,
+ .start_ap = mt7915_start_ap,
+ .stop_ap = mt7915_stop_ap,
.sta_add = mt7915_sta_add,
.sta_remove = mt7915_sta_remove,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 9fcb22fa1f97..50ae7bf3af91 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -13,6 +13,9 @@
case 0x7915: \
_fw = MT7915_##name; \
break; \
+ case 0x7981: \
+ _fw = MT7981_##name; \
+ break; \
case 0x7986: \
_fw = MT7986_##name##__VA_ARGS__; \
break; \
@@ -164,7 +167,9 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
}
rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
- if (seq != rxd->seq)
+ if (seq != rxd->seq &&
+ !(rxd->eid == MCU_CMD_EXT_CID &&
+ rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
return -EAGAIN;
if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
@@ -274,7 +279,7 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
r = (struct mt7915_mcu_rdd_report *)skb->data;
- if (r->band_idx > MT_BAND1)
+ if (r->band_idx > MT_RX_SEL2)
return;
if ((r->band_idx && !dev->phy.mt76->band_idx) &&
@@ -395,12 +400,14 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
struct mt76_connac2_mcu_rxd *rxd;
rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
- if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
- rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
- rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
- rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
- rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
- !rxd->seq)
+ if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
+ rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
+ rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
+ rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
+ rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
+ !rxd->seq) &&
+ !(rxd->eid == MCU_CMD_EXT_CID &&
+ rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
mt7915_mcu_rx_unsolicited_event(dev, skb);
else
mt76_mcu_rx_event(&dev->mt76, skb);
@@ -706,6 +713,7 @@ static void
mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
struct ieee80211_vif *vif)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
struct ieee80211_he_mcs_nss_supp mcs_map;
struct sta_rec_he *he;
@@ -739,7 +747,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
- if (vif->bss_conf.he_ldpc &&
+ if (mvif->cap.he_ldpc &&
(elem->phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
cap |= STA_REC_HE_CAP_LDPC;
@@ -848,6 +856,7 @@ static void
mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, struct ieee80211_vif *vif)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
struct sta_rec_muru *muru;
struct tlv *tlv;
@@ -860,9 +869,9 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
muru = (struct sta_rec_muru *)tlv;
- muru->cfg.mimo_dl_en = vif->bss_conf.he_mu_beamformer ||
- vif->bss_conf.vht_mu_beamformer ||
- vif->bss_conf.vht_mu_beamformee;
+ muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
+ mvif->cap.vht_mu_ebfer ||
+ mvif->cap.vht_mu_ebfee;
if (!is_mt7915(&dev->mt76))
muru->cfg.mimo_ul_en = true;
muru->cfg.ofdma_dl_en = true;
@@ -995,8 +1004,8 @@ mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
if (sta)
mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
- wtbl_hdr, vif->bss_conf.ht_ldpc,
- vif->bss_conf.vht_ldpc);
+ wtbl_hdr, mvif->cap.ht_ldpc,
+ mvif->cap.vht_ldpc);
return 0;
}
@@ -1005,6 +1014,7 @@ static inline bool
mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
if (vif->type != NL80211_IFTYPE_STATION &&
@@ -1018,10 +1028,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
if (bfee)
- return vif->bss_conf.he_su_beamformee &&
+ return mvif->cap.he_su_ebfee &&
HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
else
- return vif->bss_conf.he_su_beamformer &&
+ return mvif->cap.he_su_ebfer &&
HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
}
@@ -1029,10 +1039,10 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
u32 cap = sta->deflink.vht_cap.cap;
if (bfee)
- return vif->bss_conf.vht_su_beamformee &&
+ return mvif->cap.vht_su_ebfee &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
else
- return vif->bss_conf.vht_su_beamformer &&
+ return mvif->cap.vht_su_ebfer &&
(cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
}
@@ -1527,7 +1537,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_TX_STBC;
if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
cap |= STA_CAP_RX_STBC;
- if (vif->bss_conf.ht_ldpc &&
+ if (mvif->cap.ht_ldpc &&
(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
cap |= STA_CAP_LDPC;
@@ -1553,7 +1563,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_VHT_TX_STBC;
if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
cap |= STA_CAP_VHT_RX_STBC;
- if (vif->bss_conf.vht_ldpc &&
+ if (mvif->cap.vht_ldpc &&
(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
cap |= STA_CAP_VHT_LDPC;
@@ -2112,12 +2122,11 @@ int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
sizeof(data), false);
}
-int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms)
+int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct sk_buff *skb;
- struct mt7915_mcu_muru_stats *mu_stats =
- (struct mt7915_mcu_muru_stats *)ms;
+ struct mt7915_mcu_muru_stats *mu_stats;
int ret;
struct {
@@ -2133,7 +2142,43 @@ int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms)
if (ret)
return ret;
- memcpy(mu_stats, skb->data, sizeof(struct mt7915_mcu_muru_stats));
+ mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
+
+ /* accumulate stats, these are clear-on-read */
+#define __dl_u32(s) phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
+#define __ul_u32(s) phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
+ __dl_u32(cck_cnt);
+ __dl_u32(ofdm_cnt);
+ __dl_u32(htmix_cnt);
+ __dl_u32(htgf_cnt);
+ __dl_u32(vht_su_cnt);
+ __dl_u32(vht_2mu_cnt);
+ __dl_u32(vht_3mu_cnt);
+ __dl_u32(vht_4mu_cnt);
+ __dl_u32(he_su_cnt);
+ __dl_u32(he_2ru_cnt);
+ __dl_u32(he_2mu_cnt);
+ __dl_u32(he_3ru_cnt);
+ __dl_u32(he_3mu_cnt);
+ __dl_u32(he_4ru_cnt);
+ __dl_u32(he_4mu_cnt);
+ __dl_u32(he_5to8ru_cnt);
+ __dl_u32(he_9to16ru_cnt);
+ __dl_u32(he_gtr16ru_cnt);
+
+ __ul_u32(hetrig_su_cnt);
+ __ul_u32(hetrig_2ru_cnt);
+ __ul_u32(hetrig_3ru_cnt);
+ __ul_u32(hetrig_4ru_cnt);
+ __ul_u32(hetrig_5to8ru_cnt);
+ __ul_u32(hetrig_9to16ru_cnt);
+ __ul_u32(hetrig_gtr16ru_cnt);
+ __ul_u32(hetrig_2mu_cnt);
+ __ul_u32(hetrig_3mu_cnt);
+ __ul_u32(hetrig_4mu_cnt);
+#undef __dl_u32
+#undef __ul_u32
+
dev_kfree_skb(skb);
return 0;
@@ -2993,7 +3038,7 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
}
ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
- req, sizeof(req), true, &skb);
+ req, len * sizeof(req[0]), true, &skb);
if (ret)
return ret;
@@ -3733,6 +3778,62 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
&req, sizeof(req), true);
}
+int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
+{
+ struct {
+ __le32 cmd;
+ __le32 num;
+ __le32 __rsv;
+ __le16 wlan_idx;
+ } req = {
+ .cmd = cpu_to_le32(0x15),
+ .num = cpu_to_le32(1),
+ .wlan_idx = cpu_to_le16(wlan_idx),
+ };
+ struct mt7915_mcu_wa_tx_stat {
+ __le16 wlan_idx;
+ u8 __rsv[2];
+
+ /* tx_bytes is deprecated since WA byte counter uses u32,
+ * which easily leads to overflow.
+ */
+ __le32 tx_bytes;
+ __le32 tx_packets;
+ } *res;
+ struct mt76_wcid *wcid;
+ struct sk_buff *skb;
+ int ret;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ if (!is_mt7915(&dev->mt76))
+ skb_pull(skb, 4);
+
+ res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
+
+ if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rcu_read_lock();
+
+ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+ if (wcid)
+ wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
+ else
+ ret = -EINVAL;
+
+ rcu_read_unlock();
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
{
struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index 45f3558bf31c..fc7ace638ce8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -417,7 +417,7 @@ static u32 mt7915_reg_map_l1(struct mt7915_dev *dev, u32 addr)
u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
u32 l1_remap;
- if (is_mt7986(&dev->mt76))
+ if (is_mt798x(&dev->mt76))
return MT_CONN_INFRA_OFFSET(addr);
l1_remap = is_mt7915(&dev->mt76) ?
@@ -447,7 +447,7 @@ static u32 mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr)
/* use read to push write */
dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2);
} else {
- u32 ofs = is_mt7986(&dev->mt76) ? 0x400000 : 0;
+ u32 ofs = is_mt798x(&dev->mt76) ? 0x400000 : 0;
offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET_MT7916, addr);
base = FIELD_GET(MT_HIF_REMAP_L2_BASE_MT7916, addr);
@@ -545,8 +545,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
- struct mt7915_phy *phy;
- int ret;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
@@ -554,43 +552,19 @@ static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed)
dev->mt76.token_size = wed->wlan.token_start;
spin_unlock_bh(&dev->mt76.token_lock);
- ret = wait_event_timeout(dev->mt76.tx_wait,
- !dev->mt76.wed_token_count, HZ);
- if (!ret)
- return -EAGAIN;
-
- phy = &dev->phy;
- mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H);
-
- phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
- if (phy)
- mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx),
- MT_AGG_ACR_PPDU_TXS2H);
-
- return 0;
+ return !wait_event_timeout(dev->mt76.tx_wait,
+ !dev->mt76.wed_token_count, HZ);
}
static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
- struct mt7915_phy *phy;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
spin_lock_bh(&dev->mt76.token_lock);
dev->mt76.token_size = MT7915_TOKEN_SIZE;
spin_unlock_bh(&dev->mt76.token_lock);
-
- /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
- * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
- */
- phy = &dev->phy;
- mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H);
-
- phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
- if (phy)
- mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx),
- MT_AGG_ACR_PPDU_TXS2H);
}
static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
@@ -785,7 +759,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
wed->wlan.nbuf = MT7915_HW_TOKEN_SIZE;
wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30;
wed->wlan.tx_tbit[1] = is_mt7915(&dev->mt76) ? 5 : 31;
- wed->wlan.txfree_tbit = is_mt7986(&dev->mt76) ? 2 : 1;
+ wed->wlan.txfree_tbit = is_mt798x(&dev->mt76) ? 2 : 1;
wed->wlan.token_start = MT7915_TOKEN_SIZE - wed->wlan.nbuf;
wed->wlan.wcid_512 = !is_mt7915(&dev->mt76);
@@ -795,7 +769,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
if (is_mt7915(&dev->mt76)) {
wed->wlan.rx_tbit[0] = 16;
wed->wlan.rx_tbit[1] = 17;
- } else if (is_mt7986(&dev->mt76)) {
+ } else if (is_mt798x(&dev->mt76)) {
wed->wlan.rx_tbit[0] = 22;
wed->wlan.rx_tbit[1] = 23;
} else {
@@ -853,6 +827,7 @@ static int mt7915_mmio_init(struct mt76_dev *mdev,
dev->reg.map = mt7916_reg_map;
dev->reg.map_size = ARRAY_SIZE(mt7916_reg_map);
break;
+ case 0x7981:
case 0x7986:
dev->reg.reg_rev = mt7986_reg;
dev->reg.offs_rev = mt7916_offs;
@@ -1062,8 +1037,8 @@ static int __init mt7915_init(void)
if (ret)
goto error_pci;
- if (IS_ENABLED(CONFIG_MT7986_WMAC)) {
- ret = platform_driver_register(&mt7986_wmac_driver);
+ if (IS_ENABLED(CONFIG_MT798X_WMAC)) {
+ ret = platform_driver_register(&mt798x_wmac_driver);
if (ret)
goto error_wmac;
}
@@ -1080,8 +1055,8 @@ error_pci:
static void __exit mt7915_exit(void)
{
- if (IS_ENABLED(CONFIG_MT7986_WMAC))
- platform_driver_unregister(&mt7986_wmac_driver);
+ if (IS_ENABLED(CONFIG_MT798X_WMAC))
+ platform_driver_unregister(&mt798x_wmac_driver);
pci_unregister_driver(&mt7915_pci_driver);
pci_unregister_driver(&mt7915_hif_driver);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index b3ead3530740..0456e56f6348 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -34,6 +34,10 @@
#define MT7916_FIRMWARE_WM "mediatek/mt7916_wm.bin"
#define MT7916_ROM_PATCH "mediatek/mt7916_rom_patch.bin"
+#define MT7981_FIRMWARE_WA "mediatek/mt7981_wa.bin"
+#define MT7981_FIRMWARE_WM "mediatek/mt7981_wm.bin"
+#define MT7981_ROM_PATCH "mediatek/mt7981_rom_patch.bin"
+
#define MT7986_FIRMWARE_WA "mediatek/mt7986_wa.bin"
#define MT7986_FIRMWARE_WM "mediatek/mt7986_wm.bin"
#define MT7986_FIRMWARE_WM_MT7975 "mediatek/mt7986_wm_mt7975.bin"
@@ -43,6 +47,9 @@
#define MT7915_EEPROM_DEFAULT "mediatek/mt7915_eeprom.bin"
#define MT7915_EEPROM_DEFAULT_DBDC "mediatek/mt7915_eeprom_dbdc.bin"
#define MT7916_EEPROM_DEFAULT "mediatek/mt7916_eeprom.bin"
+
+#define MT7981_EEPROM_MT7976_DEFAULT_DBDC "mediatek/mt7981_eeprom_mt7976_dbdc.bin"
+
#define MT7986_EEPROM_MT7975_DEFAULT "mediatek/mt7986_eeprom_mt7975.bin"
#define MT7986_EEPROM_MT7975_DUAL_DEFAULT "mediatek/mt7986_eeprom_mt7975_dual.bin"
#define MT7986_EEPROM_MT7976_DEFAULT "mediatek/mt7986_eeprom_mt7976.bin"
@@ -129,7 +136,6 @@ struct mt7915_sta {
struct mt7915_vif *vif;
- struct list_head poll_list;
struct list_head rc_list;
u32 airtime_ac[8];
@@ -138,7 +144,6 @@ struct mt7915_sta {
unsigned long changed;
unsigned long jiffies;
- unsigned long ampdu_state;
struct mt76_connac_sta_key_conf bip;
struct {
@@ -147,9 +152,23 @@ struct mt7915_sta {
} twt;
};
+struct mt7915_vif_cap {
+ bool ht_ldpc:1;
+ bool vht_ldpc:1;
+ bool he_ldpc:1;
+ bool vht_su_ebfer:1;
+ bool vht_su_ebfee:1;
+ bool vht_mu_ebfer:1;
+ bool vht_mu_ebfee:1;
+ bool he_su_ebfer:1;
+ bool he_su_ebfee:1;
+ bool he_mu_ebfer:1;
+};
+
struct mt7915_vif {
struct mt76_vif mt76; /* must be first */
+ struct mt7915_vif_cap cap;
struct mt7915_sta sta;
struct mt7915_phy *phy;
@@ -157,67 +176,6 @@ struct mt7915_vif {
struct cfg80211_bitrate_mask bitrate_mask;
};
-/* per-phy stats. */
-struct mib_stats {
- u32 ack_fail_cnt;
- u32 fcs_err_cnt;
- u32 rts_cnt;
- u32 rts_retries_cnt;
- u32 ba_miss_cnt;
- u32 tx_bf_cnt;
- u32 tx_mu_mpdu_cnt;
- u32 tx_mu_acked_mpdu_cnt;
- u32 tx_su_acked_mpdu_cnt;
- u32 tx_bf_ibf_ppdu_cnt;
- u32 tx_bf_ebf_ppdu_cnt;
-
- u32 tx_bf_rx_fb_all_cnt;
- u32 tx_bf_rx_fb_he_cnt;
- u32 tx_bf_rx_fb_vht_cnt;
- u32 tx_bf_rx_fb_ht_cnt;
-
- u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
- u32 tx_bf_rx_fb_nc_cnt;
- u32 tx_bf_rx_fb_nr_cnt;
- u32 tx_bf_fb_cpl_cnt;
- u32 tx_bf_fb_trig_cnt;
-
- u32 tx_ampdu_cnt;
- u32 tx_stop_q_empty_cnt;
- u32 tx_mpdu_attempts_cnt;
- u32 tx_mpdu_success_cnt;
- u32 tx_pkt_ebf_cnt;
- u32 tx_pkt_ibf_cnt;
-
- u32 tx_rwp_fail_cnt;
- u32 tx_rwp_need_cnt;
-
- /* rx stats */
- u32 rx_fifo_full_cnt;
- u32 channel_idle_cnt;
- u32 primary_cca_busy_time;
- u32 secondary_cca_busy_time;
- u32 primary_energy_detect_time;
- u32 cck_mdrdy_time;
- u32 ofdm_mdrdy_time;
- u32 green_mdrdy_time;
- u32 rx_vector_mismatch_cnt;
- u32 rx_delimiter_fail_cnt;
- u32 rx_mrdy_cnt;
- u32 rx_len_mismatch_cnt;
- u32 rx_mpdu_cnt;
- u32 rx_ampdu_cnt;
- u32 rx_ampdu_bytes_cnt;
- u32 rx_ampdu_valid_subframe_cnt;
- u32 rx_ampdu_valid_subframe_bytes_cnt;
- u32 rx_pfdrop_cnt;
- u32 rx_vec_queue_overflow_drop_cnt;
- u32 rx_ba_cnt;
-
- u32 tx_amsdu[8];
- u32 tx_amsdu_cnt;
-};
-
/* crash-dump */
struct mt7915_crash_data {
guid_t guid;
@@ -263,7 +221,7 @@ struct mt7915_phy {
u32 rx_ampdu_ts;
u32 ampdu_ref;
- struct mib_stats mib;
+ struct mt76_mib_stats mib;
struct mt76_channel_state state_ts;
#ifdef CONFIG_NL80211_TESTMODE
@@ -328,9 +286,7 @@ struct mt7915_dev {
#endif
struct list_head sta_rc_list;
- struct list_head sta_poll_list;
struct list_head twt_list;
- spinlock_t sta_poll_lock;
u32 hw_pattern;
@@ -420,8 +376,7 @@ mt7915_ext_phy(struct mt7915_dev *dev)
static inline u32 mt7915_check_adie(struct mt7915_dev *dev, bool sku)
{
u32 mask = sku ? MT_CONNINFRA_SKU_MASK : MT_ADIE_TYPE_MASK;
-
- if (!is_mt7986(&dev->mt76))
+ if (!is_mt798x(&dev->mt76))
return 0;
return mt76_rr(dev, MT_CONNINFRA_SKU_DEC_ADDR) & mask;
@@ -431,9 +386,9 @@ extern const struct ieee80211_ops mt7915_ops;
extern const struct mt76_testmode_ops mt7915_testmode_ops;
extern struct pci_driver mt7915_pci_driver;
extern struct pci_driver mt7915_hif_driver;
-extern struct platform_driver mt7986_wmac_driver;
+extern struct platform_driver mt798x_wmac_driver;
-#ifdef CONFIG_MT7986_WMAC
+#ifdef CONFIG_MT798X_WMAC
int mt7986_wmac_enable(struct mt7915_dev *dev);
void mt7986_wmac_disable(struct mt7915_dev *dev);
#else
@@ -466,6 +421,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2);
void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
+int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset);
int mt7915_txbf_init(struct mt7915_dev *dev);
void mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband);
@@ -539,6 +495,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
struct cfg80211_chan_def *chandef);
+int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wcid);
int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set);
int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
@@ -612,7 +569,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
-void mt7915_tx_token_put(struct mt7915_dev *dev);
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len);
@@ -623,7 +579,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
void mt7915_update_channel(struct mt76_phy *mphy);
int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enable);
-int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
+int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy);
int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev);
int mt7915_init_debugfs(struct mt7915_phy *phy);
void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index c8e478a55081..588cd87e24e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -145,6 +145,9 @@ enum offs_rev {
#define MT_PLE_BASE 0x820c0000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
+#define MT_PLE_HOST_RPT0 MT_PLE(0x030)
+#define MT_PLE_HOST_RPT0_TX_LATENCY BIT(3)
+
#define MT_FL_Q_EMPTY MT_PLE(__OFFS(PLE_FL_Q_EMPTY))
#define MT_FL_Q0_CTRL MT_PLE(__OFFS(PLE_FL_Q_CTRL))
#define MT_FL_Q2_CTRL MT_PLE(__OFFS(PLE_FL_Q_CTRL) + 0x8)
@@ -871,7 +874,12 @@ enum offs_rev {
#define MT_AFE_RG_WBG_EN_WPLL_UP_MASK BIT(20)
#define MT_AFE_RG_WBG_EN_PLL_UP_MASK (MT_AFE_RG_WBG_EN_BPLL_UP_MASK | \
MT_AFE_RG_WBG_EN_WPLL_UP_MASK)
-#define MT_AFE_RG_WBG_EN_TXCAL_MASK GENMASK(21, 17)
+#define MT_AFE_RG_WBG_EN_TXCAL_WF4 BIT(29)
+#define MT_AFE_RG_WBG_EN_TXCAL_BT BIT(21)
+#define MT_AFE_RG_WBG_EN_TXCAL_WF3 BIT(20)
+#define MT_AFE_RG_WBG_EN_TXCAL_WF2 BIT(19)
+#define MT_AFE_RG_WBG_EN_TXCAL_WF1 BIT(18)
+#define MT_AFE_RG_WBG_EN_TXCAL_WF0 BIT(17)
#define MT_ADIE_SLP_CTRL_BASE(_band) (0x18005000 + ((_band) << 19))
#define MT_ADIE_SLP_CTRL(_band, ofs) (MT_ADIE_SLP_CTRL_BASE(_band) + (ofs))
@@ -1096,6 +1104,12 @@ enum offs_rev {
#define MT_TOP_MCU_EMI_BASE MT_TOP(0x1c4)
#define MT_TOP_MCU_EMI_BASE_MASK GENMASK(19, 0)
+#define MT_TOP_WF_AP_PERI_BASE MT_TOP(0x1c8)
+#define MT_TOP_WF_AP_PERI_BASE_MASK GENMASK(19, 0)
+
+#define MT_TOP_EFUSE_BASE MT_TOP(0x1cc)
+#define MT_TOP_EFUSE_BASE_MASK GENMASK(19, 0)
+
#define MT_TOP_CONN_INFRA_WAKEUP MT_TOP(0x1a0)
#define MT_TOP_CONN_INFRA_WAKEUP_MASK BIT(0)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
index 32c137066e7f..37348b208736 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
@@ -6,7 +6,6 @@
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/of_gpio.h>
#include <linux/iopoll.h>
@@ -16,6 +15,9 @@
#include "mt7915.h"
+#define MT7981_CON_INFRA_VERSION 0x02090000
+#define MT7986_CON_INFRA_VERSION 0x02070000
+
/* INFRACFG */
#define MT_INFRACFG_CONN2AP_SLPPROT 0x0d0
#define MT_INFRACFG_AP2CONN_SLPPROT 0x0d4
@@ -167,10 +169,14 @@ static u32 mt76_wmac_rmw(void __iomem *base, u32 offset, u32 mask, u32 val)
return val;
}
-static u8 mt7986_wmac_check_adie_type(struct mt7915_dev *dev)
+static u8 mt798x_wmac_check_adie_type(struct mt7915_dev *dev)
{
u32 val;
+ /* Only DBDC A-die is used with MT7981 */
+ if (is_mt7981(&dev->mt76))
+ return ADIE_DBDC;
+
val = readl(dev->sku + MT_TOP_POS_SKU);
return FIELD_GET(MT_TOP_POS_SKU_ADIE_DBDC_MASK, val);
@@ -195,7 +201,7 @@ static int mt7986_wmac_gpio_setup(struct mt7915_dev *dev)
int ret;
u8 type;
- type = mt7986_wmac_check_adie_type(dev);
+ type = mt798x_wmac_check_adie_type(dev);
pinctrl = devm_pinctrl_get(dev->mt76.dev);
if (IS_ERR(pinctrl))
return PTR_ERR(pinctrl);
@@ -257,16 +263,26 @@ static int mt7986_wmac_consys_lockup(struct mt7915_dev *dev, bool enable)
return 0;
}
-static int mt7986_wmac_coninfra_check(struct mt7915_dev *dev)
+static int mt798x_wmac_coninfra_check(struct mt7915_dev *dev)
{
u32 cur;
+ u32 con_infra_version;
+
+ if (is_mt7981(&dev->mt76)) {
+ con_infra_version = MT7981_CON_INFRA_VERSION;
+ } else if (is_mt7986(&dev->mt76)) {
+ con_infra_version = MT7986_CON_INFRA_VERSION;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
+ }
- return read_poll_timeout(mt76_rr, cur, (cur == 0x02070000),
+ return read_poll_timeout(mt76_rr, cur, (cur == con_infra_version),
USEC_PER_MSEC, 50 * USEC_PER_MSEC,
false, dev, MT_CONN_INFRA_BASE);
}
-static int mt7986_wmac_coninfra_setup(struct mt7915_dev *dev)
+static int mt798x_wmac_coninfra_setup(struct mt7915_dev *dev)
{
struct device *pdev = dev->mt76.dev;
struct reserved_mem *rmem;
@@ -284,15 +300,25 @@ static int mt7986_wmac_coninfra_setup(struct mt7915_dev *dev)
val = (rmem->base >> 16) & MT_TOP_MCU_EMI_BASE_MASK;
- /* Set conninfra subsys PLL check */
- mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS,
- MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1);
- mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS,
- MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1);
+ if (is_mt7986(&dev->mt76)) {
+ /* Set conninfra subsys PLL check */
+ mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS,
+ MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1);
+ mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS,
+ MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1);
+ }
mt76_rmw_field(dev, MT_TOP_MCU_EMI_BASE,
MT_TOP_MCU_EMI_BASE_MASK, val);
+ if (is_mt7981(&dev->mt76)) {
+ mt76_rmw_field(dev, MT_TOP_WF_AP_PERI_BASE,
+ MT_TOP_WF_AP_PERI_BASE_MASK, 0x300d0000 >> 16);
+
+ mt76_rmw_field(dev, MT_TOP_EFUSE_BASE,
+ MT_TOP_EFUSE_BASE_MASK, 0x11f20000 >> 16);
+ }
+
mt76_wr(dev, MT_INFRA_BUS_EMI_START, rmem->base);
mt76_wr(dev, MT_INFRA_BUS_EMI_END, rmem->size);
@@ -305,15 +331,18 @@ static int mt7986_wmac_coninfra_setup(struct mt7915_dev *dev)
return 0;
}
-static int mt7986_wmac_sku_setup(struct mt7915_dev *dev, u32 *adie_type)
+static int mt798x_wmac_sku_setup(struct mt7915_dev *dev, u32 *adie_type)
{
int ret;
- u32 adie_main, adie_ext;
+ u32 adie_main = 0, adie_ext = 0;
mt76_rmw_field(dev, MT_CONN_INFRA_ADIE_RESET,
MT_CONN_INFRA_ADIE1_RESET_MASK, 0x1);
- mt76_rmw_field(dev, MT_CONN_INFRA_ADIE_RESET,
- MT_CONN_INFRA_ADIE2_RESET_MASK, 0x1);
+
+ if (is_mt7986(&dev->mt76)) {
+ mt76_rmw_field(dev, MT_CONN_INFRA_ADIE_RESET,
+ MT_CONN_INFRA_ADIE2_RESET_MASK, 0x1);
+ }
mt76_wmac_spi_lock(dev);
@@ -321,9 +350,11 @@ static int mt7986_wmac_sku_setup(struct mt7915_dev *dev, u32 *adie_type)
if (ret)
goto out;
- ret = mt76_wmac_spi_read(dev, 1, MT_ADIE_CHIP_ID, &adie_ext);
- if (ret)
- goto out;
+ if (is_mt7986(&dev->mt76)) {
+ ret = mt76_wmac_spi_read(dev, 1, MT_ADIE_CHIP_ID, &adie_ext);
+ if (ret)
+ goto out;
+ }
*adie_type = FIELD_GET(MT_ADIE_CHIP_ID_MASK, adie_main) |
(MT_ADIE_CHIP_ID_MASK & adie_ext);
@@ -470,7 +501,7 @@ static int mt7986_wmac_adie_xtal_trim_7976(struct mt7915_dev *dev, u8 adie)
return ret;
}
-static int mt7986_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie)
+static int mt798x_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie)
{
u32 id, version, rg_xo_01, rg_xo_03;
int ret;
@@ -489,7 +520,14 @@ static int mt7986_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie)
rg_xo_01 = 0x1d59080f;
rg_xo_03 = 0x34c00fe0;
} else {
- rg_xo_01 = 0x1959f80f;
+ if (is_mt7981(&dev->mt76)) {
+ rg_xo_01 = 0x1959c80f;
+ } else if (is_mt7986(&dev->mt76)) {
+ rg_xo_01 = 0x1959f80f;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
+ }
rg_xo_03 = 0x34d00fe0;
}
@@ -611,7 +649,15 @@ static int mt7986_wmac_adie_patch_7975(struct mt7915_dev *dev, u8 adie)
return ret;
/* turn on SX0 LTBUF */
- ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000002);
+ if (is_mt7981(&dev->mt76)) {
+ ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000007);
+ } else if (is_mt7986(&dev->mt76)) {
+ ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000002);
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
if (ret)
return ret;
@@ -658,7 +704,10 @@ static int mt7986_wmac_adie_patch_7975(struct mt7915_dev *dev, u8 adie)
return ret;
/* set CKB driving and filter */
- return mt76_wmac_spi_write(dev, adie, 0x2c8, 0x00000072);
+ if (is_mt7986(&dev->mt76))
+ return mt76_wmac_spi_write(dev, adie, 0x2c8, 0x00000072);
+
+ return ret;
}
static int mt7986_wmac_adie_cfg(struct mt7915_dev *dev, u8 adie, u32 adie_type)
@@ -686,7 +735,7 @@ static int mt7986_wmac_adie_cfg(struct mt7915_dev *dev, u8 adie, u32 adie_type)
ret = mt7986_wmac_adie_patch_7975(dev, adie);
} else if (is_7976(dev, adie, adie_type)) {
- if (mt7986_wmac_check_adie_type(dev) == ADIE_DBDC) {
+ if (mt798x_wmac_check_adie_type(dev) == ADIE_DBDC) {
ret = mt76_wmac_spi_write(dev, adie,
MT_ADIE_WRI_CK_SEL, 0x1c);
if (ret)
@@ -701,7 +750,7 @@ static int mt7986_wmac_adie_cfg(struct mt7915_dev *dev, u8 adie, u32 adie_type)
if (ret)
goto out;
- ret = mt7986_wmac_adie_patch_7976(dev, adie);
+ ret = mt798x_wmac_adie_patch_7976(dev, adie);
}
out:
mt76_wmac_spi_unlock(dev);
@@ -714,6 +763,7 @@ mt7986_wmac_afe_cal(struct mt7915_dev *dev, u8 adie, bool dbdc, u32 adie_type)
{
int ret;
u8 idx;
+ u32 txcal;
mt76_wmac_spi_lock(dev);
if (is_7975(dev, adie, adie_type))
@@ -744,12 +794,18 @@ mt7986_wmac_afe_cal(struct mt7915_dev *dev, u8 adie, bool dbdc, u32 adie_type)
MT_AFE_RG_WBG_EN_WPLL_UP_MASK, 0x1);
usleep_range(60, 100);
- mt76_rmw_field(dev, MT_AFE_DIG_EN_01(idx),
- MT_AFE_RG_WBG_EN_TXCAL_MASK, 0x1f);
+ txcal = (MT_AFE_RG_WBG_EN_TXCAL_BT |
+ MT_AFE_RG_WBG_EN_TXCAL_WF0 |
+ MT_AFE_RG_WBG_EN_TXCAL_WF1 |
+ MT_AFE_RG_WBG_EN_TXCAL_WF2 |
+ MT_AFE_RG_WBG_EN_TXCAL_WF3);
+ if (is_mt7981(&dev->mt76))
+ txcal |= MT_AFE_RG_WBG_EN_TXCAL_WF4;
+
+ mt76_set(dev, MT_AFE_DIG_EN_01(idx), txcal);
usleep_range(800, 1000);
- mt76_rmw(dev, MT_AFE_DIG_EN_01(idx),
- MT_AFE_RG_WBG_EN_TXCAL_MASK, 0x0);
+ mt76_clear(dev, MT_AFE_DIG_EN_01(idx), txcal);
mt76_rmw(dev, MT_AFE_DIG_EN_03(idx),
MT_AFE_RG_WBG_EN_PLL_UP_MASK, 0x0);
@@ -806,7 +862,7 @@ static int mt7986_wmac_bus_timeout(struct mt7915_dev *dev)
mt76_rmw_field(dev, MT_INFRA_BUS_ON_TIMEOUT,
MT_INFRA_BUS_TIMEOUT_EN_MASK, 0xf);
- return mt7986_wmac_coninfra_check(dev);
+ return mt798x_wmac_coninfra_check(dev);
}
static void mt7986_wmac_clock_enable(struct mt7915_dev *dev, u32 adie_type)
@@ -876,14 +932,15 @@ static int mt7986_wmac_top_wfsys_wakeup(struct mt7915_dev *dev, bool enable)
if (!enable)
return 0;
- return mt7986_wmac_coninfra_check(dev);
+ return mt798x_wmac_coninfra_check(dev);
}
static int mt7986_wmac_wm_enable(struct mt7915_dev *dev, bool enable)
{
u32 cur;
- mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, 0);
+ if (is_mt7986(&dev->mt76))
+ mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, 0);
mt76_rmw_field(dev, MT7986_TOP_WM_RESET,
MT7986_TOP_WM_RESET_MASK, enable);
@@ -1006,7 +1063,7 @@ mt7986_wmac_adie_setup(struct mt7915_dev *dev, u8 adie, u32 adie_type)
if (ret)
return ret;
- if (!adie && (mt7986_wmac_check_adie_type(dev) == ADIE_DBDC))
+ if (!adie && (mt798x_wmac_check_adie_type(dev) == ADIE_DBDC))
ret = mt7986_wmac_afe_cal(dev, adie, true, adie_type);
return ret;
@@ -1061,15 +1118,15 @@ int mt7986_wmac_enable(struct mt7915_dev *dev)
if (ret)
return ret;
- ret = mt7986_wmac_coninfra_check(dev);
+ ret = mt798x_wmac_coninfra_check(dev);
if (ret)
return ret;
- ret = mt7986_wmac_coninfra_setup(dev);
+ ret = mt798x_wmac_coninfra_setup(dev);
if (ret)
return ret;
- ret = mt7986_wmac_sku_setup(dev, &adie_type);
+ ret = mt798x_wmac_sku_setup(dev, &adie_type);
if (ret)
return ret;
@@ -1077,9 +1134,12 @@ int mt7986_wmac_enable(struct mt7915_dev *dev)
if (ret)
return ret;
- ret = mt7986_wmac_adie_setup(dev, 1, adie_type);
- if (ret)
- return ret;
+ /* mt7981 doesn't support a second a-die */
+ if (is_mt7986(&dev->mt76)) {
+ ret = mt7986_wmac_adie_setup(dev, 1, adie_type);
+ if (ret)
+ return ret;
+ }
ret = mt7986_wmac_subsys_powerup(dev, adie_type);
if (ret)
@@ -1132,7 +1192,7 @@ void mt7986_wmac_disable(struct mt7915_dev *dev)
mt7986_wmac_consys_reset(dev, false);
}
-static int mt7986_wmac_init(struct mt7915_dev *dev)
+static int mt798x_wmac_init(struct mt7915_dev *dev)
{
struct device *pdev = dev->mt76.dev;
struct platform_device *pfdev = to_platform_device(pdev);
@@ -1165,7 +1225,7 @@ static int mt7986_wmac_init(struct mt7915_dev *dev)
return 0;
}
-static int mt7986_wmac_probe(struct platform_device *pdev)
+static int mt798x_wmac_probe(struct platform_device *pdev)
{
void __iomem *mem_base;
struct mt7915_dev *dev;
@@ -1203,7 +1263,7 @@ static int mt7986_wmac_probe(struct platform_device *pdev)
if (ret)
goto free_device;
- ret = mt7986_wmac_init(dev);
+ ret = mt798x_wmac_init(dev);
if (ret)
goto free_irq;
@@ -1225,7 +1285,7 @@ free_device:
return ret;
}
-static int mt7986_wmac_remove(struct platform_device *pdev)
+static int mt798x_wmac_remove(struct platform_device *pdev)
{
struct mt7915_dev *dev = platform_get_drvdata(pdev);
@@ -1234,20 +1294,21 @@ static int mt7986_wmac_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id mt7986_wmac_of_match[] = {
+static const struct of_device_id mt798x_wmac_of_match[] = {
+ { .compatible = "mediatek,mt7981-wmac", .data = (u32 *)0x7981 },
{ .compatible = "mediatek,mt7986-wmac", .data = (u32 *)0x7986 },
{},
};
-MODULE_DEVICE_TABLE(of, mt7986_wmac_of_match);
+MODULE_DEVICE_TABLE(of, mt798x_wmac_of_match);
-struct platform_driver mt7986_wmac_driver = {
+struct platform_driver mt798x_wmac_driver = {
.driver = {
- .name = "mt7986-wmac",
- .of_match_table = mt7986_wmac_of_match,
+ .name = "mt798x-wmac",
+ .of_match_table = mt798x_wmac_of_match,
},
- .probe = mt7986_wmac_probe,
- .remove = mt7986_wmac_remove,
+ .probe = mt798x_wmac_probe,
+ .remove = mt798x_wmac_remove,
};
MODULE_FIRMWARE(MT7986_FIRMWARE_WA);
@@ -1255,3 +1316,7 @@ MODULE_FIRMWARE(MT7986_FIRMWARE_WM);
MODULE_FIRMWARE(MT7986_FIRMWARE_WM_MT7975);
MODULE_FIRMWARE(MT7986_ROM_PATCH);
MODULE_FIRMWARE(MT7986_ROM_PATCH_MT7975);
+
+MODULE_FIRMWARE(MT7981_FIRMWARE_WA);
+MODULE_FIRMWARE(MT7981_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7981_ROM_PATCH);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
index adff2d7350b5..7ed51e057857 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: ISC
config MT7921_COMMON
tristate
- select MT76_CONNAC_LIB
+ select MT792x_LIB
select WANT_DEV_COREDUMP
config MT7921E
@@ -27,7 +27,7 @@ config MT7921S
config MT7921U
tristate "MediaTek MT7921U (USB) support"
- select MT76_USB
+ select MT792x_USB
select MT7921_COMMON
depends on MAC80211
depends on USB
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index e5d2d2e131a2..849be9e848e0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -5,11 +5,8 @@ obj-$(CONFIG_MT7921E) += mt7921e.o
obj-$(CONFIG_MT7921S) += mt7921s.o
obj-$(CONFIG_MT7921U) += mt7921u.o
-CFLAGS_trace.o := -I$(src)
-
-mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o
+mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o
mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
-mt7921-common-$(CONFIG_ACPI) += acpi_sar.o
-mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o
+mt7921e-y := pci.o pci_mac.o pci_mcu.o
mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o
-mt7921u-y := usb.o usb_mac.o
+mt7921u-y := usb.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h
deleted file mode 100644
index 6f2c4a572572..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* SPDX-License-Identifier: ISC */
-/* Copyright (C) 2022 MediaTek Inc. */
-
-#ifndef __MT7921_ACPI_SAR_H
-#define __MT7921_ACPI_SAR_H
-
-#define MT7921_ASAR_MIN_DYN 1
-#define MT7921_ASAR_MAX_DYN 8
-#define MT7921_ASAR_MIN_GEO 3
-#define MT7921_ASAR_MAX_GEO 8
-#define MT7921_ASAR_MIN_FG 8
-
-#define MT7921_ACPI_MTCL "MTCL"
-#define MT7921_ACPI_MTDS "MTDS"
-#define MT7921_ACPI_MTGS "MTGS"
-#define MT7921_ACPI_MTFG "MTFG"
-
-struct mt7921_asar_dyn_limit {
- u8 idx;
- u8 frp[5];
-} __packed;
-
-struct mt7921_asar_dyn {
- u8 names[4];
- u8 enable;
- u8 nr_tbl;
- DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit, tbl);
-} __packed;
-
-struct mt7921_asar_dyn_limit_v2 {
- u8 idx;
- u8 frp[11];
-} __packed;
-
-struct mt7921_asar_dyn_v2 {
- u8 names[4];
- u8 enable;
- u8 rsvd;
- u8 nr_tbl;
- DECLARE_FLEX_ARRAY(struct mt7921_asar_dyn_limit_v2, tbl);
-} __packed;
-
-struct mt7921_asar_geo_band {
- u8 pwr;
- u8 offset;
-} __packed;
-
-struct mt7921_asar_geo_limit {
- u8 idx;
- /* 0:2G, 1:5G */
- struct mt7921_asar_geo_band band[2];
-} __packed;
-
-struct mt7921_asar_geo {
- u8 names[4];
- u8 version;
- u8 nr_tbl;
- DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit, tbl);
-} __packed;
-
-struct mt7921_asar_geo_limit_v2 {
- u8 idx;
- /* 0:2G, 1:5G, 2:6G */
- struct mt7921_asar_geo_band band[3];
-} __packed;
-
-struct mt7921_asar_geo_v2 {
- u8 names[4];
- u8 version;
- u8 rsvd;
- u8 nr_tbl;
- DECLARE_FLEX_ARRAY(struct mt7921_asar_geo_limit_v2, tbl);
-} __packed;
-
-struct mt7921_asar_cl {
- u8 names[4];
- u8 version;
- u8 mode_6g;
- u8 cl6g[6];
-} __packed;
-
-struct mt7921_asar_fg {
- u8 names[4];
- u8 version;
- u8 rsvd;
- u8 nr_flag;
- u8 rsvd1;
- u8 flag[];
-} __packed;
-
-struct mt7921_acpi_sar {
- u8 ver;
- union {
- struct mt7921_asar_dyn *dyn;
- struct mt7921_asar_dyn_v2 *dyn_v2;
- };
- union {
- struct mt7921_asar_geo *geo;
- struct mt7921_asar_geo_v2 *geo_v2;
- };
- struct mt7921_asar_cl *countrylist;
- struct mt7921_asar_fg *fg;
-};
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index d6b6edba2fec..616b66a3fde2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -6,11 +6,11 @@
static int
mt7921_reg_set(void *data, u64 val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt76_wr(dev, dev->mt76.debugfs_reg, val);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
@@ -18,11 +18,11 @@ mt7921_reg_set(void *data, u64 val)
static int
mt7921_reg_get(void *data, u64 *val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
*val = mt76_rr(dev, dev->mt76.debugfs_reg);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
@@ -32,14 +32,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7921_reg_get, mt7921_reg_set,
static int
mt7921_fw_debug_set(void *data, u64 val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
dev->fw_debug = (u8)val;
mt7921_mcu_fw_log_2_host(dev, dev->fw_debug);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
@@ -47,7 +47,7 @@ mt7921_fw_debug_set(void *data, u64 val)
static int
mt7921_fw_debug_get(void *data, u64 *val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
*val = dev->fw_debug;
@@ -57,128 +57,7 @@ mt7921_fw_debug_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get,
mt7921_fw_debug_set, "%lld\n");
-static void
-mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy,
- struct seq_file *file)
-{
- struct mt7921_dev *dev = file->private;
- int bound[15], range[4], i;
-
- if (!phy)
- return;
-
- mt7921_mac_update_mib_stats(phy);
-
- /* Tx ampdu stat */
- for (i = 0; i < ARRAY_SIZE(range); i++)
- range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
-
- for (i = 0; i < ARRAY_SIZE(bound); i++)
- bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
-
- seq_printf(file, "\nPhy0\n");
-
- seq_printf(file, "Length: %8d | ", bound[0]);
- for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
- seq_printf(file, "%3d %3d | ", bound[i] + 1, bound[i + 1]);
-
- seq_puts(file, "\nCount: ");
- for (i = 0; i < ARRAY_SIZE(bound); i++)
- seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]);
- seq_puts(file, "\n");
-
- seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
-}
-
-static int
-mt7921_tx_stats_show(struct seq_file *file, void *data)
-{
- struct mt7921_dev *dev = file->private;
- struct mt7921_phy *phy = &dev->phy;
- struct mib_stats *mib = &phy->mib;
- int i;
-
- mt7921_mutex_acquire(dev);
-
- mt7921_ampdu_stat_read_phy(phy, file);
-
- seq_puts(file, "Tx MSDU stat:\n");
- for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
- seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
- i + 1, mib->tx_amsdu[i]);
- if (mib->tx_amsdu_cnt)
- seq_printf(file, "(%3d%%)\n",
- mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
- else
- seq_puts(file, "\n");
- }
-
- mt7921_mutex_release(dev);
-
- return 0;
-}
-
-DEFINE_SHOW_ATTRIBUTE(mt7921_tx_stats);
-
-static int
-mt7921_queues_acq(struct seq_file *s, void *data)
-{
- struct mt7921_dev *dev = dev_get_drvdata(s->private);
- int i;
-
- mt7921_mutex_acquire(dev);
-
- for (i = 0; i < 4; i++) {
- u32 ctrl, val, qlen = 0;
- int j;
-
- val = mt76_rr(dev, MT_PLE_AC_QEMPTY(i));
- ctrl = BIT(31) | BIT(11) | (i << 24);
-
- for (j = 0; j < 32; j++) {
- if (val & BIT(j))
- continue;
-
- mt76_wr(dev, MT_PLE_FL_Q0_CTRL, ctrl | j);
- qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
- GENMASK(11, 0));
- }
- seq_printf(s, "AC%d: queued=%d\n", i, qlen);
- }
-
- mt7921_mutex_release(dev);
-
- return 0;
-}
-
-static int
-mt7921_queues_read(struct seq_file *s, void *data)
-{
- struct mt7921_dev *dev = dev_get_drvdata(s->private);
- struct {
- struct mt76_queue *q;
- char *queue;
- } queue_map[] = {
- { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
- { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" },
- { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
- struct mt76_queue *q = queue_map[i].q;
-
- if (!q)
- continue;
-
- seq_printf(s,
- "%s: queued=%d head=%d tail=%d\n",
- queue_map[i].queue, q->queued, q->head,
- q->tail);
- }
-
- return 0;
-}
+DEFINE_SHOW_ATTRIBUTE(mt792x_tx_stats);
static void
mt7921_seq_puts_array(struct seq_file *file, const char *str,
@@ -211,13 +90,13 @@ mt7921_seq_puts_array(struct seq_file *file, const char *str,
static int
mt7921_txpwr(struct seq_file *s, void *data)
{
- struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
struct mt7921_txpwr txpwr;
int ret;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
ret = mt7921_get_txpwr_info(dev, &txpwr);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
if (ret)
return ret;
@@ -263,7 +142,7 @@ mt7921_txpwr(struct seq_file *s, void *data)
static int
mt7921_pm_set(void *data, u64 val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
struct mt76_connac_pm *pm = &dev->pm;
if (mt76_is_usb(&dev->mt76))
@@ -296,7 +175,7 @@ out:
static int
mt7921_pm_get(void *data, u64 *val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
*val = dev->pm.enable_user;
@@ -308,7 +187,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
static int
mt7921_deep_sleep_set(void *data, u64 val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
struct mt76_connac_pm *pm = &dev->pm;
bool monitor = !!(dev->mphy.hw->conf.flags & IEEE80211_CONF_MONITOR);
bool enable = !!val;
@@ -316,7 +195,7 @@ mt7921_deep_sleep_set(void *data, u64 val)
if (mt76_is_usb(&dev->mt76))
return -EOPNOTSUPP;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (pm->ds_enable_user == enable)
goto out;
@@ -324,7 +203,7 @@ mt7921_deep_sleep_set(void *data, u64 val)
pm->ds_enable = enable && !monitor;
mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
@@ -332,7 +211,7 @@ out:
static int
mt7921_deep_sleep_get(void *data, u64 *val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
*val = dev->pm.ds_enable_user;
@@ -342,67 +221,24 @@ mt7921_deep_sleep_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get,
mt7921_deep_sleep_set, "%lld\n");
-static int
-mt7921_pm_stats(struct seq_file *s, void *data)
-{
- struct mt7921_dev *dev = dev_get_drvdata(s->private);
- struct mt76_connac_pm *pm = &dev->pm;
-
- unsigned long awake_time = pm->stats.awake_time;
- unsigned long doze_time = pm->stats.doze_time;
-
- if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
- awake_time += jiffies - pm->stats.last_wake_event;
- else
- doze_time += jiffies - pm->stats.last_doze_event;
-
- seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
- jiffies_to_msecs(awake_time),
- jiffies_to_msecs(doze_time));
-
- seq_printf(s, "low power wakes: %9d\n", pm->stats.lp_wake);
-
- return 0;
-}
-
-static int
-mt7921_pm_idle_timeout_set(void *data, u64 val)
-{
- struct mt7921_dev *dev = data;
-
- dev->pm.idle_timeout = msecs_to_jiffies(val);
-
- return 0;
-}
-
-static int
-mt7921_pm_idle_timeout_get(void *data, u64 *val)
-{
- struct mt7921_dev *dev = data;
-
- *val = jiffies_to_msecs(dev->pm.idle_timeout);
-
- return 0;
-}
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
- mt7921_pm_idle_timeout_set, "%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt792x_pm_idle_timeout_get,
+ mt792x_pm_idle_timeout_set, "%lld\n");
static int mt7921_chip_reset(void *data, u64 val)
{
- struct mt7921_dev *dev = data;
+ struct mt792x_dev *dev = data;
int ret = 0;
switch (val) {
case 1:
/* Reset wifisys directly. */
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
break;
default:
/* Collect the core dump before reset wifisys. */
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
ret = mt76_connac_mcu_chip_config(&dev->mt76);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
break;
}
@@ -414,7 +250,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n");
static int
mt7921s_sched_quota_read(struct seq_file *s, void *data)
{
- struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
struct mt76_sdio *sdio = &dev->mt76.sdio;
seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota);
@@ -425,7 +261,7 @@ mt7921s_sched_quota_read(struct seq_file *s, void *data)
return 0;
}
-int mt7921_init_debugfs(struct mt7921_dev *dev)
+int mt7921_init_debugfs(struct mt792x_dev *dev)
{
struct dentry *dir;
@@ -435,23 +271,23 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
if (mt76_is_mmio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues",
- dir, mt7921_queues_read);
+ dir, mt792x_queues_read);
else
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues",
dir, mt76_queues_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
- mt7921_queues_acq);
+ mt792x_queues_acq);
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
mt7921_txpwr);
- debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops);
+ debugfs_create_file("tx_stats", 0400, dir, dev, &mt792x_tx_stats_fops);
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
debugfs_create_file("idle-timeout", 0600, dir, dev,
&fops_pm_idle_timeout);
debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
- mt7921_pm_stats);
+ mt792x_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
if (mt76_is_sdio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index bf1da9fddfab..ff63f37f67d9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -2,259 +2,84 @@
/* Copyright (C) 2020 MediaTek Inc. */
#include <linux/etherdevice.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
#include <linux/firmware.h>
#include "mt7921.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
-static const struct ieee80211_iface_limit if_limits[] = {
- {
- .max = MT7921_MAX_INTERFACES,
- .types = BIT(NL80211_IFTYPE_STATION)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_AP)
+static ssize_t mt7921_thermal_temp_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ switch (to_sensor_dev_attr(attr)->index) {
+ case 0: {
+ struct mt792x_phy *phy = dev_get_drvdata(dev);
+ struct mt792x_dev *mdev = phy->dev;
+ int temperature;
+
+ mt792x_mutex_acquire(mdev);
+ temperature = mt7921_mcu_get_temperature(phy);
+ mt792x_mutex_release(mdev);
+
+ if (temperature < 0)
+ return temperature;
+ /* display in millidegree Celsius */
+ return sprintf(buf, "%u\n", temperature * 1000);
}
-};
+ default:
+ return -EINVAL;
+ }
+}
+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7921_thermal_temp, 0);
-static const struct ieee80211_iface_combination if_comb[] = {
- {
- .limits = if_limits,
- .n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = MT7921_MAX_INTERFACES,
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
- },
+static struct attribute *mt7921_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(mt7921_hwmon);
-static const struct ieee80211_iface_limit if_limits_chanctx[] = {
- {
- .max = 2,
- .types = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_P2P_CLIENT)
- },
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_GO)
- }
-};
+static int mt7921_thermal_init(struct mt792x_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct device *hwmon;
+ const char *name;
-static const struct ieee80211_iface_combination if_comb_chanctx[] = {
- {
- .limits = if_limits_chanctx,
- .n_limits = ARRAY_SIZE(if_limits_chanctx),
- .max_interfaces = 2,
- .num_different_channels = 2,
- .beacon_int_infra_match = false,
- }
-};
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7921_%s",
+ wiphy_name(wiphy));
+
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
+ mt7921_hwmon_groups);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ return 0;
+}
static void
mt7921_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
dev->country_ie_env = request->country_ie_env;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt7921_mcu_set_clc(dev, request->alpha2, request->country_ie_env);
mt76_connac_mcu_set_channel_domain(hw->priv);
mt7921_set_tx_sar_pwr(hw, NULL);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
-static int
-mt7921_init_wiphy(struct ieee80211_hw *hw)
-{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = phy->dev;
- struct wiphy *wiphy = hw->wiphy;
-
- hw->queues = 4;
- hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
- hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
- hw->netdev_features = NETIF_F_RXCSUM;
-
- hw->radiotap_timestamp.units_pos =
- IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
-
- phy->slottime = 9;
-
- hw->sta_data_size = sizeof(struct mt7921_sta);
- hw->vif_data_size = sizeof(struct mt7921_vif);
-
- if (dev->fw_features & MT7921_FW_CAP_CNM) {
- wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- wiphy->iface_combinations = if_comb_chanctx;
- wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx);
- } else {
- wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- wiphy->iface_combinations = if_comb;
- wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
- }
- wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
- WIPHY_FLAG_4ADDR_STATION);
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO);
- wiphy->max_remain_on_channel_duration = 5000;
- wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
- wiphy->max_scan_ssids = 4;
- wiphy->max_sched_scan_plan_interval =
- MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL;
- wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID;
- wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH;
- wiphy->max_sched_scan_reqs = 1;
- wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
- wiphy->reg_notifier = mt7921_regd_notifier;
-
- wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
- NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
-
- ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
- ieee80211_hw_set(hw, HAS_RATE_CONTROL);
- ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
- ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
- ieee80211_hw_set(hw, WANT_MONITOR_VIF);
- ieee80211_hw_set(hw, SUPPORTS_PS);
- ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
- ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
- ieee80211_hw_set(hw, CONNECTION_MONITOR);
-
- if (dev->pm.enable)
- ieee80211_hw_set(hw, CONNECTION_MONITOR);
-
- hw->max_tx_fragments = 4;
-
- return 0;
-}
-
-static void
-mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
-{
- u32 mask, set;
-
- mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
- MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
- mt76_set(dev, MT_TMAC_CTCR0(band),
- MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
- MT_TMAC_CTCR0_INS_DDLMT_EN);
-
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
- mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
-
- /* enable MIB tx-rx time reporting */
- mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN);
- mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN);
-
- mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
- /* disable rx rate report by default due to hw issues */
- mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
-
- /* filter out non-resp frames and get instantaneous signal reporting */
- mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM;
- set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
- FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
- mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
-}
-
-static u8
-mt7921_get_offload_capability(struct device *dev, const char *fw_wm)
-{
- const struct mt76_connac2_fw_trailer *hdr;
- struct mt7921_realease_info *rel_info;
- const struct firmware *fw;
- int ret, i, offset = 0;
- const u8 *data, *end;
- u8 offload_caps = 0;
-
- ret = request_firmware(&fw, fw_wm, dev);
- if (ret)
- return ret;
-
- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
- dev_err(dev, "Invalid firmware\n");
- goto out;
- }
-
- data = fw->data;
- hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-
- for (i = 0; i < hdr->n_region; i++) {
- const struct mt76_connac2_fw_region *region;
-
- region = (const void *)((const u8 *)hdr -
- (hdr->n_region - i) * sizeof(*region));
- offset += le32_to_cpu(region->len);
- }
-
- data += offset + 16;
- rel_info = (struct mt7921_realease_info *)data;
- data += sizeof(*rel_info);
- end = data + le16_to_cpu(rel_info->len);
-
- while (data < end) {
- rel_info = (struct mt7921_realease_info *)data;
- data += sizeof(*rel_info);
-
- if (rel_info->tag == MT7921_FW_TAG_FEATURE) {
- struct mt7921_fw_features *features;
-
- features = (struct mt7921_fw_features *)data;
- offload_caps = features->data;
- break;
- }
-
- data += le16_to_cpu(rel_info->len) + rel_info->pad_len;
- }
-
-out:
- release_firmware(fw);
-
- return offload_caps;
-}
-
-struct ieee80211_ops *
-mt7921_get_mac80211_ops(struct device *dev, void *drv_data, u8 *fw_features)
-{
- struct ieee80211_ops *ops;
-
- ops = devm_kmemdup(dev, &mt7921_ops, sizeof(mt7921_ops), GFP_KERNEL);
- if (!ops)
- return NULL;
-
- *fw_features = mt7921_get_offload_capability(dev, drv_data);
- if (!(*fw_features & MT7921_FW_CAP_CNM)) {
- ops->remain_on_channel = NULL;
- ops->cancel_remain_on_channel = NULL;
- ops->add_chanctx = NULL;
- ops->remove_chanctx = NULL;
- ops->change_chanctx = NULL;
- ops->assign_vif_chanctx = NULL;
- ops->unassign_vif_chanctx = NULL;
- ops->mgd_prepare_tx = NULL;
- ops->mgd_complete_tx = NULL;
- }
- return ops;
-}
-EXPORT_SYMBOL_GPL(mt7921_get_mac80211_ops);
-
-int mt7921_mac_init(struct mt7921_dev *dev)
+int mt7921_mac_init(struct mt792x_dev *dev)
{
int i;
@@ -264,17 +89,17 @@ int mt7921_mac_init(struct mt7921_dev *dev)
/* enable hardware rx header translation */
mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN);
- for (i = 0; i < MT7921_WTBL_SIZE; i++)
+ for (i = 0; i < MT792x_WTBL_SIZE; i++)
mt7921_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
for (i = 0; i < 2; i++)
- mt7921_mac_init_band(dev, i);
+ mt792x_mac_init_band(dev, i);
return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
EXPORT_SYMBOL_GPL(mt7921_mac_init);
-static int __mt7921_init_hardware(struct mt7921_dev *dev)
+static int __mt7921_init_hardware(struct mt792x_dev *dev)
{
int ret;
@@ -282,7 +107,7 @@ static int __mt7921_init_hardware(struct mt7921_dev *dev)
* which should be set before firmware download stage.
*/
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
- ret = mt7921_mcu_init(dev);
+ ret = mt792x_mcu_init(dev);
if (ret)
goto out;
@@ -297,21 +122,21 @@ out:
return ret;
}
-static int mt7921_init_hardware(struct mt7921_dev *dev)
+static int mt7921_init_hardware(struct mt792x_dev *dev)
{
int ret, i;
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
- for (i = 0; i < MT7921_MCU_INIT_RETRY_COUNT; i++) {
+ for (i = 0; i < MT792x_MCU_INIT_RETRY_COUNT; i++) {
ret = __mt7921_init_hardware(dev);
if (!ret)
break;
- mt7921_init_reset(dev);
+ mt792x_init_reset(dev);
}
- if (i == MT7921_MCU_INIT_RETRY_COUNT) {
+ if (i == MT792x_MCU_INIT_RETRY_COUNT) {
dev_err(dev->mt76.dev, "hardware init failed\n");
return ret;
}
@@ -319,26 +144,9 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
return 0;
}
-static int mt7921_init_wcid(struct mt7921_dev *dev)
-{
- int idx;
-
- /* Beacon and mgmt frames should occupy wcid 0 */
- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1);
- if (idx)
- return -ENOSPC;
-
- dev->mt76.global_wcid.idx = idx;
- dev->mt76.global_wcid.hw_key_idx = -1;
- dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
- rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
-
- return 0;
-}
-
static void mt7921_init_work(struct work_struct *work)
{
- struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
+ struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
init_work);
int ret;
@@ -362,13 +170,19 @@ static void mt7921_init_work(struct work_struct *work)
return;
}
+ ret = mt7921_thermal_init(&dev->phy);
+ if (ret) {
+ dev_err(dev->mt76.dev, "thermal init failed\n");
+ return;
+ }
+
/* we support chip reset now */
dev->hw_init_done = true;
mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable);
}
-int mt7921_register_device(struct mt7921_dev *dev)
+int mt7921_register_device(struct mt792x_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
int ret;
@@ -376,17 +190,17 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
- dev->mt76.tx_worker.fn = mt7921_tx_worker;
+ dev->mt76.tx_worker.fn = mt792x_tx_worker;
- INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work);
- INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
+ INIT_DELAYED_WORK(&dev->pm.ps_work, mt792x_pm_power_save_work);
+ INIT_WORK(&dev->pm.wake_work, mt792x_pm_wake_work);
spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
init_waitqueue_head(&dev->pm.wait);
if (mt76_is_sdio(&dev->mt76))
init_waitqueue_head(&dev->mt76.sdio.wait);
spin_lock_init(&dev->pm.txq_lock);
- INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
+ INIT_DELAYED_WORK(&dev->mphy.mac_work, mt792x_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work);
#if IS_ENABLED(CONFIG_IPV6)
@@ -395,17 +209,15 @@ int mt7921_register_device(struct mt7921_dev *dev)
#endif
skb_queue_head_init(&dev->phy.scan_event_list);
skb_queue_head_init(&dev->coredump.msg_list);
- INIT_LIST_HEAD(&dev->sta_poll_list);
- spin_lock_init(&dev->sta_poll_lock);
INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
INIT_WORK(&dev->init_work, mt7921_init_work);
INIT_WORK(&dev->phy.roc_work, mt7921_roc_work);
- timer_setup(&dev->phy.roc_timer, mt7921_roc_timer, 0);
+ timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);
init_waitqueue_head(&dev->phy.roc_wait);
- dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
+ dev->pm.idle_timeout = MT792x_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
if (!mt76_is_usb(&dev->mt76)) {
@@ -418,16 +230,17 @@ int mt7921_register_device(struct mt7921_dev *dev)
if (!mt76_is_mmio(&dev->mt76))
hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;
- mt7921_init_acpi_sar(dev);
+ mt792x_init_acpi_sar(dev);
- ret = mt7921_init_wcid(dev);
+ ret = mt792x_init_wcid(dev);
if (ret)
return ret;
- ret = mt7921_init_wiphy(hw);
+ ret = mt792x_init_wiphy(hw);
if (ret)
return ret;
+ hw->wiphy->reg_notifier = mt7921_regd_notifier;
dev->mphy.sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 1675bf520481..21f937454229 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -15,35 +15,7 @@
#define MT_WTBL_AC0_CTT_OFFSET 20
-static u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
-{
- return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
-}
-
-static struct mt76_wcid *mt7921_rx_get_wcid(struct mt7921_dev *dev,
- u16 idx, bool unicast)
-{
- struct mt7921_sta *sta;
- struct mt76_wcid *wcid;
-
- if (idx >= ARRAY_SIZE(dev->mt76.wcid))
- return NULL;
-
- wcid = rcu_dereference(dev->mt76.wcid[idx]);
- if (unicast || !wcid)
- return wcid;
-
- if (!wcid->sta)
- return NULL;
-
- sta = container_of(wcid, struct mt7921_sta, wcid);
- if (!sta->vif)
- return NULL;
-
- return &sta->vif->sta.wcid;
-}
-
-bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
+bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask)
{
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
@@ -52,7 +24,12 @@ bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
0, 5000);
}
-void mt7921_mac_sta_poll(struct mt7921_dev *dev)
+static u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
+{
+ return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
+}
+
+static void mt7921_mac_sta_poll(struct mt792x_dev *dev)
{
static const u8 ac_to_tid[] = {
[IEEE80211_AC_BE] = 0,
@@ -61,16 +38,16 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
[IEEE80211_AC_VO] = 6
};
struct ieee80211_sta *sta;
- struct mt7921_sta *msta;
+ struct mt792x_sta *msta;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
struct rate_info *rate;
s8 rssi[4];
int i;
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&dev->sta_poll_list, &sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
while (true) {
bool clear = false;
@@ -78,15 +55,15 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
u16 idx;
u8 bw;
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&sta_poll_list)) {
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
break;
}
msta = list_first_entry(&sta_poll_list,
- struct mt7921_sta, poll_list);
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ struct mt792x_sta, wcid.poll_list);
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
idx = msta->wcid.idx;
addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET);
@@ -183,56 +160,9 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
}
}
-EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll);
-
-static void
-mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy,
- struct mt76_rx_status *status, u8 chfreq)
-{
- if (chfreq > 180) {
- status->band = NL80211_BAND_6GHZ;
- chfreq = (chfreq - 181) * 4 + 1;
- } else if (chfreq > 14) {
- status->band = NL80211_BAND_5GHZ;
- } else {
- status->band = NL80211_BAND_2GHZ;
- }
- status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
-}
-
-static void
-mt7921_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
-{
- struct sk_buff *skb = priv;
- struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
-
- if (status->signal > 0)
- return;
-
- if (!ether_addr_equal(vif->addr, hdr->addr1))
- return;
-
- ewma_rssi_add(&mvif->rssi, -status->signal);
-}
-
-static void
-mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
-
- if (!ieee80211_is_assoc_resp(hdr->frame_control) &&
- !ieee80211_is_auth(hdr->frame_control))
- return;
-
- ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7921_mac_rssi_iter, skb);
-}
static int
-mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
{
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
@@ -241,7 +171,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
u16 hdr_gap;
__le32 *rxv = NULL, *rxd = (__le32 *)skb->data;
struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt7921_phy *phy = &dev->phy;
+ struct mt792x_phy *phy = &dev->phy;
struct ieee80211_supported_band *sband;
u32 csum_status = *(u32 *)skb->cb;
u32 rxd0 = le32_to_cpu(rxd[0]);
@@ -249,7 +179,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
u32 rxd2 = le32_to_cpu(rxd[2]);
u32 rxd3 = le32_to_cpu(rxd[3]);
u32 rxd4 = le32_to_cpu(rxd[4]);
- struct mt7921_sta *msta = NULL;
+ struct mt792x_sta *msta = NULL;
u16 seq_ctrl = 0;
__le16 fc = 0;
u8 mode = 0;
@@ -277,17 +207,18 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3);
unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
- status->wcid = mt7921_rx_get_wcid(dev, idx, unicast);
+ status->wcid = mt792x_rx_get_wcid(dev, idx, unicast);
if (status->wcid) {
- msta = container_of(status->wcid, struct mt7921_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ msta = container_of(status->wcid, struct mt792x_sta, wcid);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
- mt7921_get_status_freq_info(dev, mphy, status, chfreq);
+ mt792x_get_status_freq_info(status, chfreq);
switch (status->band) {
case NL80211_BAND_5GHZ:
@@ -496,7 +427,7 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_8023;
}
- mt7921_mac_assoc_rssi(dev, skb);
+ mt792x_mac_assoc_rssi(dev, skb);
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
@@ -511,33 +442,9 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
return 0;
}
-static void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
+void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data)
{
- struct mt7921_sta *msta;
- u16 fc, tid;
- u32 val;
-
- if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
- return;
-
- tid = le32_get_bits(txwi[1], MT_TXD1_TID);
- if (tid >= 6) /* skip VO queue */
- return;
-
- val = le32_to_cpu(txwi[2]);
- fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
- FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
- if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
- return;
-
- msta = (struct mt7921_sta *)sta->drv_priv;
- if (!test_and_set_bit(tid, &msta->ampdu_state))
- ieee80211_start_tx_ba_session(sta, tid, 0);
-}
-
-void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
-{
- struct mt7921_sta *msta = NULL;
+ struct mt792x_sta *msta = NULL;
struct mt76_wcid *wcid;
__le32 *txs_data = data;
u16 wcidx;
@@ -552,7 +459,7 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
if (pid < MT_PACKET_ID_FIRST)
return;
- if (wcidx >= MT7921_WTBL_SIZE)
+ if (wcidx >= MT792x_WTBL_SIZE)
return;
rcu_read_lock();
@@ -561,59 +468,29 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
if (!wcid)
goto out;
- msta = container_of(wcid, struct mt7921_sta, wcid);
+ msta = container_of(wcid, struct mt792x_sta, wcid);
mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data);
if (!wcid->sta)
goto out;
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
out:
rcu_read_unlock();
}
-void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, bool clear_status,
- struct list_head *free_list)
-{
- struct mt76_dev *mdev = &dev->mt76;
- __le32 *txwi;
- u16 wcid_idx;
-
- mt76_connac_txp_skb_unmap(mdev, t);
- if (!t->skb)
- goto out;
-
- txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
- if (sta) {
- struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
-
- if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7921_tx_check_aggr(sta, txwi);
-
- wcid_idx = wcid->idx;
- } else {
- wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
- }
-
- __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
-out:
- t->skb = NULL;
- mt76_put_txwi(mdev, t);
-}
-EXPORT_SYMBOL_GPL(mt7921_txwi_free);
-
-static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
+static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len)
{
struct mt76_connac_tx_free *free = data;
__le32 *tx_info = (__le32 *)(data + sizeof(*free));
struct mt76_dev *mdev = &dev->mt76;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid = NULL;
struct sk_buff *skb, *tmp;
void *end = data + len;
LIST_HEAD(free_list);
@@ -636,8 +513,7 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
* 1'b0: msdu_id with the same 'wcid pair' as above.
*/
if (info & MT_TX_FREE_PAIR) {
- struct mt7921_sta *msta;
- struct mt76_wcid *wcid;
+ struct mt792x_sta *msta;
u16 idx;
count++;
@@ -647,22 +523,29 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
if (!sta)
continue;
- msta = container_of(wcid, struct mt7921_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ msta = container_of(wcid, struct mt792x_sta, wcid);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &mdev->sta_poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
continue;
}
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
stat = FIELD_GET(MT_TX_FREE_STATUS, info);
+ if (wcid) {
+ wcid->stats.tx_retries +=
+ FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
+ wcid->stats.tx_failed += !!stat;
+ }
+
txwi = mt76_token_release(mdev, msdu, &wake);
if (!txwi)
continue;
- mt7921_txwi_free(dev, txwi, sta, stat, &free_list);
+ mt76_connac2_txwi_free(mdev, txwi, sta, &free_list);
}
if (wake)
@@ -682,7 +565,7 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
__le32 *rxd = (__le32 *)data;
__le32 *end = (__le32 *)&rxd[len / 4];
enum rx_pkt_type type;
@@ -707,7 +590,7 @@ EXPORT_SYMBOL_GPL(mt7921_rx_check);
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
__le32 *rxd = (__le32 *)skb->data;
__le32 *end = (__le32 *)&skb->data[skb->len];
enum rx_pkt_type type;
@@ -747,128 +630,12 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb);
-void mt7921_mac_reset_counters(struct mt7921_phy *phy)
-{
- struct mt7921_dev *dev = phy->dev;
- int i;
-
- for (i = 0; i < 4; i++) {
- mt76_rr(dev, MT_TX_AGG_CNT(0, i));
- mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
- }
-
- dev->mt76.phy.survey_time = ktime_get_boottime();
- memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
-
- /* reset airtime counters */
- mt76_rr(dev, MT_MIB_SDR9(0));
- mt76_rr(dev, MT_MIB_SDR36(0));
- mt76_rr(dev, MT_MIB_SDR37(0));
-
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
- mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
-}
-
-void mt7921_mac_set_timing(struct mt7921_phy *phy)
-{
- s16 coverage_class = phy->coverage_class;
- struct mt7921_dev *dev = phy->dev;
- u32 val, reg_offset;
- u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
- FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
- u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
- FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
- bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
- int sifs = is_2ghz ? 10 : 16, offset;
-
- if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
- return;
-
- mt76_set(dev, MT_ARB_SCR(0),
- MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
- udelay(1);
-
- offset = 3 * coverage_class;
- reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
- FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
-
- mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset);
- mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset);
- mt76_wr(dev, MT_TMAC_ICR0(0),
- FIELD_PREP(MT_IFS_EIFS, 360) |
- FIELD_PREP(MT_IFS_RIFS, 2) |
- FIELD_PREP(MT_IFS_SIFS, sifs) |
- FIELD_PREP(MT_IFS_SLOT, phy->slottime));
-
- if (phy->slottime < 20 || !is_2ghz)
- val = MT7921_CFEND_RATE_DEFAULT;
- else
- val = MT7921_CFEND_RATE_11B;
-
- mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val);
- mt76_clear(dev, MT_ARB_SCR(0),
- MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
-}
-
-static u8
-mt7921_phy_get_nf(struct mt7921_phy *phy, int idx)
-{
- return 0;
-}
-
-static void
-mt7921_phy_update_channel(struct mt76_phy *mphy, int idx)
-{
- struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76);
- struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv;
- struct mt76_channel_state *state;
- u64 busy_time, tx_time, rx_time, obss_time;
- int nf;
-
- busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
- MT_MIB_SDR9_BUSY_MASK);
- tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
- MT_MIB_SDR36_TXTIME_MASK);
- rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
- MT_MIB_SDR37_RXTIME_MASK);
- obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
- MT_MIB_OBSSTIME_MASK);
-
- nf = mt7921_phy_get_nf(phy, idx);
- if (!phy->noise)
- phy->noise = nf << 4;
- else if (nf)
- phy->noise += nf - (phy->noise >> 4);
-
- state = mphy->chan_state;
- state->cc_busy += busy_time;
- state->cc_tx += tx_time;
- state->cc_rx += rx_time + obss_time;
- state->cc_bss_rx += rx_time;
- state->noise = -(phy->noise >> 4);
-}
-
-void mt7921_update_channel(struct mt76_phy *mphy)
-{
- struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76);
-
- if (mt76_connac_pm_wake(mphy, &dev->pm))
- return;
-
- mt7921_phy_update_channel(mphy, 0);
- /* reset obss airtime */
- mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
-
- mt76_connac_power_save_sched(mphy, &dev->pm);
-}
-EXPORT_SYMBOL_GPL(mt7921_update_channel);
-
static void
mt7921_vif_connect_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mvif->phy->dev;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mvif->phy->dev;
struct ieee80211_hw *hw = mt76_hw(dev);
if (vif->type == NL80211_IFTYPE_STATION)
@@ -889,7 +656,7 @@ mt7921_vif_connect_iter(void *priv, u8 *mac,
/* system error recovery */
void mt7921_mac_reset_work(struct work_struct *work)
{
- struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
+ struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
reset_work);
struct ieee80211_hw *hw = mt76_hw(dev);
struct mt76_connac_pm *pm = &dev->pm;
@@ -905,7 +672,7 @@ void mt7921_mac_reset_work(struct work_struct *work)
for (i = 0; i < 10; i++) {
mutex_lock(&dev->mt76.mutex);
- ret = mt7921_dev_reset(dev);
+ ret = mt792x_dev_reset(dev);
mutex_unlock(&dev->mt76.mutex);
if (!ret)
@@ -932,185 +699,12 @@ void mt7921_mac_reset_work(struct work_struct *work)
mt76_connac_power_save_sched(&dev->mt76.phy, pm);
}
-void mt7921_reset(struct mt76_dev *mdev)
-{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
- struct mt76_connac_pm *pm = &dev->pm;
-
- if (!dev->hw_init_done)
- return;
-
- if (dev->hw_full_reset)
- return;
-
- if (pm->suspended)
- return;
-
- queue_work(dev->mt76.wq, &dev->reset_work);
-}
-EXPORT_SYMBOL_GPL(mt7921_reset);
-
-void mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
-{
- struct mt7921_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
- int i, aggr0 = 0, aggr1;
- u32 val;
-
- mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0),
- MT_MIB_SDR3_FCS_ERR_MASK);
- mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0),
- MT_MIB_ACK_FAIL_COUNT_MASK);
- mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0),
- MT_MIB_BA_FAIL_COUNT_MASK);
- mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0),
- MT_MIB_RTS_COUNT_MASK);
- mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0),
- MT_MIB_RTS_FAIL_COUNT_MASK);
-
- mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0));
- mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0));
- mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0));
-
- val = mt76_rr(dev, MT_MIB_SDR32(0));
- mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val);
- mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val);
-
- val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0));
- mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val);
- mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val);
-
- val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0));
- mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val);
- mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val);
- mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val);
- mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val);
-
- mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0));
- mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0));
- mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0));
- mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0));
-
- for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
- val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
- mib->tx_amsdu[i] += val;
- mib->tx_amsdu_cnt += val;
- }
-
- for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) {
- u32 val2;
-
- val = mt76_rr(dev, MT_TX_AGG_CNT(0, i));
- val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
-
- phy->mt76->aggr_stats[aggr0++] += val & 0xffff;
- phy->mt76->aggr_stats[aggr0++] += val >> 16;
- phy->mt76->aggr_stats[aggr1++] += val2 & 0xffff;
- phy->mt76->aggr_stats[aggr1++] += val2 >> 16;
- }
-}
-
-void mt7921_mac_work(struct work_struct *work)
-{
- struct mt7921_phy *phy;
- struct mt76_phy *mphy;
-
- mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
- mac_work.work);
- phy = mphy->priv;
-
- mt7921_mutex_acquire(phy->dev);
-
- mt76_update_survey(mphy);
- if (++mphy->mac_work_count == 2) {
- mphy->mac_work_count = 0;
-
- mt7921_mac_update_mib_stats(phy);
- }
-
- mt7921_mutex_release(phy->dev);
-
- mt76_tx_status_check(mphy->dev, false);
- ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
- MT7921_WATCHDOG_TIME);
-}
-
-void mt7921_pm_wake_work(struct work_struct *work)
-{
- struct mt7921_dev *dev;
- struct mt76_phy *mphy;
-
- dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
- pm.wake_work);
- mphy = dev->phy.mt76;
-
- if (!mt7921_mcu_drv_pmctrl(dev)) {
- struct mt76_dev *mdev = &dev->mt76;
- int i;
-
- if (mt76_is_sdio(mdev)) {
- mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- mt76_worker_schedule(&mdev->sdio.txrx_worker);
- } else {
- local_bh_disable();
- mt76_for_each_q_rx(mdev, i)
- napi_schedule(&mdev->napi[i]);
- local_bh_enable();
- mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- mt76_connac_tx_cleanup(mdev);
- }
- if (test_bit(MT76_STATE_RUNNING, &mphy->state))
- ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
- MT7921_WATCHDOG_TIME);
- }
-
- ieee80211_wake_queues(mphy->hw);
- wake_up(&dev->pm.wait);
-}
-
-void mt7921_pm_power_save_work(struct work_struct *work)
-{
- struct mt7921_dev *dev;
- unsigned long delta;
- struct mt76_phy *mphy;
-
- dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
- pm.ps_work.work);
- mphy = dev->phy.mt76;
-
- delta = dev->pm.idle_timeout;
- if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) ||
- dev->fw_assert)
- goto out;
-
- if (mutex_is_locked(&dev->mt76.mutex))
- /* if mt76 mutex is held we should not put the device
- * to sleep since we are currently accessing device
- * register map. We need to wait for the next power_save
- * trigger.
- */
- goto out;
-
- if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
- delta = dev->pm.last_activity + delta - jiffies;
- goto out;
- }
-
- if (!mt7921_mcu_fw_pmctrl(dev)) {
- cancel_delayed_work_sync(&mphy->mac_work);
- return;
- }
-out:
- queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
-}
-
void mt7921_coredump_work(struct work_struct *work)
{
- struct mt7921_dev *dev;
+ struct mt792x_dev *dev;
char *dump, *data;
- dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
+ dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,
coredump.work.work);
if (time_is_after_jiffies(dev->coredump.last_activity +
@@ -1149,12 +743,12 @@ void mt7921_coredump_work(struct work_struct *work)
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
GFP_KERNEL);
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
}
/* usb_sdio */
static void
-mt7921_usb_sdio_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid,
+mt7921_usb_sdio_write_txwi(struct mt792x_dev *dev, struct mt76_wcid *wcid,
enum mt76_txq_id qid, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key, int pid,
struct sk_buff *skb)
@@ -1171,7 +765,7 @@ int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct sk_buff *skb = tx_info->skb;
@@ -1180,11 +774,15 @@ int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (unlikely(tx_info->skb->len <= ETH_HLEN))
return -EINVAL;
+ err = skb_cow_head(skb, MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE);
+ if (err)
+ return err;
+
if (!wcid)
wcid = &dev->mt76.global_wcid;
if (sta) {
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
if (time_after(jiffies, msta->last_txs + HZ / 4)) {
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -1224,7 +822,7 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
sta = wcid_to_sta(wcid);
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
- mt7921_tx_check_aggr(sta, txwi);
+ mt76_connac2_tx_check_aggr(sta, txwi);
skb_pull(e->skb, headroom);
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
@@ -1233,11 +831,11 @@ EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_complete_skb);
bool mt7921_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt7921_mac_sta_poll(dev);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return false;
}
@@ -1246,8 +844,8 @@ EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_status_data);
#if IS_ENABLED(CONFIG_IPV6)
void mt7921_set_ipv6_ns_work(struct work_struct *work)
{
- struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
- ipv6_ns_work);
+ struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
+ ipv6_ns_work);
struct sk_buff *skb;
int ret = 0;
@@ -1257,10 +855,10 @@ void mt7921_set_ipv6_ns_work(struct work_struct *work)
if (!skb)
break;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_UNI_CMD(OFFLOAD), true);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
} while (!ret);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 3b6adb29cbef..0844d28b3223 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -10,7 +10,7 @@
#include "mcu.h"
static int
-mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
+mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data)
{
int i, idx = 0;
@@ -185,7 +185,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
return idx;
}
-void mt7921_set_stream_he_caps(struct mt7921_phy *phy)
+void mt7921_set_stream_he_caps(struct mt792x_phy *phy)
{
struct ieee80211_sband_iftype_data *data;
struct ieee80211_supported_band *band;
@@ -219,7 +219,7 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy)
}
}
-int __mt7921_start(struct mt7921_phy *phy)
+int __mt7921_start(struct mt792x_phy *phy)
{
struct mt76_phy *mphy = phy->mt76;
int err;
@@ -240,11 +240,11 @@ int __mt7921_start(struct mt7921_phy *phy)
if (err)
return err;
- mt7921_mac_reset_counters(phy);
+ mt792x_mac_reset_counters(phy);
set_bit(MT76_STATE_RUNNING, &mphy->state);
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
- MT7921_WATCHDOG_TIME);
+ MT792x_WATCHDOG_TIME);
return 0;
}
@@ -252,20 +252,20 @@ EXPORT_SYMBOL_GPL(__mt7921_start);
static int mt7921_start(struct ieee80211_hw *hw)
{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
int err;
- mt7921_mutex_acquire(phy->dev);
+ mt792x_mutex_acquire(phy->dev);
err = __mt7921_start(phy);
- mt7921_mutex_release(phy->dev);
+ mt792x_mutex_release(phy->dev);
return err;
}
void mt7921_stop(struct ieee80211_hw *hw)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
cancel_delayed_work_sync(&phy->mt76->mac_work);
@@ -274,26 +274,26 @@ void mt7921_stop(struct ieee80211_hw *hw)
cancel_work_sync(&dev->reset_work);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
EXPORT_SYMBOL_GPL(mt7921_stop);
-static int mt7921_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int
+mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
struct mt76_txq *mtxq;
int idx, ret = 0;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
- if (mvif->mt76.idx >= MT7921_MAX_INTERFACES) {
+ if (mvif->mt76.idx >= MT792x_MAX_INTERFACES) {
ret = -ENOSPC;
goto out;
}
@@ -311,9 +311,9 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
- idx = MT7921_WTBL_RESERVED - mvif->mt76.idx;
+ idx = MT792x_WTBL_RESERVED - mvif->mt76.idx;
- INIT_LIST_HEAD(&mvif->sta.poll_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
mvif->sta.wcid.hw_key_idx = -1;
@@ -333,89 +333,55 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return ret;
}
-static void mt7921_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_sta *msta = &mvif->sta;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- int idx = msta->wcid.idx;
-
- mt7921_mutex_acquire(dev);
- mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
- mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false);
-
- rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
-
- dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
- phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
- mt7921_mutex_release(dev);
-
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
-
- mt76_packet_id_flush(&dev->mt76, &msta->wcid);
-}
-
static void mt7921_roc_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_phy *phy = priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_phy *phy = priv;
mt7921_mcu_abort_roc(phy, mvif, phy->roc_token_id);
}
void mt7921_roc_work(struct work_struct *work)
{
- struct mt7921_phy *phy;
+ struct mt792x_phy *phy;
- phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy,
+ phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
roc_work);
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return;
- mt7921_mutex_acquire(phy->dev);
+ mt792x_mutex_acquire(phy->dev);
ieee80211_iterate_active_interfaces(phy->mt76->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, phy);
- mt7921_mutex_release(phy->dev);
+ mt792x_mutex_release(phy->dev);
ieee80211_remain_on_channel_expired(phy->mt76->hw);
}
-void mt7921_roc_timer(struct timer_list *timer)
-{
- struct mt7921_phy *phy = from_timer(phy, timer, roc_timer);
-
- ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
-}
-
-static int mt7921_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif)
+static int mt7921_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif)
{
int err = 0;
del_timer_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
- mt7921_mutex_acquire(phy->dev);
+ mt792x_mutex_acquire(phy->dev);
if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
- mt7921_mutex_release(phy->dev);
+ mt792x_mutex_release(phy->dev);
return err;
}
-static int mt7921_set_roc(struct mt7921_phy *phy,
- struct mt7921_vif *vif,
+static int mt7921_set_roc(struct mt792x_phy *phy,
+ struct mt792x_vif *vif,
struct ieee80211_channel *chan,
int duration,
enum mt7921_roc_req type)
@@ -450,13 +416,13 @@ static int mt7921_remain_on_channel(struct ieee80211_hw *hw,
int duration,
enum ieee80211_roc_type type)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
int err;
- mt7921_mutex_acquire(phy->dev);
+ mt792x_mutex_acquire(phy->dev);
err = mt7921_set_roc(phy, mvif, chan, duration, MT7921_ROC_REQ_ROC);
- mt7921_mutex_release(phy->dev);
+ mt792x_mutex_release(phy->dev);
return err;
}
@@ -464,20 +430,20 @@ static int mt7921_remain_on_channel(struct ieee80211_hw *hw,
static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
return mt7921_abort_roc(phy, mvif);
}
-static int mt7921_set_channel(struct mt7921_phy *phy)
+static int mt7921_set_channel(struct mt792x_phy *phy)
{
- struct mt7921_dev *dev = phy->dev;
+ struct mt792x_dev *dev = phy->dev;
int ret;
cancel_delayed_work_sync(&phy->mt76->mac_work);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
set_bit(MT76_RESET, &phy->mt76->state);
mt76_set_channel(phy->mt76);
@@ -486,18 +452,18 @@ static int mt7921_set_channel(struct mt7921_phy *phy)
if (ret)
goto out;
- mt7921_mac_set_timing(phy);
+ mt792x_mac_set_timeing(phy);
- mt7921_mac_reset_counters(phy);
+ mt792x_mac_reset_counters(phy);
phy->noise = 0;
out:
clear_bit(MT76_RESET, &phy->mt76->state);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
mt76_worker_schedule(&dev->mt76.tx_worker);
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work,
- MT7921_WATCHDOG_TIME);
+ MT792x_WATCHDOG_TIME);
return ret;
}
@@ -506,9 +472,9 @@ static int mt7921_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 mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_sta *msta = sta ? (struct mt7921_sta *)sta->drv_priv :
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv :
&mvif->sta;
struct mt76_wcid *wcid = &msta->wcid;
u8 *wcid_keyidx = &wcid->hw_key_idx;
@@ -546,7 +512,7 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (cmd == SET_KEY) {
*wcid_keyidx = idx;
@@ -570,7 +536,7 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key, MCU_UNI_CMD(STA_REC_UPDATE),
&mvif->wep_sta->wcid, cmd);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -578,7 +544,7 @@ out:
static void
mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- struct mt7921_dev *dev = priv;
+ struct mt792x_dev *dev = priv;
struct ieee80211_hw *hw = mt76_hw(dev);
bool pm_enable = dev->pm.enable;
int err;
@@ -599,7 +565,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
static void
mt7921_sniffer_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
- struct mt7921_dev *dev = priv;
+ struct mt792x_dev *dev = priv;
struct ieee80211_hw *hw = mt76_hw(dev);
struct mt76_connac_pm *pm = &dev->pm;
bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
@@ -614,7 +580,7 @@ mt7921_sniffer_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
mt7921_mcu_set_beacon_filter(dev, vif, false);
}
-void mt7921_set_runtime_pm(struct mt7921_dev *dev)
+void mt7921_set_runtime_pm(struct mt792x_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
struct mt76_connac_pm *pm = &dev->pm;
@@ -630,8 +596,8 @@ void mt7921_set_runtime_pm(struct mt7921_dev *dev)
static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
int ret = 0;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -642,7 +608,7 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw);
}
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (changed & IEEE80211_CONF_CHANGE_POWER) {
ret = mt7921_set_tx_sar_pwr(hw, NULL);
@@ -657,25 +623,11 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
}
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return ret;
}
-static int
-mt7921_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- unsigned int link_id, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
-
- /* no need to update right away, we'll get BSS_CHANGED_QOS */
- queue = mt76_connac_lmac_mapping(queue);
- mvif->queue_params[queue] = *params;
-
- return 0;
-}
-
static void mt7921_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -686,7 +638,7 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
#define MT7921_FILTER_OTHER_BSS BIT(6)
#define MT7921_FILTER_ENABLE BIT(31)
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
u32 flags = MT7921_FILTER_ENABLE;
#define MT7921_FILTER(_fif, _type) do { \
@@ -698,9 +650,9 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
MT7921_FILTER(FIF_CONTROL, CONTROL);
MT7921_FILTER(FIF_OTHER_BSS, OTHER_BSS);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt7921_mcu_set_rxfilter(dev, flags, 0, 0);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
*total_flags &= (FIF_OTHER_BSS | FIF_FCSFAIL | FIF_CONTROL);
}
@@ -710,17 +662,17 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *info,
u64 changed)
{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = info->use_short_slot ? 9 : 20;
if (slottime != phy->slottime) {
phy->slottime = slottime;
- mt7921_mac_set_timing(phy);
+ mt792x_mac_set_timeing(phy);
}
}
@@ -743,28 +695,28 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ARP_FILTER) {
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76,
info);
}
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
int ret, idx;
- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1);
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
- INIT_LIST_HEAD(&msta->poll_list);
+ INIT_LIST_HEAD(&msta->wcid.poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
@@ -796,11 +748,11 @@ EXPORT_SYMBOL_GPL(mt7921_mac_sta_add);
void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
@@ -814,15 +766,15 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_assoc);
void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
@@ -832,7 +784,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
if (vif->type == NL80211_IFTYPE_STATION) {
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
mvif->wep_sta = NULL;
ewma_rssi_init(&mvif->rssi);
@@ -842,76 +794,22 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mvif->ctx);
}
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);
-void mt7921_tx_worker(struct mt76_worker *w)
-{
- struct mt7921_dev *dev = container_of(w, struct mt7921_dev,
- mt76.tx_worker);
-
- if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
- queue_work(dev->mt76.wq, &dev->pm.wake_work);
- return;
- }
-
- mt76_txq_schedule_all(&dev->mphy);
- mt76_connac_pm_unref(&dev->mphy, &dev->pm);
-}
-
-static void mt7921_tx(struct ieee80211_hw *hw,
- struct ieee80211_tx_control *control,
- struct sk_buff *skb)
-{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt76_phy *mphy = hw->priv;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_vif *vif = info->control.vif;
- struct mt76_wcid *wcid = &dev->mt76.global_wcid;
- int qid;
-
- if (control->sta) {
- struct mt7921_sta *sta;
-
- sta = (struct mt7921_sta *)control->sta->drv_priv;
- wcid = &sta->wcid;
- }
-
- if (vif && !control->sta) {
- struct mt7921_vif *mvif;
-
- mvif = (struct mt7921_vif *)vif->drv_priv;
- wcid = &mvif->sta.wcid;
- }
-
- if (mt76_connac_pm_ref(mphy, &dev->pm)) {
- mt76_tx(mphy, control->sta, wcid, skb);
- mt76_connac_pm_unref(mphy, &dev->pm);
- return;
- }
-
- qid = skb_get_queue_mapping(skb);
- if (qid >= MT_TXQ_PSD) {
- qid = IEEE80211_AC_BE;
- skb_set_queue_mapping(skb, qid);
- }
-
- mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb);
-}
-
static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, 0);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
@@ -921,10 +819,10 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
enum ieee80211_ampdu_mlme_action action = params->action;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct ieee80211_sta *sta = params->sta;
struct ieee80211_txq *txq = sta->txq[params->tid];
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
u16 tid = params->tid;
u16 ssn = params->ssn;
struct mt76_txq *mtxq;
@@ -935,7 +833,7 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mtxq = (struct mt76_txq *)txq->drv_priv;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
@@ -954,21 +852,21 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
mt7921_mcu_uni_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
- set_bit(tid, &msta->ampdu_state);
+ set_bit(tid, &msta->wcid.ampdu_state);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
mt7921_mcu_uni_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return ret;
}
@@ -979,289 +877,22 @@ static int mt7921_sta_state(struct ieee80211_hw *hw,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
if (dev->pm.ds_enable) {
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
return mt76_sta_state(hw, vif, sta, old_state, new_state);
}
-static int
-mt7921_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
-{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mib_stats *mib = &phy->mib;
-
- mt7921_mutex_acquire(phy->dev);
-
- stats->dot11RTSSuccessCount = mib->rts_cnt;
- stats->dot11RTSFailureCount = mib->rts_retries_cnt;
- stats->dot11FCSErrorCount = mib->fcs_err_cnt;
- stats->dot11ACKFailureCount = mib->ack_fail_cnt;
-
- mt7921_mutex_release(phy->dev);
-
- return 0;
-}
-
-static const char mt7921_gstrings_stats[][ETH_GSTRING_LEN] = {
- /* tx counters */
- "tx_ampdu_cnt",
- "tx_mpdu_attempts",
- "tx_mpdu_success",
- "tx_pkt_ebf_cnt",
- "tx_pkt_ibf_cnt",
- "tx_ampdu_len:0-1",
- "tx_ampdu_len:2-10",
- "tx_ampdu_len:11-19",
- "tx_ampdu_len:20-28",
- "tx_ampdu_len:29-37",
- "tx_ampdu_len:38-46",
- "tx_ampdu_len:47-55",
- "tx_ampdu_len:56-79",
- "tx_ampdu_len:80-103",
- "tx_ampdu_len:104-127",
- "tx_ampdu_len:128-151",
- "tx_ampdu_len:152-175",
- "tx_ampdu_len:176-199",
- "tx_ampdu_len:200-223",
- "tx_ampdu_len:224-247",
- "ba_miss_count",
- "tx_beamformer_ppdu_iBF",
- "tx_beamformer_ppdu_eBF",
- "tx_beamformer_rx_feedback_all",
- "tx_beamformer_rx_feedback_he",
- "tx_beamformer_rx_feedback_vht",
- "tx_beamformer_rx_feedback_ht",
- "tx_msdu_pack_1",
- "tx_msdu_pack_2",
- "tx_msdu_pack_3",
- "tx_msdu_pack_4",
- "tx_msdu_pack_5",
- "tx_msdu_pack_6",
- "tx_msdu_pack_7",
- "tx_msdu_pack_8",
- /* rx counters */
- "rx_mpdu_cnt",
- "rx_ampdu_cnt",
- "rx_ampdu_bytes_cnt",
- "rx_ba_cnt",
- /* per vif counters */
- "v_tx_mode_cck",
- "v_tx_mode_ofdm",
- "v_tx_mode_ht",
- "v_tx_mode_ht_gf",
- "v_tx_mode_vht",
- "v_tx_mode_he_su",
- "v_tx_mode_he_ext_su",
- "v_tx_mode_he_tb",
- "v_tx_mode_he_mu",
- "v_tx_bw_20",
- "v_tx_bw_40",
- "v_tx_bw_80",
- "v_tx_bw_160",
- "v_tx_mcs_0",
- "v_tx_mcs_1",
- "v_tx_mcs_2",
- "v_tx_mcs_3",
- "v_tx_mcs_4",
- "v_tx_mcs_5",
- "v_tx_mcs_6",
- "v_tx_mcs_7",
- "v_tx_mcs_8",
- "v_tx_mcs_9",
- "v_tx_mcs_10",
- "v_tx_mcs_11",
-};
-
-static void
-mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 sset, u8 *data)
-{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
-
- if (sset != ETH_SS_STATS)
- return;
-
- memcpy(data, *mt7921_gstrings_stats, sizeof(mt7921_gstrings_stats));
-
- if (mt76_is_sdio(&dev->mt76))
- return;
-
- data += sizeof(mt7921_gstrings_stats);
- page_pool_ethtool_stats_get_strings(data);
-}
-
-static int
-mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- int sset)
-{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
-
- if (sset != ETH_SS_STATS)
- return 0;
-
- if (mt76_is_sdio(&dev->mt76))
- return ARRAY_SIZE(mt7921_gstrings_stats);
-
- return ARRAY_SIZE(mt7921_gstrings_stats) +
- page_pool_ethtool_stats_get_count();
-}
-
-static void
-mt7921_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
-{
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct mt76_ethtool_worker_info *wi = wi_data;
-
- if (msta->vif->mt76.idx != wi->idx)
- return;
-
- mt76_ethtool_worker(wi, &msta->wcid.stats, false);
-}
-
-static
-void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ethtool_stats *stats, u64 *data)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- int stats_size = ARRAY_SIZE(mt7921_gstrings_stats);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
- struct mt76_ethtool_worker_info wi = {
- .data = data,
- .idx = mvif->mt76.idx,
- };
- int i, ei = 0;
-
- mt7921_mutex_acquire(dev);
-
- mt7921_mac_update_mib_stats(phy);
-
- data[ei++] = mib->tx_ampdu_cnt;
- data[ei++] = mib->tx_mpdu_attempts_cnt;
- data[ei++] = mib->tx_mpdu_success_cnt;
- data[ei++] = mib->tx_pkt_ebf_cnt;
- data[ei++] = mib->tx_pkt_ibf_cnt;
-
- /* Tx ampdu stat */
- for (i = 0; i < 15; i++)
- data[ei++] = phy->mt76->aggr_stats[i];
-
- data[ei++] = phy->mib.ba_miss_cnt;
-
- /* Tx Beamformer monitor */
- data[ei++] = mib->tx_bf_ibf_ppdu_cnt;
- data[ei++] = mib->tx_bf_ebf_ppdu_cnt;
-
- /* Tx Beamformer Rx feedback monitor */
- data[ei++] = mib->tx_bf_rx_fb_all_cnt;
- data[ei++] = mib->tx_bf_rx_fb_he_cnt;
- data[ei++] = mib->tx_bf_rx_fb_vht_cnt;
- data[ei++] = mib->tx_bf_rx_fb_ht_cnt;
-
- /* Tx amsdu info (pack-count histogram) */
- for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++)
- data[ei++] = mib->tx_amsdu[i];
-
- /* rx counters */
- data[ei++] = mib->rx_mpdu_cnt;
- data[ei++] = mib->rx_ampdu_cnt;
- data[ei++] = mib->rx_ampdu_bytes_cnt;
- data[ei++] = mib->rx_ba_cnt;
-
- /* Add values for all stations owned by this vif */
- wi.initial_stat_idx = ei;
- ieee80211_iterate_stations_atomic(hw, mt7921_ethtool_worker, &wi);
-
- mt7921_mutex_release(dev);
-
- if (!wi.sta_count)
- return;
-
- ei += wi.worker_stat_count;
-
- if (!mt76_is_sdio(&dev->mt76)) {
- mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
- stats_size += page_pool_ethtool_stats_get_count();
- }
-
- if (ei != stats_size)
- dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %d", ei, stats_size);
-}
-
-static u64
-mt7921_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- u8 omac_idx = mvif->mt76.omac_idx;
- union {
- u64 t64;
- u32 t32[2];
- } tsf;
- u16 n;
-
- mt7921_mutex_acquire(dev);
-
- n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx;
- /* TSF software read */
- mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_MODE);
- tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(0));
- tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(0));
-
- mt7921_mutex_release(dev);
-
- return tsf.t64;
-}
-
-static void
-mt7921_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u64 timestamp)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- u8 omac_idx = mvif->mt76.omac_idx;
- union {
- u64 t64;
- u32 t32[2];
- } tsf = { .t64 = timestamp, };
- u16 n;
-
- mt7921_mutex_acquire(dev);
-
- n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx;
- mt76_wr(dev, MT_LPON_UTTR0(0), tsf.t32[0]);
- mt76_wr(dev, MT_LPON_UTTR1(0), tsf.t32[1]);
- /* TSF software overwrite */
- mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_WRITE);
-
- mt7921_mutex_release(dev);
-}
-
-static void
-mt7921_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
-{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = phy->dev;
-
- mt7921_mutex_acquire(dev);
- phy->coverage_class = max_t(s16, coverage_class, 0);
- mt7921_mac_set_timing(phy);
- mt7921_mutex_release(dev);
-}
-
void mt7921_scan_work(struct work_struct *work)
{
- struct mt7921_phy *phy;
+ struct mt792x_phy *phy;
- phy = (struct mt7921_phy *)container_of(work, struct mt7921_phy,
+ phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
scan_work.work);
while (true) {
@@ -1294,13 +925,13 @@ static int
mt7921_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt76_connac_mcu_hw_scan(mphy, vif, req);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -1308,12 +939,12 @@ mt7921_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
static void
mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt76_connac_mcu_cancel_hw_scan(mphy, vif);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
static int
@@ -1321,11 +952,11 @@ mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_scan_ies *ies)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt76_connac_mcu_sched_scan_req(mphy, vif, req);
if (err < 0)
@@ -1333,7 +964,7 @@ mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -1341,13 +972,13 @@ out:
static int
mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -1355,17 +986,17 @@ mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
static int
mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
int max_nss = hweight8(hw->wiphy->available_antennas_tx);
if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss)
return -EINVAL;
if ((BIT(hweight8(tx_ant)) - 1) != tx_ant)
- tx_ant = BIT(ffs(tx_ant) - 1) - 1;
+ return -EINVAL;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
phy->mt76->antenna_mask = tx_ant;
phy->mt76->chainmask = tx_ant;
@@ -1373,48 +1004,17 @@ mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mt76_set_stream_caps(phy->mt76, true);
mt7921_set_stream_he_caps(phy);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
-static void mt7921_sta_statistics(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct station_info *sinfo)
-{
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct rate_info *txrate = &msta->wcid.rate;
-
- if (!txrate->legacy && !txrate->flags)
- return;
-
- if (txrate->legacy) {
- sinfo->txrate.legacy = txrate->legacy;
- } else {
- sinfo->txrate.mcs = txrate->mcs;
- sinfo->txrate.nss = txrate->nss;
- sinfo->txrate.bw = txrate->bw;
- sinfo->txrate.he_gi = txrate->he_gi;
- sinfo->txrate.he_dcm = txrate->he_dcm;
- sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
- }
- sinfo->txrate.flags = txrate->flags;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
-
- sinfo->ack_signal = (s8)msta->ack_signal;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
-
- sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal);
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
-}
-
#ifdef CONFIG_PM
static int mt7921_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
cancel_delayed_work_sync(&phy->scan_work);
cancel_delayed_work_sync(&phy->mt76->mac_work);
@@ -1422,7 +1022,7 @@ static int mt7921_suspend(struct ieee80211_hw *hw,
cancel_delayed_work_sync(&dev->pm.ps_work);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
@@ -1430,17 +1030,17 @@ static int mt7921_suspend(struct ieee80211_hw *hw,
mt7921_mcu_set_suspend_iter,
&dev->mphy);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
static int mt7921_resume(struct ieee80211_hw *hw)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
@@ -1449,51 +1049,34 @@ static int mt7921_resume(struct ieee80211_hw *hw)
&dev->mphy);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
- MT7921_WATCHDOG_TIME);
+ MT792x_WATCHDOG_TIME);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return 0;
}
-static void mt7921_set_wakeup(struct ieee80211_hw *hw, bool enabled)
-{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt76_dev *mdev = &dev->mt76;
-
- device_set_wakeup_enable(mdev->dev, enabled);
-}
-
static void mt7921_set_rekey_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_gtk_rekey_data *data)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt76_connac_mcu_update_gtk_rekey(hw, vif, data);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
#endif /* CONFIG_PM */
-static void mt7921_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- u32 queues, bool drop)
-{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
-
- wait_event_timeout(dev->mt76.tx_wait, !mt76_has_tx_pending(&dev->mphy),
- HZ / 2);
-}
-
static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
bool enabled)
{
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
if (enabled)
set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
@@ -1503,7 +1086,7 @@ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw,
mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid,
MCU_UNI_CMD(STA_REC_UPDATE));
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -1511,8 +1094,8 @@ static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct inet6_dev *idev)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mvif->phy->dev;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mvif->phy->dev;
struct inet6_ifaddr *ifa;
struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
struct sk_buff *skb;
@@ -1570,28 +1153,25 @@ int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar)
{
struct mt76_phy *mphy = hw->priv;
- int err;
if (sar) {
- err = mt76_init_sar_power(hw, sar);
+ int err = mt76_init_sar_power(hw, sar);
+
if (err)
return err;
}
+ mt792x_init_acpi_sar_power(mt792x_hw_phy(hw), !sar);
- mt7921_init_acpi_sar_power(mt7921_hw_phy(hw), !sar);
-
- err = mt76_connac_mcu_set_rate_txpower(mphy);
-
- return err;
+ return mt76_connac_mcu_set_rate_txpower(mphy);
}
static int mt7921_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt7921_mcu_set_clc(dev, dev->mt76.alpha2,
dev->country_ie_env);
if (err < 0)
@@ -1599,7 +1179,7 @@ static int mt7921_set_sar_specs(struct ieee80211_hw *hw,
err = mt7921_set_tx_sar_pwr(hw, sar);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -1609,23 +1189,23 @@ mt7921_channel_switch_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, true);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
static int
mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid,
true, mvif->ctx);
@@ -1639,7 +1219,7 @@ mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
err = mt7921_mcu_sta_update(dev, NULL, vif, true,
MT76_STA_INFO_STATE_NONE);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
return err;
}
@@ -1648,12 +1228,12 @@ static void
mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err;
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
err = mt7921_mcu_set_bss_pm(dev, vif, false);
if (err)
@@ -1663,7 +1243,7 @@ mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mvif->ctx);
out:
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
static int
@@ -1682,7 +1262,7 @@ mt7921_remove_chanctx(struct ieee80211_hw *hw,
static void mt7921_ctx_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_chanctx_conf *ctx = priv;
if (ctx != mvif->ctx)
@@ -1699,77 +1279,47 @@ mt7921_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed)
{
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
- mt7921_mutex_acquire(phy->dev);
+ mt792x_mutex_acquire(phy->dev);
ieee80211_iterate_active_interfaces(phy->mt76->hw,
IEEE80211_IFACE_ITER_ACTIVE,
mt7921_ctx_iter, ctx);
- mt7921_mutex_release(phy->dev);
-}
-
-static int
-mt7921_assign_vif_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_chanctx_conf *ctx)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
-
- mutex_lock(&dev->mt76.mutex);
- mvif->ctx = ctx;
- mutex_unlock(&dev->mt76.mutex);
-
- return 0;
-}
-
-static void
-mt7921_unassign_vif_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_chanctx_conf *ctx)
-{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
-
- mutex_lock(&dev->mt76.mutex);
- mvif->ctx = NULL;
- mutex_unlock(&dev->mt76.mutex);
+ mt792x_mutex_release(phy->dev);
}
static void mt7921_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
u16 duration = info->duration ? info->duration :
jiffies_to_msecs(HZ);
- mt7921_mutex_acquire(dev);
+ mt792x_mutex_acquire(dev);
mt7921_set_roc(mvif->phy, mvif, mvif->ctx->def.chan, duration,
MT7921_ROC_REQ_JOIN);
- mt7921_mutex_release(dev);
+ mt792x_mutex_release(dev);
}
static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
mt7921_abort_roc(mvif->phy, mvif);
}
const struct ieee80211_ops mt7921_ops = {
- .tx = mt7921_tx,
+ .tx = mt792x_tx,
.start = mt7921_start,
.stop = mt7921_stop,
.add_interface = mt7921_add_interface,
- .remove_interface = mt7921_remove_interface,
+ .remove_interface = mt792x_remove_interface,
.config = mt7921_config,
- .conf_tx = mt7921_conf_tx,
+ .conf_tx = mt792x_conf_tx,
.configure_filter = mt7921_configure_filter,
.bss_info_changed = mt7921_bss_info_changed,
.start_ap = mt7921_start_ap,
@@ -1787,19 +1337,19 @@ const struct ieee80211_ops mt7921_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.channel_switch_beacon = mt7921_channel_switch_beacon,
.get_txpower = mt76_get_txpower,
- .get_stats = mt7921_get_stats,
- .get_et_sset_count = mt7921_get_et_sset_count,
- .get_et_strings = mt7921_get_et_strings,
- .get_et_stats = mt7921_get_et_stats,
- .get_tsf = mt7921_get_tsf,
- .set_tsf = mt7921_set_tsf,
+ .get_stats = mt792x_get_stats,
+ .get_et_sset_count = mt792x_get_et_sset_count,
+ .get_et_strings = mt792x_get_et_strings,
+ .get_et_stats = mt792x_get_et_stats,
+ .get_tsf = mt792x_get_tsf,
+ .set_tsf = mt792x_set_tsf,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
.set_antenna = mt7921_set_antenna,
- .set_coverage_class = mt7921_set_coverage_class,
+ .set_coverage_class = mt792x_set_coverage_class,
.hw_scan = mt7921_hw_scan,
.cancel_hw_scan = mt7921_cancel_hw_scan,
- .sta_statistics = mt7921_sta_statistics,
+ .sta_statistics = mt792x_sta_statistics,
.sched_scan_start = mt7921_start_sched_scan,
.sched_scan_stop = mt7921_stop_sched_scan,
CFG80211_TESTMODE_CMD(mt7921_testmode_cmd)
@@ -1807,18 +1357,18 @@ const struct ieee80211_ops mt7921_ops = {
#ifdef CONFIG_PM
.suspend = mt7921_suspend,
.resume = mt7921_resume,
- .set_wakeup = mt7921_set_wakeup,
+ .set_wakeup = mt792x_set_wakeup,
.set_rekey_data = mt7921_set_rekey_data,
#endif /* CONFIG_PM */
- .flush = mt7921_flush,
+ .flush = mt792x_flush,
.set_sar_specs = mt7921_set_sar_specs,
.remain_on_channel = mt7921_remain_on_channel,
.cancel_remain_on_channel = mt7921_cancel_remain_on_channel,
.add_chanctx = mt7921_add_chanctx,
.remove_chanctx = mt7921_remove_chanctx,
.change_chanctx = mt7921_change_chanctx,
- .assign_vif_chanctx = mt7921_assign_vif_chanctx,
- .unassign_vif_chanctx = mt7921_unassign_vif_chanctx,
+ .assign_vif_chanctx = mt792x_assign_vif_chanctx,
+ .unassign_vif_chanctx = mt792x_unassign_vif_chanctx,
.mgd_prepare_tx = mt7921_mgd_prepare_tx,
.mgd_complete_tx = mt7921_mgd_complete_tx,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index f55caa00ac69..90c93970acab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -4,9 +4,9 @@
#include <linux/fs.h>
#include <linux/firmware.h>
#include "mt7921.h"
-#include "mt7921_trace.h"
#include "mcu.h"
#include "../mt76_connac2_mac.h"
+#include "../mt792x_trace.h"
#define MT_STA_BFER BIT(0)
#define MT_STA_BFEE BIT(1)
@@ -25,7 +25,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
if (!skb) {
dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
cmd, seq);
- mt7921_reset(mdev);
+ mt792x_reset(mdev);
return -ETIMEDOUT;
}
@@ -69,7 +69,7 @@ int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
}
EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);
-static int mt7921_mcu_read_eeprom(struct mt7921_dev *dev, u32 offset, u8 *val)
+static int mt7921_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
{
struct mt7921_mcu_eeprom_info *res, req = {
.addr = cpu_to_le32(round_down(offset,
@@ -96,7 +96,7 @@ static int
mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev,
struct ieee80211_vif *vif, bool suspend)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct {
struct {
u8 bss_idx;
@@ -134,7 +134,7 @@ void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
#endif /* CONFIG_PM */
static void
-mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt7921_roc_grant_tlv *grant;
struct mt76_connac2_mcu_rxd *rxd;
@@ -157,17 +157,17 @@ mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv;
+ struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
spin_lock_bh(&dev->mt76.lock);
__skb_queue_tail(&phy->scan_event_list, skb);
spin_unlock_bh(&dev->mt76.lock);
ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
- MT7921_HW_SCAN_TIMEOUT);
+ MT792x_HW_SCAN_TIMEOUT);
}
static void
@@ -188,7 +188,7 @@ mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
}
static void
-mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_connac_beacon_loss_event *event;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -202,7 +202,7 @@ mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt7921_debug_msg {
__le16 id;
@@ -229,7 +229,7 @@ mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_low_power_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_lp_event {
u8 state;
@@ -243,7 +243,7 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_tx_done_event *event;
@@ -254,7 +254,7 @@ mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
+mt7921_mcu_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_connac2_mcu_rxd *rxd;
@@ -288,7 +288,7 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
static void
-mt7921_mcu_uni_rx_unsolicited_event(struct mt7921_dev *dev,
+mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
struct sk_buff *skb)
{
struct mt76_connac2_mcu_rxd *rxd;
@@ -305,7 +305,7 @@ mt7921_mcu_uni_rx_unsolicited_event(struct mt7921_dev *dev,
dev_kfree_skb(skb);
}
-void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
+void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_connac2_mcu_rxd *rxd;
@@ -339,11 +339,11 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
}
/** starec & wtbl **/
-int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
+int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable)
{
- struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv;
+ struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
if (enable && !params->amsdu)
msta->wcid.amsdu = false;
@@ -353,48 +353,24 @@ int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
enable, true);
}
-int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
+int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable)
{
- struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv;
+ struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params,
MCU_UNI_CMD(STA_REC_UPDATE),
enable, false);
}
-static char *mt7921_patch_name(struct mt7921_dev *dev)
-{
- char *ret;
-
- if (is_mt7922(&dev->mt76))
- ret = MT7922_ROM_PATCH;
- else
- ret = MT7921_ROM_PATCH;
-
- return ret;
-}
-
-static char *mt7921_ram_name(struct mt7921_dev *dev)
-{
- char *ret;
-
- if (is_mt7922(&dev->mt76))
- ret = MT7922_FIRMWARE_WM;
- else
- ret = MT7921_FIRMWARE_WM;
-
- return ret;
-}
-
-static int mt7921_load_clc(struct mt7921_dev *dev, const char *fw_name)
+static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
{
const struct mt76_connac2_fw_trailer *hdr;
const struct mt76_connac2_fw_region *region;
const struct mt7921_clc *clc;
struct mt76_dev *mdev = &dev->mt76;
- struct mt7921_phy *phy = &dev->phy;
+ struct mt792x_phy *phy = &dev->phy;
const struct firmware *fw;
int ret, i, len, offset = 0;
u8 *clc_base = NULL, hw_encap = 0;
@@ -472,42 +448,7 @@ out:
return ret;
}
-static int mt7921_load_firmware(struct mt7921_dev *dev)
-{
- int ret;
-
- ret = mt76_connac2_load_patch(&dev->mt76, mt7921_patch_name(dev));
- if (ret)
- return ret;
-
- if (mt76_is_sdio(&dev->mt76)) {
- /* activate again */
- ret = __mt7921_mcu_fw_pmctrl(dev);
- if (!ret)
- ret = __mt7921_mcu_drv_pmctrl(dev);
- }
-
- ret = mt76_connac2_load_ram(&dev->mt76, mt7921_ram_name(dev), NULL);
- if (ret)
- return ret;
-
- if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
- MT_TOP_MISC2_FW_N9_RDY, 1500)) {
- dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
-
- return -EIO;
- }
-
-#ifdef CONFIG_PM
- dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
-#endif /* CONFIG_PM */
-
- dev_dbg(dev->mt76.dev, "Firmware init done\n");
-
- return 0;
-}
-
-int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl)
+int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl)
{
struct {
u8 ctrl_val;
@@ -520,11 +461,11 @@ int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl)
&data, sizeof(data), false);
}
-int mt7921_run_firmware(struct mt7921_dev *dev)
+int mt7921_run_firmware(struct mt792x_dev *dev)
{
int err;
- err = mt7921_load_firmware(dev);
+ err = mt792x_load_firmware(dev);
if (err)
return err;
@@ -533,7 +474,7 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
return err;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
- err = mt7921_load_clc(dev, mt7921_ram_name(dev));
+ err = mt7921_load_clc(dev, mt792x_ram_name(dev));
if (err)
return err;
@@ -541,9 +482,9 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
}
EXPORT_SYMBOL_GPL(mt7921_run_firmware);
-int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
+int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct edca {
__le16 cw_min;
__le16 cw_max;
@@ -635,12 +576,12 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
&req_mu, sizeof(req_mu), false);
}
-int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
+int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
struct ieee80211_channel *chan, int duration,
enum mt7921_roc_req type, u8 token_id)
{
int center_ch = ieee80211_frequency_to_channel(chan->center_freq);
- struct mt7921_dev *dev = phy->dev;
+ struct mt792x_dev *dev = phy->dev;
struct {
struct {
u8 rsv[4];
@@ -702,10 +643,10 @@ int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
&req, sizeof(req), false);
}
-int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
+int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
u8 token_id)
{
- struct mt7921_dev *dev = phy->dev;
+ struct mt792x_dev *dev = phy->dev;
struct {
struct {
u8 rsv[4];
@@ -732,9 +673,9 @@ int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
&req, sizeof(req), false);
}
-int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd)
+int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd)
{
- struct mt7921_dev *dev = phy->dev;
+ struct mt792x_dev *dev = phy->dev;
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
int freq1 = chandef->center_freq1;
struct {
@@ -791,7 +732,7 @@ int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd)
return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
-int mt7921_mcu_set_eeprom(struct mt7921_dev *dev)
+int mt7921_mcu_set_eeprom(struct mt792x_dev *dev)
{
struct req_hdr {
u8 buffer_mode;
@@ -807,9 +748,9 @@ int mt7921_mcu_set_eeprom(struct mt7921_dev *dev)
}
EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);
-int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
+int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct {
struct {
u8 bss_idx;
@@ -845,10 +786,10 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
}
static int
-mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct {
struct {
u8 bss_idx;
@@ -881,10 +822,10 @@ mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
}
int
-mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct {
u8 bss_idx;
u8 dtim_period;
@@ -918,11 +859,11 @@ mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
&req, sizeof(req), false);
}
-int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta,
struct ieee80211_vif *vif, bool enable,
enum mt76_sta_info_state state)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
int rssi = -ewma_rssi_read(&mvif->rssi);
struct mt76_sta_cmd_info info = {
.sta = sta,
@@ -933,60 +874,16 @@ int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
.offload_fw = true,
.rcpi = to_rcpi(rssi),
};
- struct mt7921_sta *msta;
+ struct mt792x_sta *msta;
- msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL;
+ msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL;
info.wcid = msta ? &msta->wcid : &mvif->sta.wcid;
info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true;
return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
}
-int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_pm *pm = &dev->pm;
- int err = 0;
-
- mutex_lock(&pm->mutex);
-
- if (!test_bit(MT76_STATE_PM, &mphy->state))
- goto out;
-
- err = __mt7921_mcu_drv_pmctrl(dev);
-out:
- mutex_unlock(&pm->mutex);
-
- if (err)
- mt7921_reset(&dev->mt76);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl);
-
-int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_pm *pm = &dev->pm;
- int err = 0;
-
- mutex_lock(&pm->mutex);
-
- if (mt76_connac_skip_fw_pmctrl(mphy, pm))
- goto out;
-
- err = __mt7921_mcu_fw_pmctrl(dev);
-out:
- mutex_unlock(&pm->mutex);
-
- if (err)
- mt7921_reset(&dev->mt76);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl);
-
-int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
+int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
bool enable)
{
@@ -1021,7 +918,7 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
return 0;
}
-int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
+int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr)
{
struct mt7921_txpwr_event *event;
struct mt7921_txpwr_req req = {
@@ -1044,7 +941,7 @@ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
return 0;
}
-int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable)
{
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
@@ -1074,7 +971,7 @@ int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
true);
}
-int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
+int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
struct ieee80211_chanctx_conf *ctx)
{
struct cfg80211_chan_def *chandef = &ctx->def;
@@ -1143,12 +1040,12 @@ int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
}
int
-mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev,
+mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
bool enable)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
struct ieee80211_mutable_offsets offs;
struct {
@@ -1221,7 +1118,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev,
}
static
-int __mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
+int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap env_cap,
struct mt7921_clc *clc,
u8 idx)
@@ -1241,7 +1138,7 @@ int __mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
} __packed req = {
.idx = idx,
.env = env_cap,
- .acpi_conf = mt7921_acpi_get_flags(&dev->phy),
+ .acpi_conf = mt792x_acpi_get_flags(&dev->phy),
};
int ret, valid_cnt = 0;
u8 i, *pos;
@@ -1283,10 +1180,10 @@ int __mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
return 0;
}
-int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
+int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap env_cap)
{
- struct mt7921_phy *phy = (struct mt7921_phy *)&dev->phy;
+ struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy;
int i, ret;
/* submit all clc config */
@@ -1305,7 +1202,24 @@ int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
return 0;
}
-int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
+int mt7921_mcu_get_temperature(struct mt792x_phy *phy)
+{
+ struct mt792x_dev *dev = phy->dev;
+ struct {
+ u8 ctrl_id;
+ u8 action;
+ u8 band_idx;
+ u8 rsv[5];
+ } req = {
+ .ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
+ .band_idx = phy->mt76->band_idx,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
+ sizeof(req), true);
+}
+
+int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
u8 bit_op, u32 bit_map)
{
struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 149acb1662d5..87dd06855f68 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -4,22 +4,8 @@
#ifndef __MT7921_H
#define __MT7921_H
-#include <linux/interrupt.h>
-#include <linux/ktime.h>
-#include "../mt76_connac_mcu.h"
+#include "../mt792x.h"
#include "regs.h"
-#include "acpi_sar.h"
-
-#define MT7921_MAX_INTERFACES 4
-#define MT7921_WTBL_SIZE 20
-#define MT7921_WTBL_RESERVED (MT7921_WTBL_SIZE - 1)
-#define MT7921_WTBL_STA (MT7921_WTBL_RESERVED - \
- MT7921_MAX_INTERFACES)
-
-#define MT7921_PM_TIMEOUT (HZ / 12)
-#define MT7921_HW_SCAN_TIMEOUT (HZ / 10)
-#define MT7921_WATCHDOG_TIME (HZ / 4)
-#define MT7921_RESET_TIMEOUT (30 * HZ)
#define MT7921_TX_RING_SIZE 2048
#define MT7921_TX_MCU_RING_SIZE 256
@@ -28,27 +14,11 @@
#define MT7921_RX_RING_SIZE 1536
#define MT7921_RX_MCU_RING_SIZE 512
-#define MT7921_DRV_OWN_RETRY_COUNT 10
-#define MT7921_MCU_INIT_RETRY_COUNT 10
-#define MT7921_WFSYS_INIT_RETRY_COUNT 2
-
-#define MT7921_FW_TAG_FEATURE 4
-#define MT7921_FW_CAP_CNM BIT(7)
-
-#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
-#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
-
-#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
-#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
-
#define MT7921_EEPROM_SIZE 3584
#define MT7921_TOKEN_SIZE 8192
#define MT7921_EEPROM_BLOCK_SIZE 16
-#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
-#define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
-
#define MT7921_SKU_RATE_NUM 161
#define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM
#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1)
@@ -128,9 +98,6 @@ struct mt7921_sdio_intr {
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
#define to_rcpi(rssi) (2 * (rssi) + 220)
-struct mt7921_vif;
-struct mt7921_sta;
-
enum mt7921_txq_id {
MT7921_TXQ_BAND0,
MT7921_TXQ_BAND1,
@@ -144,70 +111,6 @@ enum mt7921_rxq_id {
MT7921_RXQ_MCU_WM = 0,
};
-DECLARE_EWMA(avg_signal, 10, 8)
-
-struct mt7921_sta {
- struct mt76_wcid wcid; /* must be first */
-
- struct mt7921_vif *vif;
-
- struct list_head poll_list;
- u32 airtime_ac[8];
-
- int ack_signal;
- struct ewma_avg_signal avg_ack_signal;
-
- unsigned long last_txs;
- unsigned long ampdu_state;
-
- struct mt76_connac_sta_key_conf bip;
-};
-
-DECLARE_EWMA(rssi, 10, 8);
-
-struct mt7921_vif {
- struct mt76_vif mt76; /* must be first */
-
- struct mt7921_sta sta;
- struct mt7921_sta *wep_sta;
-
- struct mt7921_phy *phy;
-
- struct ewma_rssi rssi;
-
- struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
- struct ieee80211_chanctx_conf *ctx;
-};
-
-struct mib_stats {
- u32 ack_fail_cnt;
- u32 fcs_err_cnt;
- u32 rts_cnt;
- u32 rts_retries_cnt;
- u32 ba_miss_cnt;
-
- u32 tx_bf_ibf_ppdu_cnt;
- u32 tx_bf_ebf_ppdu_cnt;
- u32 tx_bf_rx_fb_all_cnt;
- u32 tx_bf_rx_fb_he_cnt;
- u32 tx_bf_rx_fb_vht_cnt;
- u32 tx_bf_rx_fb_ht_cnt;
-
- u32 tx_ampdu_cnt;
- u32 tx_mpdu_attempts_cnt;
- u32 tx_mpdu_success_cnt;
- u32 tx_pkt_ebf_cnt;
- u32 tx_pkt_ibf_cnt;
-
- u32 rx_mpdu_cnt;
- u32 rx_ampdu_cnt;
- u32 rx_ampdu_bytes_cnt;
- u32 rx_ba_cnt;
-
- u32 tx_amsdu[8];
- u32 tx_amsdu_cnt;
-};
-
enum {
MT7921_CLC_POWER,
MT7921_CLC_CHAN,
@@ -231,41 +134,6 @@ struct mt7921_clc {
u8 data[];
} __packed;
-struct mt7921_phy {
- struct mt76_phy *mt76;
- struct mt7921_dev *dev;
-
- struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
-
- u64 omac_mask;
-
- u16 noise;
-
- s16 coverage_class;
- u8 slottime;
-
- u32 rx_ampdu_ts;
- u32 ampdu_ref;
-
- struct mib_stats mib;
-
- u8 sta_work_count;
-
- struct sk_buff_head scan_event_list;
- struct delayed_work scan_work;
-#ifdef CONFIG_ACPI
- struct mt7921_acpi_sar *acpisar;
-#endif
-
- struct mt7921_clc *clc[MT7921_CLC_MAX_NUM];
-
- struct work_struct roc_work;
- struct timer_list roc_timer;
- wait_queue_head_t roc_wait;
- u8 roc_token_id;
- bool roc_grant;
-};
-
enum mt7921_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
@@ -277,52 +145,6 @@ enum mt7921_eeprom_field {
#define MT_EE_HW_TYPE_ENCAP BIT(0)
-#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
-#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
-#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
-#define __mt7921_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev))
-#define __mt7921_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev))
-struct mt7921_hif_ops {
- int (*init_reset)(struct mt7921_dev *dev);
- int (*reset)(struct mt7921_dev *dev);
- int (*mcu_init)(struct mt7921_dev *dev);
- int (*drv_own)(struct mt7921_dev *dev);
- int (*fw_own)(struct mt7921_dev *dev);
-};
-
-struct mt7921_dev {
- union { /* must be first */
- struct mt76_dev mt76;
- struct mt76_phy mphy;
- };
-
- const struct mt76_bus_ops *bus_ops;
- struct mt7921_phy phy;
-
- struct work_struct reset_work;
- bool hw_full_reset:1;
- bool hw_init_done:1;
- bool fw_assert:1;
-
- struct list_head sta_poll_list;
- spinlock_t sta_poll_lock;
-
- struct work_struct init_work;
-
- u8 fw_debug;
- u8 fw_features;
-
- struct mt76_connac_pm pm;
- struct mt76_connac_coredump coredump;
- const struct mt7921_hif_ops *hif_ops;
-
- struct work_struct ipv6_ns_work;
- /* IPv6 addresses for WoWLAN */
- struct sk_buff_head ipv6_ns_list;
-
- enum environment_cap country_ie_env;
-};
-
enum {
TXPWR_USER,
TXPWR_EEPROM,
@@ -353,56 +175,31 @@ struct mt7921_txpwr {
} data[TXPWR_MAX_NUM];
};
-static inline struct mt7921_phy *
-mt7921_hw_phy(struct ieee80211_hw *hw)
-{
- struct mt76_phy *phy = hw->priv;
-
- return phy->priv;
-}
-
-static inline struct mt7921_dev *
-mt7921_hw_dev(struct ieee80211_hw *hw)
-{
- struct mt76_phy *phy = hw->priv;
-
- return container_of(phy->dev, struct mt7921_dev, mt76);
-}
-
-#define mt7921_mutex_acquire(dev) \
- mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm)
-#define mt7921_mutex_release(dev) \
- mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm)
-
extern const struct ieee80211_ops mt7921_ops;
-u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr);
-
-int __mt7921_start(struct mt7921_phy *phy);
-int mt7921_register_device(struct mt7921_dev *dev);
-void mt7921_unregister_device(struct mt7921_dev *dev);
-int mt7921_dma_init(struct mt7921_dev *dev);
-int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force);
-int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev);
-void mt7921_dma_cleanup(struct mt7921_dev *dev);
-int mt7921_run_firmware(struct mt7921_dev *dev);
-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+u32 mt7921_reg_map(struct mt792x_dev *dev, u32 addr);
+
+int __mt7921_start(struct mt792x_phy *phy);
+int mt7921_register_device(struct mt792x_dev *dev);
+void mt7921_unregister_device(struct mt792x_dev *dev);
+int mt7921_run_firmware(struct mt792x_dev *dev);
+int mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable);
-int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta,
struct ieee80211_vif *vif, bool enable,
enum mt76_sta_info_state state);
-int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd);
-int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif);
-int mt7921_mcu_set_eeprom(struct mt7921_dev *dev);
-int mt7921_mcu_get_rx_rate(struct mt7921_phy *phy, struct ieee80211_vif *vif,
+int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd);
+int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif);
+int mt7921_mcu_set_eeprom(struct mt792x_dev *dev);
+int mt7921_mcu_get_rx_rate(struct mt792x_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
-int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl);
-void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb);
-int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
+int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl);
+void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb);
+int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
u8 bit_op, u32 bit_map);
static inline u32
-mt7921_reg_map_l1(struct mt7921_dev *dev, u32 addr)
+mt7921_reg_map_l1(struct mt792x_dev *dev, u32 addr)
{
u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
@@ -415,19 +212,19 @@ mt7921_reg_map_l1(struct mt7921_dev *dev, u32 addr)
}
static inline u32
-mt7921_l1_rr(struct mt7921_dev *dev, u32 addr)
+mt7921_l1_rr(struct mt792x_dev *dev, u32 addr)
{
return mt76_rr(dev, mt7921_reg_map_l1(dev, addr));
}
static inline void
-mt7921_l1_wr(struct mt7921_dev *dev, u32 addr, u32 val)
+mt7921_l1_wr(struct mt792x_dev *dev, u32 addr, u32 val)
{
mt76_wr(dev, mt7921_reg_map_l1(dev, addr), val);
}
static inline u32
-mt7921_l1_rmw(struct mt7921_dev *dev, u32 addr, u32 mask, u32 val)
+mt7921_l1_rmw(struct mt792x_dev *dev, u32 addr, u32 mask, u32 val)
{
val |= mt7921_l1_rr(dev, addr) & ~mask;
mt7921_l1_wr(dev, addr, val);
@@ -438,13 +235,8 @@ mt7921_l1_rmw(struct mt7921_dev *dev, u32 addr, u32 mask, u32 val)
#define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val)
#define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0)
-static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev)
-{
- return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
-}
-
static inline void
-mt7921_skb_add_usb_sdio_hdr(struct mt7921_dev *dev, struct sk_buff *skb,
+mt7921_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb,
int type)
{
u32 hdr, len;
@@ -457,89 +249,69 @@ mt7921_skb_add_usb_sdio_hdr(struct mt7921_dev *dev, struct sk_buff *skb,
}
void mt7921_stop(struct ieee80211_hw *hw);
-int mt7921_mac_init(struct mt7921_dev *dev);
-bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
-void mt7921_mac_reset_counters(struct mt7921_phy *phy);
-void mt7921_mac_set_timing(struct mt7921_phy *phy);
+int mt7921_mac_init(struct mt792x_dev *dev);
+bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask);
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-void mt7921_mac_work(struct work_struct *work);
void mt7921_mac_reset_work(struct work_struct *work);
-void mt7921_mac_update_mib_stats(struct mt7921_phy *phy);
-void mt7921_reset(struct mt76_dev *mdev);
int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
-void mt7921_tx_worker(struct mt76_worker *w);
-void mt7921_tx_token_put(struct mt7921_dev *dev);
bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len);
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
void mt7921_stats_work(struct work_struct *work);
-void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
-void mt7921_update_channel(struct mt76_phy *mphy);
-int mt7921_init_debugfs(struct mt7921_dev *dev);
+void mt7921_set_stream_he_caps(struct mt792x_phy *phy);
+int mt7921_init_debugfs(struct mt792x_dev *dev);
-int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
+int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
bool enable);
-int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
+int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable);
-int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
+int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable);
void mt7921_scan_work(struct work_struct *work);
void mt7921_roc_work(struct work_struct *work);
-void mt7921_roc_timer(struct timer_list *timer);
-int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
-int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
-int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
-void mt7921_pm_wake_work(struct work_struct *work);
-void mt7921_pm_power_save_work(struct work_struct *work);
+int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif);
void mt7921_coredump_work(struct work_struct *work);
-int mt7921_wfsys_reset(struct mt7921_dev *dev);
-int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr);
+int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr);
int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len);
int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
struct netlink_callback *cb, void *data, int len);
-void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, bool clear_status,
- struct list_head *free_list);
-void mt7921_mac_sta_poll(struct mt7921_dev *dev);
int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq);
-int mt7921e_driver_own(struct mt7921_dev *dev);
-int mt7921e_mac_reset(struct mt7921_dev *dev);
-int mt7921e_mcu_init(struct mt7921_dev *dev);
-int mt7921s_wfsys_reset(struct mt7921_dev *dev);
-int mt7921s_mac_reset(struct mt7921_dev *dev);
-int mt7921s_init_reset(struct mt7921_dev *dev);
-int __mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
-int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
-int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);
-
-int mt7921s_mcu_init(struct mt7921_dev *dev);
-int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev);
-int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev);
-void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data);
-void mt7921_set_runtime_pm(struct mt7921_dev *dev);
+int mt7921e_driver_own(struct mt792x_dev *dev);
+int mt7921e_mac_reset(struct mt792x_dev *dev);
+int mt7921e_mcu_init(struct mt792x_dev *dev);
+int mt7921s_wfsys_reset(struct mt792x_dev *dev);
+int mt7921s_mac_reset(struct mt792x_dev *dev);
+int mt7921s_init_reset(struct mt792x_dev *dev);
+
+int mt7921s_mcu_init(struct mt792x_dev *dev);
+int mt7921s_mcu_drv_pmctrl(struct mt792x_dev *dev);
+int mt7921s_mcu_fw_pmctrl(struct mt792x_dev *dev);
+void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data);
+void mt7921_set_runtime_pm(struct mt792x_dev *dev);
void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
void mt7921_set_ipv6_ns_work(struct work_struct *work);
-int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable);
-int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
+int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
struct ieee80211_chanctx_conf *ctx);
+int mt7921_mcu_get_temperature(struct mt792x_phy *phy);
int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
@@ -550,51 +322,18 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
bool mt7921_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update);
/* usb */
-#define MT_USB_TYPE_VENDOR (USB_TYPE_VENDOR | 0x1f)
-#define MT_USB_TYPE_UHW_VENDOR (USB_TYPE_VENDOR | 0x1e)
-
-int mt7921u_mcu_power_on(struct mt7921_dev *dev);
-int mt7921u_wfsys_reset(struct mt7921_dev *dev);
-int mt7921u_dma_init(struct mt7921_dev *dev, bool resume);
-int mt7921u_init_reset(struct mt7921_dev *dev);
-int mt7921u_mac_reset(struct mt7921_dev *dev);
-int mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev,
+int mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
bool enable);
-#ifdef CONFIG_ACPI
-int mt7921_init_acpi_sar(struct mt7921_dev *dev);
-int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default);
-u8 mt7921_acpi_get_flags(struct mt7921_phy *phy);
-#else
-static inline int
-mt7921_init_acpi_sar(struct mt7921_dev *dev)
-{
- return 0;
-}
-
-static inline int
-mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default)
-{
- return 0;
-}
-
-static inline u8
-mt7921_acpi_get_flags(struct mt7921_phy *phy)
-{
- return 0;
-}
-#endif
int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar);
-int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
+int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
enum environment_cap env_cap);
-int mt7921_mcu_set_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
+int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
struct ieee80211_channel *chan, int duration,
enum mt7921_roc_req type, u8 token_id);
-int mt7921_mcu_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif,
+int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
u8 token_id);
-struct ieee80211_ops *mt7921_get_mac80211_ops(struct device *dev,
- void *drv_data, u8 *fw_features);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 95610a117d2f..3dda84a93717 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -9,8 +9,8 @@
#include "mt7921.h"
#include "../mt76_connac2_mac.h"
+#include "../dma.h"
#include "mcu.h"
-#include "../trace.h"
static const struct pci_device_id mt7921_pci_device_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961),
@@ -28,81 +28,12 @@ static bool mt7921_disable_aspm;
module_param_named(disable_aspm, mt7921_disable_aspm, bool, 0644);
MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support");
-static void
-mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
+static int mt7921e_init_reset(struct mt792x_dev *dev)
{
- if (q == MT_RXQ_MAIN)
- mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_DATA);
- else if (q == MT_RXQ_MCU_WA)
- mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_WM2);
- else
- mt76_connac_irq_enable(mdev, MT_INT_RX_DONE_WM);
+ return mt792x_wpdma_reset(dev, true);
}
-static irqreturn_t mt7921_irq_handler(int irq, void *dev_instance)
-{
- struct mt7921_dev *dev = dev_instance;
-
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
-
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
- return IRQ_NONE;
-
- tasklet_schedule(&dev->mt76.irq_tasklet);
-
- return IRQ_HANDLED;
-}
-
-static void mt7921_irq_tasklet(unsigned long data)
-{
- struct mt7921_dev *dev = (struct mt7921_dev *)data;
- u32 intr, mask = 0;
-
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
-
- intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA);
- intr &= dev->mt76.mmio.irqmask;
- mt76_wr(dev, MT_WFDMA0_HOST_INT_STA, intr);
-
- trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
-
- mask |= intr & MT_INT_RX_DONE_ALL;
- if (intr & MT_INT_TX_DONE_MCU)
- mask |= MT_INT_TX_DONE_MCU;
-
- if (intr & MT_INT_MCU_CMD) {
- u32 intr_sw;
-
- intr_sw = mt76_rr(dev, MT_MCU_CMD);
- /* ack MCU2HOST_SW_INT_STA */
- mt76_wr(dev, MT_MCU_CMD, intr_sw);
- if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) {
- mask |= MT_INT_RX_DONE_DATA;
- intr |= MT_INT_RX_DONE_DATA;
- }
- }
-
- mt76_set_irq_mask(&dev->mt76, MT_WFDMA0_HOST_INT_ENA, mask, 0);
-
- if (intr & MT_INT_TX_DONE_ALL)
- napi_schedule(&dev->mt76.tx_napi);
-
- if (intr & MT_INT_RX_DONE_WM)
- napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]);
-
- if (intr & MT_INT_RX_DONE_WM2)
- napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]);
-
- if (intr & MT_INT_RX_DONE_DATA)
- napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
-}
-
-static int mt7921e_init_reset(struct mt7921_dev *dev)
-{
- return mt7921_wpdma_reset(dev, true);
-}
-
-static void mt7921e_unregister_device(struct mt7921_dev *dev)
+static void mt7921e_unregister_device(struct mt792x_dev *dev)
{
int i;
struct mt76_connac_pm *pm = &dev->pm;
@@ -115,16 +46,16 @@ static void mt7921e_unregister_device(struct mt7921_dev *dev)
cancel_work_sync(&pm->wake_work);
cancel_work_sync(&dev->reset_work);
- mt7921_tx_token_put(dev);
- __mt7921_mcu_drv_pmctrl(dev);
- mt7921_dma_cleanup(dev);
- mt7921_wfsys_reset(dev);
+ mt76_connac2_tx_token_put(&dev->mt76);
+ __mt792x_mcu_drv_pmctrl(dev);
+ mt792x_dma_cleanup(dev);
+ mt792x_wfsys_reset(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
tasklet_disable(&dev->mt76.irq_tasklet);
}
-static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
+static u32 __mt7921_reg_addr(struct mt792x_dev *dev, u32 addr)
{
static const struct mt76_connac_reg_map fixed_map[] = {
{ 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
@@ -203,7 +134,7 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
u32 addr = __mt7921_reg_addr(dev, offset);
return dev->bus_ops->rr(mdev, addr);
@@ -211,7 +142,7 @@ static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset)
static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
u32 addr = __mt7921_reg_addr(dev, offset);
dev->bus_ops->wr(mdev, addr, val);
@@ -219,12 +150,77 @@ static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val)
static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
u32 addr = __mt7921_reg_addr(dev, offset);
return dev->bus_ops->rmw(mdev, addr, mask, val);
}
+static int mt7921_dma_init(struct mt792x_dev *dev)
+{
+ int ret;
+
+ mt76_dma_attach(&dev->mt76);
+
+ ret = mt792x_dma_disable(dev, true);
+ if (ret)
+ return ret;
+
+ /* init tx queue */
+ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0,
+ MT7921_TX_RING_SIZE,
+ MT_TX_RING_BASE, 0);
+ if (ret)
+ return ret;
+
+ mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
+
+ /* command to WM */
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM,
+ MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
+ if (ret)
+ return ret;
+
+ /* firmware download */
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL,
+ MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
+ if (ret)
+ return ret;
+
+ /* event from WM before firmware download */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
+ MT7921_RXQ_MCU_WM,
+ MT7921_RX_MCU_RING_SIZE,
+ MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
+ if (ret)
+ return ret;
+
+ /* Change mcu queue after firmware download */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
+ MT7921_RXQ_MCU_WM,
+ MT7921_RX_MCU_RING_SIZE,
+ MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
+ if (ret)
+ return ret;
+
+ /* rx data */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
+ MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE,
+ MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
+ if (ret)
+ return ret;
+
+ ret = mt76_init_queues(dev, mt792x_poll_rx);
+ if (ret < 0)
+ return ret;
+
+ netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
+ mt792x_poll_tx);
+ napi_enable(&dev->mt76.tx_napi);
+
+ return mt792x_dma_enable(dev);
+}
+
static int mt7921_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -241,22 +237,34 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.tx_complete_skb = mt76_connac_tx_complete_skb,
.rx_check = mt7921_rx_check,
.rx_skb = mt7921_queue_rx_skb,
- .rx_poll_complete = mt7921_rx_poll_complete,
+ .rx_poll_complete = mt792x_rx_poll_complete,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
- .update_survey = mt7921_update_channel,
+ .update_survey = mt792x_update_channel,
};
- static const struct mt7921_hif_ops mt7921_pcie_ops = {
+ static const struct mt792x_hif_ops mt7921_pcie_ops = {
.init_reset = mt7921e_init_reset,
.reset = mt7921e_mac_reset,
.mcu_init = mt7921e_mcu_init,
- .drv_own = mt7921e_mcu_drv_pmctrl,
- .fw_own = mt7921e_mcu_fw_pmctrl,
+ .drv_own = mt792xe_mcu_drv_pmctrl,
+ .fw_own = mt792xe_mcu_fw_pmctrl,
+ };
+ static const struct mt792x_irq_map irq_map = {
+ .host_irq_enable = MT_WFDMA0_HOST_INT_ENA,
+ .tx = {
+ .all_complete_mask = MT_INT_TX_DONE_ALL,
+ .mcu_complete_mask = MT_INT_TX_DONE_MCU,
+ },
+ .rx = {
+ .data_complete_mask = MT_INT_RX_DONE_DATA,
+ .wm_complete_mask = MT_INT_RX_DONE_WM,
+ .wm2_complete_mask = MT_INT_RX_DONE_WM2,
+ },
};
struct ieee80211_ops *ops;
struct mt76_bus_ops *bus_ops;
- struct mt7921_dev *dev;
+ struct mt792x_dev *dev;
struct mt76_dev *mdev;
u8 features;
int ret;
@@ -288,8 +296,8 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (mt7921_disable_aspm)
mt76_pci_disable_aspm(pdev);
- ops = mt7921_get_mac80211_ops(&pdev->dev, (void *)id->driver_data,
- &features);
+ ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops,
+ (void *)id->driver_data, &features);
if (!ops) {
ret = -ENOMEM;
goto err_free_pci_vec;
@@ -303,11 +311,12 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mdev);
- dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &mt7921_pcie_ops;
+ dev->irq_map = &irq_map;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
- tasklet_init(&mdev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
+ tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
@@ -325,11 +334,11 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
bus_ops->rmw = mt7921_rmw;
dev->mt76.bus = bus_ops;
- ret = mt7921e_mcu_fw_pmctrl(dev);
+ ret = mt792xe_mcu_fw_pmctrl(dev);
if (ret)
goto err_free_dev;
- ret = __mt7921e_mcu_drv_pmctrl(dev);
+ ret = __mt792xe_mcu_drv_pmctrl(dev);
if (ret)
goto err_free_dev;
@@ -337,15 +346,15 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
(mt7921_l1_rr(dev, MT_HW_REV) & 0xff);
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
- ret = mt7921_wfsys_reset(dev);
+ ret = mt792x_wfsys_reset(dev);
if (ret)
goto err_free_dev;
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, irq_map.host_irq_enable, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
- ret = devm_request_irq(mdev->dev, pdev->irq, mt7921_irq_handler,
+ ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
goto err_free_dev;
@@ -373,7 +382,7 @@ err_free_pci_vec:
static void mt7921_pci_remove(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
mt7921e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
@@ -385,7 +394,7 @@ static int mt7921_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct mt76_dev *mdev = pci_get_drvdata(pdev);
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt76_connac_pm *pm = &dev->pm;
int i, err;
@@ -394,7 +403,7 @@ static int mt7921_pci_suspend(struct device *device)
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- err = mt7921_mcu_drv_pmctrl(dev);
+ err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
goto restore_suspend;
@@ -424,12 +433,12 @@ static int mt7921_pci_suspend(struct device *device)
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
/* disable interrupt */
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
synchronize_irq(pdev->irq);
tasklet_kill(&mdev->irq_tasklet);
- err = mt7921_mcu_fw_pmctrl(dev);
+ err = mt792x_mcu_fw_pmctrl(dev);
if (err)
goto restore_napi;
@@ -450,7 +459,7 @@ restore_suspend:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
@@ -459,21 +468,21 @@ static int mt7921_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct mt76_dev *mdev = pci_get_drvdata(pdev);
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt76_connac_pm *pm = &dev->pm;
int i, err;
- err = mt7921_mcu_drv_pmctrl(dev);
+ err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
goto failed;
- mt7921_wpdma_reinit_cond(dev);
+ mt792x_wpdma_reinit_cond(dev);
/* enable interrupt */
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
mt76_connac_irq_enable(&dev->mt76,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
+ dev->irq_map->tx.all_complete_mask |
+ MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD);
mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
/* put dma enabled */
@@ -500,7 +509,7 @@ failed:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
index 6053a2556c20..e7a995e7e70a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
@@ -10,7 +10,7 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct mt76_connac_hw_txp *txp;
@@ -32,7 +32,7 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return id;
if (sta) {
- struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
if (time_after(jiffies, msta->last_txs + HZ / 4)) {
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -53,29 +53,15 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return 0;
}
-void mt7921_tx_token_put(struct mt7921_dev *dev)
-{
- struct mt76_txwi_cache *txwi;
- int id;
-
- spin_lock_bh(&dev->mt76.token_lock);
- idr_for_each_entry(&dev->mt76.token, txwi, id) {
- mt7921_txwi_free(dev, txwi, NULL, false, NULL);
- dev->mt76.token_count--;
- }
- spin_unlock_bh(&dev->mt76.token_lock);
- idr_destroy(&dev->mt76.token);
-}
-
-int mt7921e_mac_reset(struct mt7921_dev *dev)
+int mt7921e_mac_reset(struct mt792x_dev *dev)
{
int i, err;
- mt7921e_mcu_drv_pmctrl(dev);
+ mt792xe_mcu_drv_pmctrl(dev);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
set_bit(MT76_RESET, &dev->mphy.state);
@@ -91,10 +77,10 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
napi_disable(&dev->mt76.tx_napi);
- mt7921_tx_token_put(dev);
+ mt76_connac2_tx_token_put(&dev->mt76);
idr_init(&dev->mt76.token);
- mt7921_wpdma_reset(dev, true);
+ mt792x_wpdma_reset(dev, true);
local_bh_disable();
mt76_for_each_q_rx(&dev->mt76, i) {
@@ -106,9 +92,9 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
dev->fw_assert = false;
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
+ mt76_wr(dev, dev->irq_map->host_irq_enable,
+ dev->irq_map->tx.all_complete_mask |
+ MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
err = mt7921e_driver_own(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
index 1aefbb6cf0ab..4cf1f2f0f968 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
@@ -4,7 +4,7 @@
#include "mt7921.h"
#include "mcu.h"
-int mt7921e_driver_own(struct mt7921_dev *dev)
+int mt7921e_driver_own(struct mt792x_dev *dev)
{
u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
@@ -22,7 +22,7 @@ static int
mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *seq)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
enum mt76_mcuq_id txq = MT_MCUQ_WM;
int ret;
@@ -38,7 +38,7 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
}
-int mt7921e_mcu_init(struct mt7921_dev *dev)
+int mt7921e_mcu_init(struct mt792x_dev *dev)
{
static const struct mt76_mcu_ops mt7921_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd),
@@ -61,68 +61,3 @@ int mt7921e_mcu_init(struct mt7921_dev *dev)
return err;
}
-
-int __mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev)
-{
- int i, err = 0;
-
- for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
- mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
- if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
- PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1))
- break;
- }
-
- if (i == MT7921_DRV_OWN_RETRY_COUNT) {
- dev_err(dev->mt76.dev, "driver own failed\n");
- err = -EIO;
- }
-
- return err;
-}
-
-int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_pm *pm = &dev->pm;
- int err;
-
- err = __mt7921e_mcu_drv_pmctrl(dev);
- if (err < 0)
- goto out;
-
- mt7921_wpdma_reinit_cond(dev);
- clear_bit(MT76_STATE_PM, &mphy->state);
-
- pm->stats.last_wake_event = jiffies;
- pm->stats.doze_time += pm->stats.last_wake_event -
- pm->stats.last_doze_event;
-out:
- return err;
-}
-
-int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_connac_pm *pm = &dev->pm;
- int i;
-
- for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
- mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
- if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
- PCIE_LPCR_HOST_OWN_SYNC, 4, 50, 1))
- break;
- }
-
- if (i == MT7921_DRV_OWN_RETRY_COUNT) {
- dev_err(dev->mt76.dev, "firmware own failed\n");
- clear_bit(MT76_STATE_PM, &mphy->state);
- return -EIO;
- }
-
- pm->stats.last_doze_event = jiffies;
- pm->stats.awake_time += pm->stats.last_doze_event -
- pm->stats.last_wake_event;
-
- return 0;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
index e52977ff3349..43427a3a48af 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
@@ -4,26 +4,7 @@
#ifndef __MT7921_REGS_H
#define __MT7921_REGS_H
-/* MCU WFDMA1 */
-#define MT_MCU_WFDMA1_BASE 0x3000
-#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs))
-
-#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108)
-#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0)
-#define MT_MCU_INT_EVENT_DMA_INIT BIT(1)
-#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
-#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
-
-#define MT_PLE_BASE 0x820c0000
-#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
-
-#define MT_PLE_FL_Q0_CTRL MT_PLE(0x3e0)
-#define MT_PLE_FL_Q1_CTRL MT_PLE(0x3e4)
-#define MT_PLE_FL_Q2_CTRL MT_PLE(0x3e8)
-#define MT_PLE_FL_Q3_CTRL MT_PLE(0x3ec)
-
-#define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n))
-#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
+#include "../mt792x_regs.h"
#define MT_MDP_BASE 0x820cd000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
@@ -47,280 +28,7 @@
#define MT_MDP_TO_HIF 0
#define MT_MDP_TO_WM 1
-/* TMAC: band 0(0x21000), band 1(0xa1000) */
-#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
-#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
-
-#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
-#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25)
-
-#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
-#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094)
-#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
-#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16)
-
-#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4)
-#define MT_IFS_EIFS GENMASK(8, 0)
-#define MT_IFS_RIFS GENMASK(14, 10)
-#define MT_IFS_SIFS GENMASK(22, 16)
-#define MT_IFS_SLOT GENMASK(30, 24)
-
-#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4)
-#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0)
-#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
-#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
-
-#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
-#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
-
-#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000)
-#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
-
-#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
-#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
-#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
-
-/* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */
-#define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000)
-#define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs))
-
-#define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008)
-#define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30)
-#define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24)
-
-/* LPON: band 0(0x24200), band 1(0xa4200) */
-#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
-#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))
-
-#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080)
-#define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084)
-
-#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4)
-#define MT_LPON_TCR_SW_MODE GENMASK(1, 0)
-#define MT_LPON_TCR_SW_WRITE BIT(0)
-
-/* ETBF: band 0(0x24000), band 1(0xa4000) */
-#define MT_WF_ETBF_BASE(_band) ((_band) ? 0x820fa000 : 0x820ea000)
-#define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs))
-
-#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x150)
-#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16)
-#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0)
-
-#define MT_ETBF_RX_FB_CNT(_band) MT_WF_ETBF(_band, 0x158)
-#define MT_ETBF_RX_FB_ALL GENMASK(31, 24)
-#define MT_ETBF_RX_FB_HE GENMASK(23, 16)
-#define MT_ETBF_RX_FB_VHT GENMASK(15, 8)
-#define MT_ETBF_RX_FB_HT GENMASK(7, 0)
-
-/* MIB: band 0(0x24800), band 1(0xa4800) */
-#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000)
-#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
-
-#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
-#define MT_MIB_TXDUR_EN BIT(8)
-#define MT_MIB_RXDUR_EN BIT(9)
-
-#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x698)
-#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(31, 16)
-
-#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x780)
-
-#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
-#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
-
-#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x558)
-#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x564)
-#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x568)
-
-#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
-#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
-
-#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x770)
-#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x774)
-#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x55c)
-
-#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x7a8)
-#define MT_MIB_SDR9_IBF_CNT_MASK GENMASK(31, 16)
-#define MT_MIB_SDR9_EBF_CNT_MASK GENMASK(15, 0)
-
-#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090)
-#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0)
-
-#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x054)
-#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
-#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x058)
-#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
-
-#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
-#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4)
-#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc)
-
-#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4))
-#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
-#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
-
-#define MT_MIB_MB_BSDR0(_band) MT_WF_MIB(_band, 0x688)
-#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
-#define MT_MIB_MB_BSDR1(_band) MT_WF_MIB(_band, 0x690)
-#define MT_MIB_RTS_FAIL_COUNT_MASK GENMASK(15, 0)
-#define MT_MIB_MB_BSDR2(_band) MT_WF_MIB(_band, 0x518)
-#define MT_MIB_BA_FAIL_COUNT_MASK GENMASK(15, 0)
-#define MT_MIB_MB_BSDR3(_band) MT_WF_MIB(_band, 0x520)
-#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(15, 0)
-
-#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4))
-#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0)
-
-#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x7dc + ((n) << 2))
-#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x7ec + ((n) << 2))
-#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
-#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
-
-#define MT_WTBLON_TOP_BASE 0x820d4000
-#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
-#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200)
-#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
-
-#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x230)
-#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0)
-#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
-#define MT_WTBL_UPDATE_BUSY BIT(31)
-
-#define MT_WTBL_BASE 0x820d8000
-#define MT_WTBL_LMAC_ID GENMASK(14, 8)
-#define MT_WTBL_LMAC_DW GENMASK(7, 2)
-#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
- FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \
- FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
-
-/* AGG: band 0(0x20800), band 1(0xa0800) */
-#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000)
-#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
-
-#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
-#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4)
-#define MT_AGG_PCR0_MM_PROT BIT(0)
-#define MT_AGG_PCR0_GF_PROT BIT(1)
-#define MT_AGG_PCR0_BW20_PROT BIT(2)
-#define MT_AGG_PCR0_BW40_PROT BIT(4)
-#define MT_AGG_PCR0_BW80_PROT BIT(6)
-#define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8)
-#define MT_AGG_PCR0_VHT_PROT BIT(13)
-#define MT_AGG_PCR0_PTA_WIN_DIS BIT(15)
-
-#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23)
-#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0)
-
-#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084)
-#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
-#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)
-
-#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098)
-#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
-#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
-#define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7)
-#define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24)
-
-#define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0)
-#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
-
-/* ARB: band 0(0x20c00), band 1(0xa0c00) */
-#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000)
-#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
-
-#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
-#define MT_ARB_SCR_TX_DISABLE BIT(8)
-#define MT_ARB_SCR_RX_DISABLE BIT(9)
-
-#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
-
-/* RMAC: band 0(0x21400), band 1(0xa1400) */
-#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
-#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
-
-#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)
-#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0)
-#define MT_WF_RFCR_DROP_FCSFAIL BIT(1)
-#define MT_WF_RFCR_DROP_VERSION BIT(3)
-#define MT_WF_RFCR_DROP_PROBEREQ BIT(4)
-#define MT_WF_RFCR_DROP_MCAST BIT(5)
-#define MT_WF_RFCR_DROP_BCAST BIT(6)
-#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7)
-#define MT_WF_RFCR_DROP_A3_MAC BIT(8)
-#define MT_WF_RFCR_DROP_A3_BSSID BIT(9)
-#define MT_WF_RFCR_DROP_A2_BSSID BIT(10)
-#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11)
-#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12)
-#define MT_WF_RFCR_DROP_CTL_RSV BIT(13)
-#define MT_WF_RFCR_DROP_CTS BIT(14)
-#define MT_WF_RFCR_DROP_RTS BIT(15)
-#define MT_WF_RFCR_DROP_DUPLICATE BIT(16)
-#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17)
-#define MT_WF_RFCR_DROP_OTHER_UC BIT(18)
-#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19)
-#define MT_WF_RFCR_DROP_NDPA BIT(20)
-#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
-
-#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004)
-#define MT_WF_RFCR1_DROP_ACK BIT(4)
-#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
-#define MT_WF_RFCR1_DROP_BA BIT(6)
-#define MT_WF_RFCR1_DROP_CFEND BIT(7)
-#define MT_WF_RFCR1_DROP_CFACK BIT(8)
-
-#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4)
-#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
-#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
-
-#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8)
-#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
-#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
-
-/* WFDMA0 */
-#define MT_WFDMA0_BASE 0xd4000
-#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs))
-
-#define MT_WFDMA0_RST MT_WFDMA0(0x100)
-#define MT_WFDMA0_RST_LOGIC_RST BIT(4)
-#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5)
-
-#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c)
-#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0)
-#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
-#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)
-
-#define MT_MCU_CMD MT_WFDMA0(0x1f0)
-#define MT_MCU_CMD_WAKE_RX_PCIE BIT(0)
-#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
-#define MT_MCU_CMD_STOP_DMA BIT(2)
-#define MT_MCU_CMD_RESET_DONE BIT(3)
-#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
-#define MT_MCU_CMD_NORMAL_STATE BIT(5)
-#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
-
-#define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4)
-
-#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200)
-#define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */
-#define HOST_RX_DONE_INT_STS2 BIT(2) /* Rx data */
-#define HOST_RX_DONE_INT_STS4 BIT(22) /* Rx mcu after fw downloaded */
-#define HOST_TX_DONE_INT_STS16 BIT(26)
-#define HOST_TX_DONE_INT_STS17 BIT(27) /* MCU tx done*/
-
#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x204)
-#define HOST_RX_DONE_INT_ENA0 BIT(0)
-#define HOST_RX_DONE_INT_ENA1 BIT(1)
-#define HOST_RX_DONE_INT_ENA2 BIT(2)
-#define HOST_RX_DONE_INT_ENA3 BIT(3)
-#define HOST_TX_DONE_INT_ENA0 BIT(4)
-#define HOST_TX_DONE_INT_ENA1 BIT(5)
-#define HOST_TX_DONE_INT_ENA2 BIT(6)
-#define HOST_TX_DONE_INT_ENA3 BIT(7)
-#define HOST_TX_DONE_INT_ENA4 BIT(8)
-#define HOST_TX_DONE_INT_ENA5 BIT(9)
-#define HOST_TX_DONE_INT_ENA6 BIT(10)
-#define HOST_TX_DONE_INT_ENA7 BIT(11)
#define HOST_TX_DONE_INT_ENA8 BIT(12)
#define HOST_TX_DONE_INT_ENA9 BIT(13)
#define HOST_TX_DONE_INT_ENA10 BIT(14)
@@ -328,14 +36,10 @@
#define HOST_TX_DONE_INT_ENA12 BIT(16)
#define HOST_TX_DONE_INT_ENA13 BIT(17)
#define HOST_TX_DONE_INT_ENA14 BIT(18)
-#define HOST_RX_COHERENT_EN BIT(20)
-#define HOST_TX_COHERENT_EN BIT(21)
#define HOST_RX_DONE_INT_ENA4 BIT(22)
#define HOST_RX_DONE_INT_ENA5 BIT(23)
#define HOST_TX_DONE_INT_ENA16 BIT(26)
#define HOST_TX_DONE_INT_ENA17 BIT(27)
-#define MCU2HOST_SW_INT_ENA BIT(29)
-#define HOST_TX_DONE_INT_ENA18 BIT(30)
/* WFDMA interrupt */
#define MT_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2
@@ -347,7 +51,6 @@
#define MT_INT_TX_DONE_MCU_WM HOST_TX_DONE_INT_ENA17
#define MT_INT_TX_DONE_FWDL HOST_TX_DONE_INT_ENA16
#define MT_INT_TX_DONE_BAND0 HOST_TX_DONE_INT_ENA0
-#define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA
#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WM | \
MT_INT_TX_DONE_FWDL)
@@ -355,56 +58,8 @@
MT_INT_TX_DONE_BAND0 | \
GENMASK(18, 4))
-#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
-#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
-#define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1)
-#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
-#define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3)
-#define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6)
-#define MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL BIT(9)
-#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12)
-#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15)
-#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21)
-#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
-#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
-#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS BIT(30)
-
-#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c)
-#define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
-#define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6)
-#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0)
-
#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x520)
-#define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600)
-#define MT_WFDMA0_TX_RING1_EXT_CTRL MT_WFDMA0(0x604)
-#define MT_WFDMA0_TX_RING2_EXT_CTRL MT_WFDMA0(0x608)
-#define MT_WFDMA0_TX_RING3_EXT_CTRL MT_WFDMA0(0x60c)
-#define MT_WFDMA0_TX_RING4_EXT_CTRL MT_WFDMA0(0x610)
-#define MT_WFDMA0_TX_RING5_EXT_CTRL MT_WFDMA0(0x614)
-#define MT_WFDMA0_TX_RING6_EXT_CTRL MT_WFDMA0(0x618)
-#define MT_WFDMA0_TX_RING16_EXT_CTRL MT_WFDMA0(0x640)
-#define MT_WFDMA0_TX_RING17_EXT_CTRL MT_WFDMA0(0x644)
-
-#define MT_WPDMA0_MAX_CNT_MASK GENMASK(7, 0)
-#define MT_WPDMA0_BASE_PTR_MASK GENMASK(31, 16)
-
-#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680)
-#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684)
-#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688)
-#define MT_WFDMA0_RX_RING3_EXT_CTRL MT_WFDMA0(0x68c)
-#define MT_WFDMA0_RX_RING4_EXT_CTRL MT_WFDMA0(0x690)
-#define MT_WFDMA0_RX_RING5_EXT_CTRL MT_WFDMA0(0x694)
-
-#define MT_TX_RING_BASE MT_WFDMA0(0x300)
-#define MT_RX_EVENT_RING_BASE MT_WFDMA0(0x500)
-
-/* WFDMA CSR */
-#define MT_WFDMA_EXT_CSR_BASE 0xd7000
-#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs))
-#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
-#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
-
#define MT_INFRA_CFG_BASE 0xfe000
#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs))
@@ -414,121 +69,13 @@
#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16)
#define MT_HIF_REMAP_BASE_L1 0x40000
-#define MT_SWDEF_BASE 0x41f200
-#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
-#define MT_SWDEF_MODE MT_SWDEF(0x3c)
-#define MT_SWDEF_NORMAL_MODE 0
-#define MT_SWDEF_ICAP_MODE 1
-#define MT_SWDEF_SPECTRUM_MODE 2
-
-#define MT_TOP_BASE 0x18060000
-#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
-
-#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10)
-#define MT_TOP_LPCR_HOST_FW_OWN BIT(0)
-#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1)
-
-#define MT_TOP_MISC MT_TOP(0xf0)
-#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
-
-#define MT_MCU_WPDMA0_BASE 0x54000000
-#define MT_MCU_WPDMA0(ofs) (MT_MCU_WPDMA0_BASE + (ofs))
-
-#define MT_WFDMA_DUMMY_CR MT_MCU_WPDMA0(0x120)
-#define MT_WFDMA_NEED_REINIT BIT(1)
-
-#define MT_CBTOP_RGU(ofs) (0x70002000 + (ofs))
-#define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
-#define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
-
-#define MT_HW_BOUND 0x70010020
-#define MT_HW_CHIPID 0x70010200
-#define MT_HW_REV 0x70010204
-
-#define MT_PCIE_MAC_BASE 0x10000
-#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs))
-#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188)
-#define MT_PCIE_MAC_PM MT_PCIE_MAC(0x194)
-#define MT_PCIE_MAC_PM_L0S_DIS BIT(8)
-
-#define MT_DMA_SHDL(ofs) (0x7c026000 + (ofs))
-#define MT_DMASHDL_SW_CONTROL MT_DMA_SHDL(0x004)
-#define MT_DMASHDL_DMASHDL_BYPASS BIT(28)
-#define MT_DMASHDL_OPTIONAL MT_DMA_SHDL(0x008)
-#define MT_DMASHDL_PAGE MT_DMA_SHDL(0x00c)
-#define MT_DMASHDL_GROUP_SEQ_ORDER BIT(16)
-#define MT_DMASHDL_REFILL MT_DMA_SHDL(0x010)
-#define MT_DMASHDL_REFILL_MASK GENMASK(31, 16)
-#define MT_DMASHDL_PKT_MAX_SIZE MT_DMA_SHDL(0x01c)
-#define MT_DMASHDL_PKT_MAX_SIZE_PLE GENMASK(11, 0)
-#define MT_DMASHDL_PKT_MAX_SIZE_PSE GENMASK(27, 16)
-
-#define MT_DMASHDL_GROUP_QUOTA(_n) MT_DMA_SHDL(0x020 + ((_n) << 2))
-#define MT_DMASHDL_GROUP_QUOTA_MIN GENMASK(11, 0)
-#define MT_DMASHDL_GROUP_QUOTA_MAX GENMASK(27, 16)
-
-#define MT_DMASHDL_Q_MAP(_n) MT_DMA_SHDL(0x060 + ((_n) << 2))
-#define MT_DMASHDL_Q_MAP_MASK GENMASK(3, 0)
-#define MT_DMASHDL_Q_MAP_SHIFT(_n) (4 * ((_n) % 8))
-
-#define MT_DMASHDL_SCHED_SET(_n) MT_DMA_SHDL(0x070 + ((_n) << 2))
-
-#define MT_WFDMA_HOST_CONFIG 0x7c027030
-#define MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN BIT(6)
-
-#define MT_UMAC(ofs) (0x74000000 + (ofs))
-#define MT_UDMA_TX_QSEL MT_UMAC(0x008)
-#define MT_FW_DL_EN BIT(3)
-
-#define MT_UDMA_WLCFG_1 MT_UMAC(0x00c)
-#define MT_WL_RX_AGG_PKT_LMT GENMASK(7, 0)
-#define MT_WL_TX_TMOUT_LMT GENMASK(27, 8)
-
-#define MT_UDMA_WLCFG_0 MT_UMAC(0x18)
-#define MT_WL_RX_AGG_TO GENMASK(7, 0)
-#define MT_WL_RX_AGG_LMT GENMASK(15, 8)
-#define MT_WL_TX_TMOUT_FUNC_EN BIT(16)
-#define MT_WL_TX_DPH_CHK_EN BIT(17)
-#define MT_WL_RX_MPSZ_PAD0 BIT(18)
-#define MT_WL_RX_FLUSH BIT(19)
-#define MT_TICK_1US_EN BIT(20)
-#define MT_WL_RX_AGG_EN BIT(21)
-#define MT_WL_RX_EN BIT(22)
-#define MT_WL_TX_EN BIT(23)
-#define MT_WL_RX_BUSY BIT(30)
-#define MT_WL_TX_BUSY BIT(31)
-
-#define MT_UDMA_CONN_INFRA_STATUS MT_UMAC(0xa20)
-#define MT_UDMA_CONN_WFSYS_INIT_DONE BIT(22)
-#define MT_UDMA_CONN_INFRA_STATUS_SEL MT_UMAC(0xa24)
-
-#define MT_SSUSB_EPCTL_CSR(ofs) (0x74011800 + (ofs))
-#define MT_SSUSB_EPCTL_CSR_EP_RST_OPT MT_SSUSB_EPCTL_CSR(0x090)
-
-#define MT_UWFDMA0(ofs) (0x7c024000 + (ofs))
-#define MT_UWFDMA0_GLO_CFG MT_UWFDMA0(0x208)
-#define MT_UWFDMA0_GLO_CFG_EXT0 MT_UWFDMA0(0x2b0)
-#define MT_UWFDMA0_TX_RING_EXT_CTRL(_n) MT_UWFDMA0(0x600 + ((_n) << 2))
-
-#define MT_CONN_STATUS 0x7c053c10
-#define MT_WIFI_PATCH_DL_STATE BIT(0)
-
-#define MT_CONN_ON_LPCTL 0x7c060010
-#define PCIE_LPCR_HOST_OWN_SYNC BIT(2)
-#define PCIE_LPCR_HOST_CLR_OWN BIT(1)
-#define PCIE_LPCR_HOST_SET_OWN BIT(0)
-
#define MT_WFSYS_SW_RST_B 0x18000140
-#define WFSYS_SW_RST_B BIT(0)
-#define WFSYS_SW_INIT_DONE BIT(4)
-#define MT_CONN_ON_MISC 0x7c0600f0
-#define MT_TOP_MISC2_FW_PWR_ON BIT(0)
-#define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0)
+#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200)
+#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
-#define MT_WF_SW_DEF_CR(ofs) (0x401a00 + (ofs))
-#define MT_WF_SW_DEF_CR_USB_MCU_EVENT MT_WF_SW_DEF_CR(0x028)
-#define MT_WF_SW_SER_TRIGGER_SUSPEND BIT(6)
-#define MT_WF_SW_SER_DONE_SUSPEND BIT(7)
+#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x230)
+#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0)
+#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
index a77a309c0d60..dc1beb76df3e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -27,7 +27,7 @@ static void mt7921s_txrx_worker(struct mt76_worker *w)
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(mdev->wq, &dev->pm.wake_work);
@@ -38,7 +38,7 @@ static void mt7921s_txrx_worker(struct mt76_worker *w)
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
-static void mt7921s_unregister_device(struct mt7921_dev *dev)
+static void mt7921s_unregister_device(struct mt792x_dev *dev)
{
struct mt76_connac_pm *pm = &dev->pm;
@@ -102,7 +102,7 @@ static int mt7921s_probe(struct sdio_func *func,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
- .update_survey = mt7921_update_channel,
+ .update_survey = mt792x_update_channel,
};
static const struct mt76_bus_ops mt7921s_ops = {
.rr = mt76s_rr,
@@ -114,7 +114,7 @@ static int mt7921s_probe(struct sdio_func *func,
.rd_rp = mt76s_rd_rp,
.type = MT76_BUS_SDIO,
};
- static const struct mt7921_hif_ops mt7921_sdio_ops = {
+ static const struct mt792x_hif_ops mt7921_sdio_ops = {
.init_reset = mt7921s_init_reset,
.reset = mt7921s_mac_reset,
.mcu_init = mt7921s_mcu_init,
@@ -122,13 +122,13 @@ static int mt7921s_probe(struct sdio_func *func,
.fw_own = mt7921s_mcu_fw_pmctrl,
};
struct ieee80211_ops *ops;
- struct mt7921_dev *dev;
+ struct mt792x_dev *dev;
struct mt76_dev *mdev;
u8 features;
int ret;
- ops = mt7921_get_mac80211_ops(&func->dev, (void *)id->driver_data,
- &features);
+ ops = mt792x_get_mac80211_ops(&func->dev, &mt7921_ops,
+ (void *)id->driver_data, &features);
if (!ops)
return -ENOMEM;
@@ -136,7 +136,7 @@ static int mt7921s_probe(struct sdio_func *func,
if (!mdev)
return -ENOMEM;
- dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &mt7921_sdio_ops;
sdio_set_drvdata(func, dev);
@@ -196,7 +196,7 @@ error:
static void mt7921s_remove(struct sdio_func *func)
{
- struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt792x_dev *dev = sdio_get_drvdata(func);
mt7921s_unregister_device(dev);
}
@@ -204,7 +204,7 @@ static void mt7921s_remove(struct sdio_func *func)
static int mt7921s_suspend(struct device *__dev)
{
struct sdio_func *func = dev_to_sdio_func(__dev);
- struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt792x_dev *dev = sdio_get_drvdata(func);
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_dev *mdev = &dev->mt76;
int err;
@@ -216,7 +216,7 @@ static int mt7921s_suspend(struct device *__dev)
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- err = mt7921_mcu_drv_pmctrl(dev);
+ err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
goto restore_suspend;
@@ -244,7 +244,7 @@ static int mt7921s_suspend(struct device *__dev)
mt76_worker_disable(&mdev->sdio.txrx_worker);
mt76_worker_disable(&mdev->sdio.net_worker);
- err = mt7921_mcu_fw_pmctrl(dev);
+ err = mt792x_mcu_fw_pmctrl(dev);
if (err)
goto restore_txrx_worker;
@@ -269,7 +269,7 @@ restore_suspend:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
@@ -277,14 +277,14 @@ restore_suspend:
static int mt7921s_resume(struct device *__dev)
{
struct sdio_func *func = dev_to_sdio_func(__dev);
- struct mt7921_dev *dev = sdio_get_drvdata(func);
+ struct mt792x_dev *dev = sdio_get_drvdata(func);
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_dev *mdev = &dev->mt76;
int err;
clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
- err = mt7921_mcu_drv_pmctrl(dev);
+ err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
goto failed;
@@ -302,7 +302,7 @@ failed:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
index cff9925c41ea..8edd0291c128 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -30,7 +30,7 @@ static u32 mt7921s_read_whcr(struct mt76_dev *dev)
return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
}
-int mt7921s_wfsys_reset(struct mt7921_dev *dev)
+int mt7921s_wfsys_reset(struct mt792x_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
u32 val, status;
@@ -71,7 +71,7 @@ int mt7921s_wfsys_reset(struct mt7921_dev *dev)
return 0;
}
-int mt7921s_init_reset(struct mt7921_dev *dev)
+int mt7921s_init_reset(struct mt792x_dev *dev)
{
set_bit(MT76_MCU_RESET, &dev->mphy.state);
@@ -91,7 +91,7 @@ int mt7921s_init_reset(struct mt7921_dev *dev)
return 0;
}
-int mt7921s_mac_reset(struct mt7921_dev *dev)
+int mt7921s_mac_reset(struct mt792x_dev *dev)
{
int err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
index 177679ce1c80..310eeca024ad 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
@@ -16,14 +16,14 @@ static int
mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *seq)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD;
enum mt76_mcuq_id txq = MT_MCUQ_WM;
int ret, pad;
/* We just return in case firmware assertion to avoid blocking the
* common workqueue to run, for example, the coredump work might be
- * blocked by mt7921_mac_work that is excuting register access via sdio
+ * blocked by mt792x_mac_work that is excuting register access via sdio
* bus.
*/
if (dev->fw_assert)
@@ -51,14 +51,14 @@ mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
return ret;
}
-static u32 mt7921s_read_rm3r(struct mt7921_dev *dev)
+static u32 mt7921s_read_rm3r(struct mt792x_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
return sdio_readl(sdio->func, MCR_D2HRM3R, NULL);
}
-static u32 mt7921s_clear_rm3r_drv_own(struct mt7921_dev *dev)
+static u32 mt7921s_clear_rm3r_drv_own(struct mt792x_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
u32 val;
@@ -71,7 +71,7 @@ static u32 mt7921s_clear_rm3r_drv_own(struct mt7921_dev *dev)
return val;
}
-int mt7921s_mcu_init(struct mt7921_dev *dev)
+int mt7921s_mcu_init(struct mt792x_dev *dev)
{
static const struct mt76_mcu_ops mt7921s_mcu_ops = {
.headroom = MT_SDIO_HDR_SIZE +
@@ -97,7 +97,7 @@ int mt7921s_mcu_init(struct mt7921_dev *dev)
return 0;
}
-int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev)
+int mt7921s_mcu_drv_pmctrl(struct mt792x_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -133,7 +133,7 @@ int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev)
return 0;
}
-int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev)
+int mt7921s_mcu_fw_pmctrl(struct mt792x_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
index 7f408212e716..e838d93477c1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
@@ -31,7 +31,7 @@ static const struct nla_policy mt7921_tm_policy[NUM_MT7921_TM_ATTRS] = {
};
static int
-mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
+mt7921_tm_set(struct mt792x_dev *dev, struct mt7921_tm_cmd *req)
{
struct mt7921_rftest_cmd cmd = {
.action = req->action,
@@ -57,7 +57,7 @@ mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
pm->enable = false;
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- __mt7921_mcu_drv_pmctrl(dev);
+ __mt792x_mcu_drv_pmctrl(dev);
phy->test.state = MT76_TM_STATE_ON;
}
@@ -82,7 +82,7 @@ out:
}
static int
-mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req,
+mt7921_tm_query(struct mt792x_dev *dev, struct mt7921_tm_cmd *req,
struct mt7921_tm_evt *evt_resp)
{
struct mt7921_rftest_cmd cmd = {
@@ -113,7 +113,7 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
struct nlattr *tb[NUM_MT76_TM_ATTRS];
struct mt76_phy *mphy = hw->priv;
- struct mt7921_phy *phy = mphy->priv;
+ struct mt792x_phy *phy = mphy->priv;
int err;
if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
@@ -150,7 +150,7 @@ int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
{
struct nlattr *tb[NUM_MT76_TM_ATTRS];
struct mt76_phy *mphy = hw->priv;
- struct mt7921_phy *phy = mphy->priv;
+ struct mt792x_phy *phy = mphy->priv;
int err;
if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/trace.c b/drivers/net/wireless/mediatek/mt76/mt7921/trace.c
deleted file mode 100644
index 4dc3c7b89ebd..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7921/trace.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-License-Identifier: ISC
-/*
- * Copyright (C) 2021 Lorenzo Bianconi <lorenzo@kernel.org>
- */
-
-#include <linux/module.h>
-
-#ifndef __CHECKER__
-#define CREATE_TRACE_POINTS
-#include "mt7921_trace.h"
-
-#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 1f302c430339..59cd3d98bf90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -24,88 +24,11 @@ static const struct usb_device_id mt7921u_device_table[] = {
{ },
};
-static u32 mt7921u_rr(struct mt76_dev *dev, u32 addr)
-{
- u32 ret;
-
- mutex_lock(&dev->usb.usb_ctrl_mtx);
- ret = ___mt76u_rr(dev, MT_VEND_READ_EXT,
- USB_DIR_IN | MT_USB_TYPE_VENDOR, addr);
- mutex_unlock(&dev->usb.usb_ctrl_mtx);
-
- return ret;
-}
-
-static void mt7921u_wr(struct mt76_dev *dev, u32 addr, u32 val)
-{
- mutex_lock(&dev->usb.usb_ctrl_mtx);
- ___mt76u_wr(dev, MT_VEND_WRITE_EXT,
- USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val);
- mutex_unlock(&dev->usb.usb_ctrl_mtx);
-}
-
-static u32 mt7921u_rmw(struct mt76_dev *dev, u32 addr,
- u32 mask, u32 val)
-{
- mutex_lock(&dev->usb.usb_ctrl_mtx);
- val |= ___mt76u_rr(dev, MT_VEND_READ_EXT,
- USB_DIR_IN | MT_USB_TYPE_VENDOR, addr) & ~mask;
- ___mt76u_wr(dev, MT_VEND_WRITE_EXT,
- USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val);
- mutex_unlock(&dev->usb.usb_ctrl_mtx);
-
- return val;
-}
-
-static void mt7921u_copy(struct mt76_dev *dev, u32 offset,
- const void *data, int len)
-{
- struct mt76_usb *usb = &dev->usb;
- int ret, i = 0, batch_len;
- const u8 *val = data;
-
- len = round_up(len, 4);
-
- mutex_lock(&usb->usb_ctrl_mtx);
- while (i < len) {
- batch_len = min_t(int, usb->data_len, len - i);
- memcpy(usb->data, val + i, batch_len);
- ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT,
- USB_DIR_OUT | MT_USB_TYPE_VENDOR,
- (offset + i) >> 16, offset + i,
- usb->data, batch_len);
- if (ret < 0)
- break;
-
- i += batch_len;
- }
- mutex_unlock(&usb->usb_ctrl_mtx);
-}
-
-int mt7921u_mcu_power_on(struct mt7921_dev *dev)
-{
- int ret;
-
- ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON,
- USB_DIR_OUT | MT_USB_TYPE_VENDOR,
- 0x0, 0x1, NULL, 0);
- if (ret)
- return ret;
-
- if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON,
- MT_TOP_MISC2_FW_PWR_ON, 500)) {
- dev_err(dev->mt76.dev, "Timeout for power on\n");
- ret = -EIO;
- }
-
- return ret;
-}
-
static int
mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *seq)
{
- struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
u32 pad, ep;
int ret;
@@ -131,7 +54,7 @@ mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
return ret;
}
-static int mt7921u_mcu_init(struct mt7921_dev *dev)
+static int mt7921u_mcu_init(struct mt792x_dev *dev)
{
static const struct mt76_mcu_ops mcu_ops = {
.headroom = MT_SDIO_HDR_SIZE +
@@ -155,20 +78,69 @@ static int mt7921u_mcu_init(struct mt7921_dev *dev)
return 0;
}
-static void mt7921u_stop(struct ieee80211_hw *hw)
+static int mt7921u_mac_reset(struct mt792x_dev *dev)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ int err;
+
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_worker_disable(&dev->mt76.tx_worker);
+ set_bit(MT76_RESET, &dev->mphy.state);
+ set_bit(MT76_MCU_RESET, &dev->mphy.state);
+
+ wake_up(&dev->mt76.mcu.wait);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+
+ mt76u_stop_rx(&dev->mt76);
mt76u_stop_tx(&dev->mt76);
- mt7921_stop(hw);
+
+ mt792xu_wfsys_reset(dev);
+
+ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+ err = mt76u_resume_rx(&dev->mt76);
+ if (err)
+ goto out;
+
+ err = mt792xu_mcu_power_on(dev);
+ if (err)
+ goto out;
+
+ err = mt792xu_dma_init(dev, false);
+ if (err)
+ goto out;
+
+ mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
+ mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);
+
+ err = mt7921_run_firmware(dev);
+ if (err)
+ goto out;
+
+ mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);
+
+ err = mt7921_mcu_set_eeprom(dev);
+ if (err)
+ goto out;
+
+ err = mt7921_mac_init(dev);
+ if (err)
+ goto out;
+
+ err = __mt7921_start(&dev->phy);
+out:
+ clear_bit(MT76_RESET, &dev->mphy.state);
+
+ mt76_worker_enable(&dev->mt76.tx_worker);
+
+ return err;
}
-static void mt7921u_cleanup(struct mt7921_dev *dev)
+static void mt7921u_stop(struct ieee80211_hw *hw)
{
- clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
- mt7921u_wfsys_reset(dev);
- skb_queue_purge(&dev->mt76.mcu.res_q);
- mt76u_queues_deinit(&dev->mt76);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+
+ mt76u_stop_tx(&dev->mt76);
+ mt7921_stop(hw);
}
static int mt7921u_probe(struct usb_interface *usb_intf,
@@ -189,31 +161,31 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
- .update_survey = mt7921_update_channel,
+ .update_survey = mt792x_update_channel,
};
- static const struct mt7921_hif_ops hif_ops = {
+ static const struct mt792x_hif_ops hif_ops = {
.mcu_init = mt7921u_mcu_init,
- .init_reset = mt7921u_init_reset,
+ .init_reset = mt792xu_init_reset,
.reset = mt7921u_mac_reset,
};
static struct mt76_bus_ops bus_ops = {
- .rr = mt7921u_rr,
- .wr = mt7921u_wr,
- .rmw = mt7921u_rmw,
+ .rr = mt792xu_rr,
+ .wr = mt792xu_wr,
+ .rmw = mt792xu_rmw,
.read_copy = mt76u_read_copy,
- .write_copy = mt7921u_copy,
+ .write_copy = mt792xu_copy,
.type = MT76_BUS_USB,
};
struct usb_device *udev = interface_to_usbdev(usb_intf);
struct ieee80211_ops *ops;
struct ieee80211_hw *hw;
- struct mt7921_dev *dev;
+ struct mt792x_dev *dev;
struct mt76_dev *mdev;
u8 features;
int ret;
- ops = mt7921_get_mac80211_ops(&usb_intf->dev, (void *)id->driver_info,
- &features);
+ ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7921_ops,
+ (void *)id->driver_info, &features);
if (!ops)
return -ENOMEM;
@@ -222,7 +194,7 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
if (!mdev)
return -ENOMEM;
- dev = container_of(mdev, struct mt7921_dev, mt76);
+ dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &hif_ops;
@@ -240,12 +212,12 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {
- ret = mt7921u_wfsys_reset(dev);
+ ret = mt792xu_wfsys_reset(dev);
if (ret)
goto error;
}
- ret = mt7921u_mcu_power_on(dev);
+ ret = mt792xu_mcu_power_on(dev);
if (ret)
goto error;
@@ -257,7 +229,7 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
if (ret)
goto error;
- ret = mt7921u_dma_init(dev, false);
+ ret = mt792xu_dma_init(dev, false);
if (ret)
goto error;
@@ -282,27 +254,10 @@ error:
return ret;
}
-static void mt7921u_disconnect(struct usb_interface *usb_intf)
-{
- struct mt7921_dev *dev = usb_get_intfdata(usb_intf);
-
- cancel_work_sync(&dev->init_work);
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
- return;
-
- mt76_unregister_device(&dev->mt76);
- mt7921u_cleanup(dev);
-
- usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
-
- mt76_free_device(&dev->mt76);
-}
-
#ifdef CONFIG_PM
static int mt7921u_suspend(struct usb_interface *intf, pm_message_t state)
{
- struct mt7921_dev *dev = usb_get_intfdata(intf);
+ struct mt792x_dev *dev = usb_get_intfdata(intf);
struct mt76_connac_pm *pm = &dev->pm;
int err;
@@ -322,14 +277,14 @@ failed:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
static int mt7921u_resume(struct usb_interface *intf)
{
- struct mt7921_dev *dev = usb_get_intfdata(intf);
+ struct mt792x_dev *dev = usb_get_intfdata(intf);
struct mt76_connac_pm *pm = &dev->pm;
bool reinit = true;
int err, i;
@@ -349,8 +304,8 @@ static int mt7921u_resume(struct usb_interface *intf)
msleep(20);
}
- if (reinit || mt7921_dma_need_reinit(dev)) {
- err = mt7921u_dma_init(dev, true);
+ if (reinit || mt792x_dma_need_reinit(dev)) {
+ err = mt792xu_dma_init(dev, true);
if (err)
goto failed;
}
@@ -364,7 +319,7 @@ failed:
pm->suspended = false;
if (err < 0)
- mt7921_reset(&dev->mt76);
+ mt792x_reset(&dev->mt76);
return err;
}
@@ -378,7 +333,7 @@ static struct usb_driver mt7921u_driver = {
.name = KBUILD_MODNAME,
.id_table = mt7921u_device_table,
.probe = mt7921u_probe,
- .disconnect = mt7921u_disconnect,
+ .disconnect = mt792xu_disconnect,
#ifdef CONFIG_PM
.suspend = mt7921u_suspend,
.resume = mt7921u_resume,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c
deleted file mode 100644
index 50eb6e7fd6b5..000000000000
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb_mac.c
+++ /dev/null
@@ -1,255 +0,0 @@
-// SPDX-License-Identifier: ISC
-/* Copyright (C) 2022 MediaTek Inc.
- *
- * Author: Lorenzo Bianconi <lorenzo@kernel.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-#include "mt7921.h"
-#include "mcu.h"
-#include "../mt76_connac2_mac.h"
-
-static u32 mt7921u_uhw_rr(struct mt76_dev *dev, u32 addr)
-{
- u32 ret;
-
- mutex_lock(&dev->usb.usb_ctrl_mtx);
- ret = ___mt76u_rr(dev, MT_VEND_DEV_MODE,
- USB_DIR_IN | MT_USB_TYPE_UHW_VENDOR, addr);
- mutex_unlock(&dev->usb.usb_ctrl_mtx);
-
- return ret;
-}
-
-static void mt7921u_uhw_wr(struct mt76_dev *dev, u32 addr, u32 val)
-{
- mutex_lock(&dev->usb.usb_ctrl_mtx);
- ___mt76u_wr(dev, MT_VEND_WRITE,
- USB_DIR_OUT | MT_USB_TYPE_UHW_VENDOR, addr, val);
- mutex_unlock(&dev->usb.usb_ctrl_mtx);
-}
-
-static void mt7921u_dma_prefetch(struct mt7921_dev *dev)
-{
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0),
- MT_WPDMA0_BASE_PTR_MASK, 0x80);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1),
- MT_WPDMA0_BASE_PTR_MASK, 0xc0);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2),
- MT_WPDMA0_BASE_PTR_MASK, 0x100);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3),
- MT_WPDMA0_BASE_PTR_MASK, 0x140);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4),
- MT_WPDMA0_BASE_PTR_MASK, 0x180);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16),
- MT_WPDMA0_BASE_PTR_MASK, 0x280);
-
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17),
- MT_WPDMA0_MAX_CNT_MASK, 4);
- mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17),
- MT_WPDMA0_BASE_PTR_MASK, 0x2c0);
-}
-
-static void mt7921u_wfdma_init(struct mt7921_dev *dev)
-{
- mt7921u_dma_prefetch(dev);
-
- mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_OMIT_RX_INFO);
- mt76_set(dev, MT_UWFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 |
- MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL |
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
-
- /* disable dmashdl */
- mt76_clear(dev, MT_UWFDMA0_GLO_CFG_EXT0,
- MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
- mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
-
- mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
-}
-
-static int mt7921u_dma_rx_evt_ep4(struct mt7921_dev *dev)
-{
- if (!mt76_poll(dev, MT_UWFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000))
- return -ETIMEDOUT;
-
- mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN);
- mt76_set(dev, MT_WFDMA_HOST_CONFIG,
- MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN);
- mt76_set(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN);
-
- return 0;
-}
-
-static void mt7921u_epctl_rst_opt(struct mt7921_dev *dev, bool reset)
-{
- u32 val;
-
- /* usb endpoint reset opt
- * bits[4,9]: out blk ep 4-9
- * bits[20,21]: in blk ep 4-5
- * bits[22]: in int ep 6
- */
- val = mt7921u_uhw_rr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT);
- if (reset)
- val |= GENMASK(9, 4) | GENMASK(22, 20);
- else
- val &= ~(GENMASK(9, 4) | GENMASK(22, 20));
- mt7921u_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val);
-}
-
-int mt7921u_dma_init(struct mt7921_dev *dev, bool resume)
-{
- int err;
-
- mt7921u_wfdma_init(dev);
-
- mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH);
-
- mt76_set(dev, MT_UDMA_WLCFG_0,
- MT_WL_RX_EN | MT_WL_TX_EN |
- MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN);
- mt76_clear(dev, MT_UDMA_WLCFG_0,
- MT_WL_RX_AGG_TO | MT_WL_RX_AGG_LMT);
- mt76_clear(dev, MT_UDMA_WLCFG_1, MT_WL_RX_AGG_PKT_LMT);
-
- if (resume)
- return 0;
-
- err = mt7921u_dma_rx_evt_ep4(dev);
- if (err)
- return err;
-
- mt7921u_epctl_rst_opt(dev, false);
-
- return 0;
-}
-
-int mt7921u_wfsys_reset(struct mt7921_dev *dev)
-{
- u32 val;
- int i;
-
- mt7921u_epctl_rst_opt(dev, false);
-
- val = mt7921u_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
- val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
- mt7921u_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
-
- usleep_range(10, 20);
-
- val = mt7921u_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
- val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
- mt7921u_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
-
- mt7921u_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
- for (i = 0; i < MT7921_WFSYS_INIT_RETRY_COUNT; i++) {
- val = mt7921u_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS);
- if (val & MT_UDMA_CONN_WFSYS_INIT_DONE)
- break;
-
- msleep(100);
- }
-
- if (i == MT7921_WFSYS_INIT_RETRY_COUNT)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-int mt7921u_init_reset(struct mt7921_dev *dev)
-{
- set_bit(MT76_RESET, &dev->mphy.state);
-
- wake_up(&dev->mt76.mcu.wait);
- skb_queue_purge(&dev->mt76.mcu.res_q);
-
- mt76u_stop_rx(&dev->mt76);
- mt76u_stop_tx(&dev->mt76);
-
- mt7921u_wfsys_reset(dev);
-
- clear_bit(MT76_RESET, &dev->mphy.state);
-
- return mt76u_resume_rx(&dev->mt76);
-}
-
-int mt7921u_mac_reset(struct mt7921_dev *dev)
-{
- int err;
-
- mt76_txq_schedule_all(&dev->mphy);
- mt76_worker_disable(&dev->mt76.tx_worker);
-
- set_bit(MT76_RESET, &dev->mphy.state);
- set_bit(MT76_MCU_RESET, &dev->mphy.state);
-
- wake_up(&dev->mt76.mcu.wait);
- skb_queue_purge(&dev->mt76.mcu.res_q);
-
- mt76u_stop_rx(&dev->mt76);
- mt76u_stop_tx(&dev->mt76);
-
- mt7921u_wfsys_reset(dev);
-
- clear_bit(MT76_MCU_RESET, &dev->mphy.state);
- err = mt76u_resume_rx(&dev->mt76);
- if (err)
- goto out;
-
- err = mt7921u_mcu_power_on(dev);
- if (err)
- goto out;
-
- err = mt7921u_dma_init(dev, false);
- if (err)
- goto out;
-
- mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
- mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);
-
- err = mt7921_run_firmware(dev);
- if (err)
- goto out;
-
- mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN);
-
- err = mt7921_mcu_set_eeprom(dev);
- if (err)
- goto out;
-
- err = mt7921_mac_init(dev);
- if (err)
- goto out;
-
- err = __mt7921_start(&dev->phy);
-out:
- clear_bit(MT76_RESET, &dev->mphy.state);
-
- mt76_worker_enable(&dev->mt76.tx_worker);
-
- return err;
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
new file mode 100644
index 000000000000..5d5ab8630041
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -0,0 +1,367 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#ifndef __MT792X_H
+#define __MT792X_H
+
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+
+#include "mt76_connac_mcu.h"
+#include "mt792x_regs.h"
+#include "mt792x_acpi_sar.h"
+
+#define MT792x_PM_TIMEOUT (HZ / 12)
+#define MT792x_HW_SCAN_TIMEOUT (HZ / 10)
+
+#define MT792x_MAX_INTERFACES 4
+#define MT792x_WTBL_SIZE 20
+#define MT792x_WTBL_RESERVED (MT792x_WTBL_SIZE - 1)
+#define MT792x_WTBL_STA (MT792x_WTBL_RESERVED - MT792x_MAX_INTERFACES)
+
+#define MT792x_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
+#define MT792x_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
+
+#define MT792x_FW_TAG_FEATURE 4
+#define MT792x_FW_CAP_CNM BIT(7)
+
+/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
+#define MT792x_BASIC_RATES_TBL 11
+
+#define MT792x_WATCHDOG_TIME (HZ / 4)
+
+#define MT792x_DRV_OWN_RETRY_COUNT 10
+#define MT792x_MCU_INIT_RETRY_COUNT 10
+#define MT792x_WFSYS_INIT_RETRY_COUNT 2
+
+#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
+#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
+
+#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
+#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
+
+struct mt792x_vif;
+struct mt792x_sta;
+
+struct mt792x_realease_info {
+ __le16 len;
+ u8 pad_len;
+ u8 tag;
+} __packed;
+
+struct mt792x_fw_features {
+ u8 segment;
+ u8 data;
+ u8 rsv[14];
+} __packed;
+
+enum {
+ MT792x_CLC_POWER,
+ MT792x_CLC_CHAN,
+ MT792x_CLC_MAX_NUM,
+};
+
+DECLARE_EWMA(avg_signal, 10, 8)
+
+struct mt792x_sta {
+ struct mt76_wcid wcid; /* must be first */
+
+ struct mt792x_vif *vif;
+
+ u32 airtime_ac[8];
+
+ int ack_signal;
+ struct ewma_avg_signal avg_ack_signal;
+
+ unsigned long last_txs;
+
+ struct mt76_connac_sta_key_conf bip;
+};
+
+DECLARE_EWMA(rssi, 10, 8);
+
+struct mt792x_vif {
+ struct mt76_vif mt76; /* must be first */
+
+ struct mt792x_sta sta;
+ struct mt792x_sta *wep_sta;
+
+ struct mt792x_phy *phy;
+
+ struct ewma_rssi rssi;
+
+ struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct ieee80211_chanctx_conf *ctx;
+};
+
+struct mt792x_phy {
+ struct mt76_phy *mt76;
+ struct mt792x_dev *dev;
+
+ struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
+
+ u64 omac_mask;
+
+ u16 noise;
+
+ s16 coverage_class;
+ u8 slottime;
+
+ u32 rx_ampdu_ts;
+ u32 ampdu_ref;
+
+ struct mt76_mib_stats mib;
+
+ u8 sta_work_count;
+
+ struct sk_buff_head scan_event_list;
+ struct delayed_work scan_work;
+#ifdef CONFIG_ACPI
+ void *acpisar;
+#endif
+ void *clc[MT792x_CLC_MAX_NUM];
+
+ struct work_struct roc_work;
+ struct timer_list roc_timer;
+ wait_queue_head_t roc_wait;
+ u8 roc_token_id;
+ bool roc_grant;
+};
+
+struct mt792x_irq_map {
+ u32 host_irq_enable;
+ struct {
+ u32 all_complete_mask;
+ u32 mcu_complete_mask;
+ } tx;
+ struct {
+ u32 data_complete_mask;
+ u32 wm_complete_mask;
+ u32 wm2_complete_mask;
+ } rx;
+};
+
+#define mt792x_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
+#define mt792x_dev_reset(dev) ((dev)->hif_ops->reset(dev))
+#define mt792x_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
+#define __mt792x_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev))
+#define __mt792x_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev))
+
+struct mt792x_hif_ops {
+ int (*init_reset)(struct mt792x_dev *dev);
+ int (*reset)(struct mt792x_dev *dev);
+ int (*mcu_init)(struct mt792x_dev *dev);
+ int (*drv_own)(struct mt792x_dev *dev);
+ int (*fw_own)(struct mt792x_dev *dev);
+};
+
+struct mt792x_dev {
+ union { /* must be first */
+ struct mt76_dev mt76;
+ struct mt76_phy mphy;
+ };
+
+ const struct mt76_bus_ops *bus_ops;
+ struct mt792x_phy phy;
+
+ struct work_struct reset_work;
+ bool hw_full_reset:1;
+ bool hw_init_done:1;
+ bool fw_assert:1;
+ bool has_eht:1;
+
+ struct work_struct init_work;
+
+ u8 fw_debug;
+ u8 fw_features;
+
+ struct mt76_connac_pm pm;
+ struct mt76_connac_coredump coredump;
+ const struct mt792x_hif_ops *hif_ops;
+ const struct mt792x_irq_map *irq_map;
+
+ struct work_struct ipv6_ns_work;
+ /* IPv6 addresses for WoWLAN */
+ struct sk_buff_head ipv6_ns_list;
+
+ enum environment_cap country_ie_env;
+ u32 backup_l1;
+ u32 backup_l2;
+};
+
+static inline struct mt792x_dev *
+mt792x_hw_dev(struct ieee80211_hw *hw)
+{
+ struct mt76_phy *phy = hw->priv;
+
+ return container_of(phy->dev, struct mt792x_dev, mt76);
+}
+
+static inline struct mt792x_phy *
+mt792x_hw_phy(struct ieee80211_hw *hw)
+{
+ struct mt76_phy *phy = hw->priv;
+
+ return phy->priv;
+}
+
+static inline void
+mt792x_get_status_freq_info(struct mt76_rx_status *status, u8 chfreq)
+{
+ if (chfreq > 180) {
+ status->band = NL80211_BAND_6GHZ;
+ chfreq = (chfreq - 181) * 4 + 1;
+ } else if (chfreq > 14) {
+ status->band = NL80211_BAND_5GHZ;
+ } else {
+ status->band = NL80211_BAND_2GHZ;
+ }
+ status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
+}
+
+static inline bool mt792x_dma_need_reinit(struct mt792x_dev *dev)
+{
+ return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
+}
+
+#define mt792x_mutex_acquire(dev) \
+ mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm)
+#define mt792x_mutex_release(dev) \
+ mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm)
+
+void mt792x_pm_wake_work(struct work_struct *work);
+void mt792x_pm_power_save_work(struct work_struct *work);
+void mt792x_reset(struct mt76_dev *mdev);
+void mt792x_update_channel(struct mt76_phy *mphy);
+void mt792x_mac_reset_counters(struct mt792x_phy *phy);
+void mt792x_mac_init_band(struct mt792x_dev *dev, u8 band);
+void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb);
+struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx,
+ bool unicast);
+void mt792x_mac_update_mib_stats(struct mt792x_phy *phy);
+void mt792x_mac_set_timeing(struct mt792x_phy *phy);
+void mt792x_mac_work(struct work_struct *work);
+void mt792x_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb);
+int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params);
+int mt792x_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats);
+u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u64 timestamp);
+void mt792x_tx_worker(struct mt76_worker *w);
+void mt792x_roc_timer(struct timer_list *timer);
+void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 queues, bool drop);
+int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx);
+void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx);
+void mt792x_set_wakeup(struct ieee80211_hw *hw, bool enabled);
+void mt792x_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 sset, u8 *data);
+int mt792x_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ int sset);
+void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data);
+void mt792x_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo);
+void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class);
+void mt792x_dma_cleanup(struct mt792x_dev *dev);
+int mt792x_dma_enable(struct mt792x_dev *dev);
+int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force);
+int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev);
+int mt792x_dma_disable(struct mt792x_dev *dev, bool force);
+irqreturn_t mt792x_irq_handler(int irq, void *dev_instance);
+void mt792x_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
+int mt792x_poll_tx(struct napi_struct *napi, int budget);
+int mt792x_poll_rx(struct napi_struct *napi, int budget);
+void mt792x_irq_tasklet(unsigned long data);
+int mt792x_wfsys_reset(struct mt792x_dev *dev);
+int mt792x_tx_stats_show(struct seq_file *file, void *data);
+int mt792x_queues_acq(struct seq_file *s, void *data);
+int mt792x_queues_read(struct seq_file *s, void *data);
+int mt792x_pm_stats(struct seq_file *s, void *data);
+int mt792x_pm_idle_timeout_set(void *data, u64 val);
+int mt792x_pm_idle_timeout_get(void *data, u64 *val);
+int mt792x_init_wiphy(struct ieee80211_hw *hw);
+struct ieee80211_ops *
+mt792x_get_mac80211_ops(struct device *dev,
+ const struct ieee80211_ops *mac80211_ops,
+ void *drv_data, u8 *fw_features);
+int mt792x_init_wcid(struct mt792x_dev *dev);
+int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev);
+int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev);
+
+static inline char *mt792x_ram_name(struct mt792x_dev *dev)
+{
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7922:
+ return MT7922_FIRMWARE_WM;
+ default:
+ return MT7921_FIRMWARE_WM;
+ }
+}
+
+static inline char *mt792x_patch_name(struct mt792x_dev *dev)
+{
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7922:
+ return MT7922_ROM_PATCH;
+ default:
+ return MT7921_ROM_PATCH;
+ }
+}
+
+int mt792x_load_firmware(struct mt792x_dev *dev);
+
+/* usb */
+#define MT_USB_TYPE_VENDOR (USB_TYPE_VENDOR | 0x1f)
+#define MT_USB_TYPE_UHW_VENDOR (USB_TYPE_VENDOR | 0x1e)
+int mt792xu_dma_init(struct mt792x_dev *dev, bool resume);
+int mt792xu_mcu_power_on(struct mt792x_dev *dev);
+int mt792xu_wfsys_reset(struct mt792x_dev *dev);
+int mt792xu_init_reset(struct mt792x_dev *dev);
+u32 mt792xu_rr(struct mt76_dev *dev, u32 addr);
+void mt792xu_wr(struct mt76_dev *dev, u32 addr, u32 val);
+u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val);
+void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len);
+void mt792xu_disconnect(struct usb_interface *usb_intf);
+
+int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev);
+int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev);
+int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev);
+
+#ifdef CONFIG_ACPI
+int mt792x_init_acpi_sar(struct mt792x_dev *dev);
+int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default);
+u8 mt792x_acpi_get_flags(struct mt792x_phy *phy);
+#else
+static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev)
+{
+ return 0;
+}
+
+static inline int mt792x_init_acpi_sar_power(struct mt792x_phy *phy,
+ bool set_default)
+{
+ return 0;
+}
+
+static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
+{
+ return 0;
+}
+#endif
+
+#endif /* __MT7925_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
index 48dd0decac5d..303c0f5c9c66 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/acpi_sar.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
@@ -1,15 +1,15 @@
// SPDX-License-Identifier: ISC
-/* Copyright (C) 2022 MediaTek Inc. */
+/* Copyright (C) 2023 MediaTek Inc. */
#include <linux/acpi.h>
-#include "mt7921.h"
+#include "mt792x.h"
static int
-mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
+mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *sar_root, *sar_unit;
struct mt76_dev *mdev = &dev->mt76;
+ union acpi_object *sar_root;
acpi_handle root, handle;
acpi_status status;
u32 i = 0;
@@ -45,18 +45,20 @@ mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
goto free;
}
}
+
if (len)
*len = sar_root->package.count;
for (i = 0; i < sar_root->package.count; i++) {
- sar_unit = &sar_root->package.elements[i];
+ union acpi_object *sar_unit = &sar_root->package.elements[i];
if (sar_unit->type != ACPI_TYPE_INTEGER)
break;
+
*(*tbl + i) = (u8)sar_unit->integer.value;
}
- ret = (i == sar_root->package.count) ? 0 : -EINVAL;
+ ret = i == sar_root->package.count ? 0 : -EINVAL;
free:
kfree(sar_root);
@@ -64,36 +66,37 @@ free:
}
/* MTCL : Country List Table for 6G band */
-static int
-mt7921_asar_acpi_read_mtcl(struct mt7921_dev *dev, u8 **table, u8 *version)
+static void
+mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version)
{
- *version = (mt7921_acpi_read(dev, MT7921_ACPI_MTCL, table, NULL) < 0)
- ? 1 : 2;
- return 0;
+ if (mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL) < 0)
+ *version = 1;
+ else
+ *version = 2;
}
/* MTDS : Dynamic SAR Power Table */
static int
-mt7921_asar_acpi_read_mtds(struct mt7921_dev *dev, u8 **table, u8 version)
+mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version)
{
int len, ret, sarlen, prelen, tblcnt;
bool enable;
- ret = mt7921_acpi_read(dev, MT7921_ACPI_MTDS, table, &len);
+ ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len);
if (ret)
return ret;
/* Table content validation */
switch (version) {
case 1:
- enable = ((struct mt7921_asar_dyn *)*table)->enable;
- sarlen = sizeof(struct mt7921_asar_dyn_limit);
- prelen = sizeof(struct mt7921_asar_dyn);
+ enable = ((struct mt792x_asar_dyn *)*table)->enable;
+ sarlen = sizeof(struct mt792x_asar_dyn_limit);
+ prelen = sizeof(struct mt792x_asar_dyn);
break;
case 2:
- enable = ((struct mt7921_asar_dyn_v2 *)*table)->enable;
- sarlen = sizeof(struct mt7921_asar_dyn_limit_v2);
- prelen = sizeof(struct mt7921_asar_dyn_v2);
+ enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable;
+ sarlen = sizeof(struct mt792x_asar_dyn_limit_v2);
+ prelen = sizeof(struct mt792x_asar_dyn_v2);
break;
default:
return -EINVAL;
@@ -101,88 +104,89 @@ mt7921_asar_acpi_read_mtds(struct mt7921_dev *dev, u8 **table, u8 version)
tblcnt = (len - prelen) / sarlen;
if (!enable ||
- tblcnt > MT7921_ASAR_MAX_DYN || tblcnt < MT7921_ASAR_MIN_DYN)
- ret = -EINVAL;
+ tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN)
+ return -EINVAL;
- return ret;
+ return 0;
}
/* MTGS : Geo SAR Power Table */
static int
-mt7921_asar_acpi_read_mtgs(struct mt7921_dev *dev, u8 **table, u8 version)
+mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version)
{
- int len, ret = 0, sarlen, prelen, tblcnt;
+ int len, ret, sarlen, prelen, tblcnt;
- ret = mt7921_acpi_read(dev, MT7921_ACPI_MTGS, table, &len);
+ ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len);
if (ret)
return ret;
/* Table content validation */
switch (version) {
case 1:
- sarlen = sizeof(struct mt7921_asar_geo_limit);
- prelen = sizeof(struct mt7921_asar_geo);
+ sarlen = sizeof(struct mt792x_asar_geo_limit);
+ prelen = sizeof(struct mt792x_asar_geo);
break;
case 2:
- sarlen = sizeof(struct mt7921_asar_geo_limit_v2);
- prelen = sizeof(struct mt7921_asar_geo_v2);
+ sarlen = sizeof(struct mt792x_asar_geo_limit_v2);
+ prelen = sizeof(struct mt792x_asar_geo_v2);
break;
default:
return -EINVAL;
}
tblcnt = (len - prelen) / sarlen;
- if (tblcnt > MT7921_ASAR_MAX_GEO || tblcnt < MT7921_ASAR_MIN_GEO)
- ret = -EINVAL;
+ if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO)
+ return -EINVAL;
- return ret;
+ return 0;
}
/* MTFG : Flag Table */
static int
-mt7921_asar_acpi_read_mtfg(struct mt7921_dev *dev, u8 **table)
+mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table)
{
int len, ret;
- ret = mt7921_acpi_read(dev, MT7921_ACPI_MTFG, table, &len);
+ ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len);
if (ret)
return ret;
- if (len < MT7921_ASAR_MIN_FG)
- ret = -EINVAL;
+ if (len < MT792x_ASAR_MIN_FG)
+ return -EINVAL;
- return ret;
+ return 0;
}
-int mt7921_init_acpi_sar(struct mt7921_dev *dev)
+int mt792x_init_acpi_sar(struct mt792x_dev *dev)
{
- struct mt7921_acpi_sar *asar;
+ struct mt792x_acpi_sar *asar;
int ret;
asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL);
if (!asar)
return -ENOMEM;
- mt7921_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
+ mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver);
/* MTDS is mandatory. Return error if table is invalid */
- ret = mt7921_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
+ ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
if (ret) {
devm_kfree(dev->mt76.dev, asar->dyn);
devm_kfree(dev->mt76.dev, asar->countrylist);
devm_kfree(dev->mt76.dev, asar);
+
return ret;
}
/* MTGS is optional */
- ret = mt7921_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
+ ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
if (ret) {
devm_kfree(dev->mt76.dev, asar->geo);
asar->geo = NULL;
}
/* MTFG is optional */
- ret = mt7921_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg);
+ ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg);
if (ret) {
devm_kfree(dev->mt76.dev, asar->fg);
asar->fg = NULL;
@@ -191,13 +195,14 @@ int mt7921_init_acpi_sar(struct mt7921_dev *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar);
static s8
-mt7921_asar_get_geo_pwr(struct mt7921_phy *phy,
+mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,
enum nl80211_band band, s8 dyn_power)
{
- struct mt7921_acpi_sar *asar = phy->acpisar;
- struct mt7921_asar_geo_band *band_pwr;
+ struct mt792x_acpi_sar *asar = phy->acpisar;
+ struct mt792x_asar_geo_band *band_pwr;
s8 geo_power;
u8 idx, max;
@@ -248,12 +253,12 @@ mt7921_asar_get_geo_pwr(struct mt7921_phy *phy,
}
static s8
-mt7921_asar_range_pwr(struct mt7921_phy *phy,
+mt792x_asar_range_pwr(struct mt792x_phy *phy,
const struct cfg80211_sar_freq_ranges *range,
u8 idx)
{
const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
- struct mt7921_acpi_sar *asar = phy->acpisar;
+ struct mt792x_acpi_sar *asar = phy->acpisar;
u8 *limit, band, max;
if (!capa)
@@ -277,10 +282,10 @@ mt7921_asar_range_pwr(struct mt7921_phy *phy,
else
band = NL80211_BAND_2GHZ;
- return mt7921_asar_get_geo_pwr(phy, band, limit[idx]);
+ return mt792x_asar_get_geo_pwr(phy, band, limit[idx]);
}
-int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default)
+int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default)
{
const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa;
int i;
@@ -300,41 +305,46 @@ int mt7921_init_acpi_sar_power(struct mt7921_phy *phy, bool set_default)
continue;
frp->power = min_t(s8, set_default ? 127 : frp->power,
- mt7921_asar_range_pwr(phy, frp->range, i));
+ mt792x_asar_range_pwr(phy, frp->range, i));
}
return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power);
-u8 mt7921_acpi_get_flags(struct mt7921_phy *phy)
+u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
{
- struct mt7921_asar_fg *fg;
+ struct mt792x_acpi_sar *acpisar = phy->acpisar;
+ struct mt792x_asar_fg *fg;
struct {
u8 acpi_idx;
u8 chip_idx;
} map[] = {
- {1, 1},
- {4, 2},
+ { 1, 1 },
+ { 4, 2 },
};
u8 flags = BIT(0);
int i, j;
- if (!phy->acpisar)
+ if (!acpisar)
return 0;
- fg = phy->acpisar->fg;
+ fg = acpisar->fg;
if (!fg)
return flags;
/* pickup necessary settings per device and
* translate the index of bitmap for chip command.
*/
- for (i = 0; i < fg->nr_flag; i++)
- for (j = 0; j < ARRAY_SIZE(map); j++)
+ for (i = 0; i < fg->nr_flag; i++) {
+ for (j = 0; j < ARRAY_SIZE(map); j++) {
if (fg->flag[i] == map[j].acpi_idx) {
flags |= BIT(map[j].chip_idx);
break;
}
+ }
+ }
return flags;
}
+EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
new file mode 100644
index 000000000000..d6d332e863ba
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#ifndef __MT7921_ACPI_SAR_H
+#define __MT7921_ACPI_SAR_H
+
+#define MT792x_ASAR_MIN_DYN 1
+#define MT792x_ASAR_MAX_DYN 8
+#define MT792x_ASAR_MIN_GEO 3
+#define MT792x_ASAR_MAX_GEO 8
+#define MT792x_ASAR_MIN_FG 8
+
+#define MT792x_ACPI_MTCL "MTCL"
+#define MT792x_ACPI_MTDS "MTDS"
+#define MT792x_ACPI_MTGS "MTGS"
+#define MT792x_ACPI_MTFG "MTFG"
+
+struct mt792x_asar_dyn_limit {
+ u8 idx;
+ u8 frp[5];
+} __packed;
+
+struct mt792x_asar_dyn {
+ u8 names[4];
+ u8 enable;
+ u8 nr_tbl;
+ DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit, tbl);
+} __packed;
+
+struct mt792x_asar_dyn_limit_v2 {
+ u8 idx;
+ u8 frp[11];
+} __packed;
+
+struct mt792x_asar_dyn_v2 {
+ u8 names[4];
+ u8 enable;
+ u8 rsvd;
+ u8 nr_tbl;
+ DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit_v2, tbl);
+} __packed;
+
+struct mt792x_asar_geo_band {
+ u8 pwr;
+ u8 offset;
+} __packed;
+
+struct mt792x_asar_geo_limit {
+ u8 idx;
+ /* 0:2G, 1:5G */
+ struct mt792x_asar_geo_band band[2];
+} __packed;
+
+struct mt792x_asar_geo {
+ u8 names[4];
+ u8 version;
+ u8 nr_tbl;
+ DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit, tbl);
+} __packed;
+
+struct mt792x_asar_geo_limit_v2 {
+ u8 idx;
+ /* 0:2G, 1:5G, 2:6G */
+ struct mt792x_asar_geo_band band[3];
+} __packed;
+
+struct mt792x_asar_geo_v2 {
+ u8 names[4];
+ u8 version;
+ u8 rsvd;
+ u8 nr_tbl;
+ DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit_v2, tbl);
+} __packed;
+
+struct mt792x_asar_cl {
+ u8 names[4];
+ u8 version;
+ u8 mode_6g;
+ u8 cl6g[6];
+} __packed;
+
+struct mt792x_asar_fg {
+ u8 names[4];
+ u8 version;
+ u8 rsvd;
+ u8 nr_flag;
+ u8 rsvd1;
+ u8 flag[];
+} __packed;
+
+struct mt792x_acpi_sar {
+ u8 ver;
+ union {
+ struct mt792x_asar_dyn *dyn;
+ struct mt792x_asar_dyn_v2 *dyn_v2;
+ };
+ union {
+ struct mt792x_asar_geo *geo;
+ struct mt792x_asar_geo_v2 *geo_v2;
+ };
+ struct mt792x_asar_cl *countrylist;
+ struct mt792x_asar_fg *fg;
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
new file mode 100644
index 000000000000..46be7f996c7e
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -0,0 +1,844 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+
+#include "mt792x.h"
+#include "dma.h"
+
+static const struct ieee80211_iface_limit if_limits[] = {
+ {
+ .max = MT792x_MAX_INTERFACES,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP)
+ }
+};
+
+static const struct ieee80211_iface_combination if_comb[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = MT792x_MAX_INTERFACES,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ },
+};
+
+static const struct ieee80211_iface_limit if_limits_chanctx[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT)
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO)
+ }
+};
+
+static const struct ieee80211_iface_combination if_comb_chanctx[] = {
+ {
+ .limits = if_limits_chanctx,
+ .n_limits = ARRAY_SIZE(if_limits_chanctx),
+ .max_interfaces = 2,
+ .num_different_channels = 2,
+ .beacon_int_infra_match = false,
+ }
+};
+
+void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+{
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_phy *mphy = hw->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_vif *vif = info->control.vif;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ int qid;
+
+ if (control->sta) {
+ struct mt792x_sta *sta;
+
+ sta = (struct mt792x_sta *)control->sta->drv_priv;
+ wcid = &sta->wcid;
+ }
+
+ if (vif && !control->sta) {
+ struct mt792x_vif *mvif;
+
+ mvif = (struct mt792x_vif *)vif->drv_priv;
+ wcid = &mvif->sta.wcid;
+ }
+
+ if (mt76_connac_pm_ref(mphy, &dev->pm)) {
+ mt76_tx(mphy, control->sta, wcid, skb);
+ mt76_connac_pm_unref(mphy, &dev->pm);
+ return;
+ }
+
+ qid = skb_get_queue_mapping(skb);
+ if (qid >= MT_TXQ_PSD) {
+ qid = IEEE80211_AC_BE;
+ skb_set_queue_mapping(skb, qid);
+ }
+
+ mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb);
+}
+EXPORT_SYMBOL_GPL(mt792x_tx);
+
+void mt792x_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_sta *msta = &mvif->sta;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ int idx = msta->wcid.idx;
+
+ mt792x_mutex_acquire(dev);
+ mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
+ mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false);
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+ dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
+ phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
+ mt792x_mutex_release(dev);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+ mt76_packet_id_flush(&dev->mt76, &msta->wcid);
+}
+EXPORT_SYMBOL_GPL(mt792x_remove_interface);
+
+int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+
+ /* no need to update right away, we'll get BSS_CHANGED_QOS */
+ queue = mt76_connac_lmac_mapping(queue);
+ mvif->queue_params[queue] = *params;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_conf_tx);
+
+int mt792x_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt76_mib_stats *mib = &phy->mib;
+
+ mt792x_mutex_acquire(phy->dev);
+
+ stats->dot11RTSSuccessCount = mib->rts_cnt;
+ stats->dot11RTSFailureCount = mib->rts_retries_cnt;
+ stats->dot11FCSErrorCount = mib->fcs_err_cnt;
+ stats->dot11ACKFailureCount = mib->ack_fail_cnt;
+
+ mt792x_mutex_release(phy->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_get_stats);
+
+u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ u8 omac_idx = mvif->mt76.omac_idx;
+ union {
+ u64 t64;
+ u32 t32[2];
+ } tsf;
+ u16 n;
+
+ mt792x_mutex_acquire(dev);
+
+ n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx;
+ /* TSF software read */
+ mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_MODE);
+ tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(0));
+ tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(0));
+
+ mt792x_mutex_release(dev);
+
+ return tsf.t64;
+}
+EXPORT_SYMBOL_GPL(mt792x_get_tsf);
+
+void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u64 timestamp)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ u8 omac_idx = mvif->mt76.omac_idx;
+ union {
+ u64 t64;
+ u32 t32[2];
+ } tsf = { .t64 = timestamp, };
+ u16 n;
+
+ mt792x_mutex_acquire(dev);
+
+ n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(0), tsf.t32[0]);
+ mt76_wr(dev, MT_LPON_UTTR1(0), tsf.t32[1]);
+ /* TSF software overwrite */
+ mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_WRITE);
+
+ mt792x_mutex_release(dev);
+}
+EXPORT_SYMBOL_GPL(mt792x_set_tsf);
+
+void mt792x_tx_worker(struct mt76_worker *w)
+{
+ struct mt792x_dev *dev = container_of(w, struct mt792x_dev,
+ mt76.tx_worker);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return;
+ }
+
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+}
+EXPORT_SYMBOL_GPL(mt792x_tx_worker);
+
+void mt792x_roc_timer(struct timer_list *timer)
+{
+ struct mt792x_phy *phy = from_timer(phy, timer, roc_timer);
+
+ ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
+}
+EXPORT_SYMBOL_GPL(mt792x_roc_timer);
+
+void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 queues, bool drop)
+{
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+
+ wait_event_timeout(dev->mt76.tx_wait,
+ !mt76_has_tx_pending(&dev->mphy), HZ / 2);
+}
+EXPORT_SYMBOL_GPL(mt792x_flush);
+
+int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mvif->ctx = ctx;
+ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_assign_vif_chanctx);
+
+void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mvif->ctx = NULL;
+ mutex_unlock(&dev->mt76.mutex);
+}
+EXPORT_SYMBOL_GPL(mt792x_unassign_vif_chanctx);
+
+void mt792x_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_dev *mdev = &dev->mt76;
+
+ device_set_wakeup_enable(mdev->dev, enabled);
+}
+EXPORT_SYMBOL_GPL(mt792x_set_wakeup);
+
+static const char mt792x_gstrings_stats[][ETH_GSTRING_LEN] = {
+ /* tx counters */
+ "tx_ampdu_cnt",
+ "tx_mpdu_attempts",
+ "tx_mpdu_success",
+ "tx_pkt_ebf_cnt",
+ "tx_pkt_ibf_cnt",
+ "tx_ampdu_len:0-1",
+ "tx_ampdu_len:2-10",
+ "tx_ampdu_len:11-19",
+ "tx_ampdu_len:20-28",
+ "tx_ampdu_len:29-37",
+ "tx_ampdu_len:38-46",
+ "tx_ampdu_len:47-55",
+ "tx_ampdu_len:56-79",
+ "tx_ampdu_len:80-103",
+ "tx_ampdu_len:104-127",
+ "tx_ampdu_len:128-151",
+ "tx_ampdu_len:152-175",
+ "tx_ampdu_len:176-199",
+ "tx_ampdu_len:200-223",
+ "tx_ampdu_len:224-247",
+ "ba_miss_count",
+ "tx_beamformer_ppdu_iBF",
+ "tx_beamformer_ppdu_eBF",
+ "tx_beamformer_rx_feedback_all",
+ "tx_beamformer_rx_feedback_he",
+ "tx_beamformer_rx_feedback_vht",
+ "tx_beamformer_rx_feedback_ht",
+ "tx_msdu_pack_1",
+ "tx_msdu_pack_2",
+ "tx_msdu_pack_3",
+ "tx_msdu_pack_4",
+ "tx_msdu_pack_5",
+ "tx_msdu_pack_6",
+ "tx_msdu_pack_7",
+ "tx_msdu_pack_8",
+ /* rx counters */
+ "rx_mpdu_cnt",
+ "rx_ampdu_cnt",
+ "rx_ampdu_bytes_cnt",
+ "rx_ba_cnt",
+ /* per vif counters */
+ "v_tx_mode_cck",
+ "v_tx_mode_ofdm",
+ "v_tx_mode_ht",
+ "v_tx_mode_ht_gf",
+ "v_tx_mode_vht",
+ "v_tx_mode_he_su",
+ "v_tx_mode_he_ext_su",
+ "v_tx_mode_he_tb",
+ "v_tx_mode_he_mu",
+ "v_tx_mode_eht_su",
+ "v_tx_mode_eht_trig",
+ "v_tx_mode_eht_mu",
+ "v_tx_bw_20",
+ "v_tx_bw_40",
+ "v_tx_bw_80",
+ "v_tx_bw_160",
+ "v_tx_mcs_0",
+ "v_tx_mcs_1",
+ "v_tx_mcs_2",
+ "v_tx_mcs_3",
+ "v_tx_mcs_4",
+ "v_tx_mcs_5",
+ "v_tx_mcs_6",
+ "v_tx_mcs_7",
+ "v_tx_mcs_8",
+ "v_tx_mcs_9",
+ "v_tx_mcs_10",
+ "v_tx_mcs_11",
+ "v_tx_mcs_12",
+ "v_tx_mcs_13",
+ "v_tx_nss_1",
+ "v_tx_nss_2",
+ "v_tx_nss_3",
+ "v_tx_nss_4",
+};
+
+void mt792x_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 sset, u8 *data)
+{
+ if (sset != ETH_SS_STATS)
+ return;
+
+ memcpy(data, *mt792x_gstrings_stats, sizeof(mt792x_gstrings_stats));
+
+ data += sizeof(mt792x_gstrings_stats);
+ page_pool_ethtool_stats_get_strings(data);
+}
+EXPORT_SYMBOL_GPL(mt792x_get_et_strings);
+
+int mt792x_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ int sset)
+{
+ if (sset != ETH_SS_STATS)
+ return 0;
+
+ return ARRAY_SIZE(mt792x_gstrings_stats) +
+ page_pool_ethtool_stats_get_count();
+}
+EXPORT_SYMBOL_GPL(mt792x_get_et_sset_count);
+
+static void
+mt792x_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+{
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct mt76_ethtool_worker_info *wi = wi_data;
+
+ if (msta->vif->mt76.idx != wi->idx)
+ return;
+
+ mt76_ethtool_worker(wi, &msta->wcid.stats, true);
+}
+
+void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ int stats_size = ARRAY_SIZE(mt792x_gstrings_stats);
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = phy->dev;
+ struct mt76_mib_stats *mib = &phy->mib;
+ struct mt76_ethtool_worker_info wi = {
+ .data = data,
+ .idx = mvif->mt76.idx,
+ };
+ int i, ei = 0;
+
+ mt792x_mutex_acquire(dev);
+
+ mt792x_mac_update_mib_stats(phy);
+
+ data[ei++] = mib->tx_ampdu_cnt;
+ data[ei++] = mib->tx_mpdu_attempts_cnt;
+ data[ei++] = mib->tx_mpdu_success_cnt;
+ data[ei++] = mib->tx_pkt_ebf_cnt;
+ data[ei++] = mib->tx_pkt_ibf_cnt;
+
+ /* Tx ampdu stat */
+ for (i = 0; i < 15; i++)
+ data[ei++] = phy->mt76->aggr_stats[i];
+
+ data[ei++] = phy->mib.ba_miss_cnt;
+
+ /* Tx Beamformer monitor */
+ data[ei++] = mib->tx_bf_ibf_ppdu_cnt;
+ data[ei++] = mib->tx_bf_ebf_ppdu_cnt;
+
+ /* Tx Beamformer Rx feedback monitor */
+ data[ei++] = mib->tx_bf_rx_fb_all_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_he_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_vht_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_ht_cnt;
+
+ /* Tx amsdu info (pack-count histogram) */
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++)
+ data[ei++] = mib->tx_amsdu[i];
+
+ /* rx counters */
+ data[ei++] = mib->rx_mpdu_cnt;
+ data[ei++] = mib->rx_ampdu_cnt;
+ data[ei++] = mib->rx_ampdu_bytes_cnt;
+ data[ei++] = mib->rx_ba_cnt;
+
+ /* Add values for all stations owned by this vif */
+ wi.initial_stat_idx = ei;
+ ieee80211_iterate_stations_atomic(hw, mt792x_ethtool_worker, &wi);
+
+ mt792x_mutex_release(dev);
+
+ if (!wi.sta_count)
+ return;
+
+ ei += wi.worker_stat_count;
+
+ mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
+ stats_size += page_pool_ethtool_stats_get_count();
+
+ if (ei != stats_size)
+ dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %d", ei,
+ stats_size);
+}
+EXPORT_SYMBOL_GPL(mt792x_get_et_stats);
+
+void mt792x_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
+{
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct rate_info *txrate = &msta->wcid.rate;
+
+ if (!txrate->legacy && !txrate->flags)
+ return;
+
+ if (txrate->legacy) {
+ sinfo->txrate.legacy = txrate->legacy;
+ } else {
+ sinfo->txrate.mcs = txrate->mcs;
+ sinfo->txrate.nss = txrate->nss;
+ sinfo->txrate.bw = txrate->bw;
+ sinfo->txrate.he_gi = txrate->he_gi;
+ sinfo->txrate.he_dcm = txrate->he_dcm;
+ sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ }
+ sinfo->tx_failed = msta->wcid.stats.tx_failed;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+
+ sinfo->tx_retries = msta->wcid.stats.tx_retries;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+
+ sinfo->txrate.flags = txrate->flags;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+ sinfo->ack_signal = (s8)msta->ack_signal;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
+
+ sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal);
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
+}
+EXPORT_SYMBOL_GPL(mt792x_sta_statistics);
+
+void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
+{
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = phy->dev;
+
+ mt792x_mutex_acquire(dev);
+
+ phy->coverage_class = max_t(s16, coverage_class, 0);
+ mt792x_mac_set_timeing(phy);
+
+ mt792x_mutex_release(dev);
+}
+EXPORT_SYMBOL_GPL(mt792x_set_coverage_class);
+
+int mt792x_init_wiphy(struct ieee80211_hw *hw)
+{
+ struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ struct mt792x_dev *dev = phy->dev;
+ struct wiphy *wiphy = hw->wiphy;
+
+ hw->queues = 4;
+ if (dev->has_eht) {
+ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT;
+ hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT;
+ } else {
+ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
+ hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
+ }
+ hw->netdev_features = NETIF_F_RXCSUM;
+
+ hw->radiotap_timestamp.units_pos =
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
+
+ phy->slottime = 9;
+
+ hw->sta_data_size = sizeof(struct mt792x_sta);
+ hw->vif_data_size = sizeof(struct mt792x_vif);
+
+ if (dev->fw_features & MT792x_FW_CAP_CNM) {
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wiphy->iface_combinations = if_comb_chanctx;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx);
+ } else {
+ wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wiphy->iface_combinations = if_comb;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ }
+ wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP |
+ WIPHY_FLAG_4ADDR_STATION);
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ wiphy->max_remain_on_channel_duration = 5000;
+ wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
+ wiphy->max_scan_ssids = 4;
+ wiphy->max_sched_scan_plan_interval =
+ MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL;
+ wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID;
+ wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH;
+ wiphy->max_sched_scan_reqs = 1;
+ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
+ WIPHY_FLAG_SPLIT_SCAN_6GHZ;
+
+ wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+
+ ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+
+ if (dev->pm.enable)
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+
+ hw->max_tx_fragments = 4;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_init_wiphy);
+
+static u8
+mt792x_get_offload_capability(struct device *dev, const char *fw_wm)
+{
+ const struct mt76_connac2_fw_trailer *hdr;
+ struct mt792x_realease_info *rel_info;
+ const struct firmware *fw;
+ int ret, i, offset = 0;
+ const u8 *data, *end;
+ u8 offload_caps = 0;
+
+ ret = request_firmware(&fw, fw_wm, dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+ dev_err(dev, "Invalid firmware\n");
+ goto out;
+ }
+
+ data = fw->data;
+ hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
+
+ for (i = 0; i < hdr->n_region; i++) {
+ const struct mt76_connac2_fw_region *region;
+
+ region = (const void *)((const u8 *)hdr -
+ (hdr->n_region - i) * sizeof(*region));
+ offset += le32_to_cpu(region->len);
+ }
+
+ data += offset + 16;
+ rel_info = (struct mt792x_realease_info *)data;
+ data += sizeof(*rel_info);
+ end = data + le16_to_cpu(rel_info->len);
+
+ while (data < end) {
+ rel_info = (struct mt792x_realease_info *)data;
+ data += sizeof(*rel_info);
+
+ if (rel_info->tag == MT792x_FW_TAG_FEATURE) {
+ struct mt792x_fw_features *features;
+
+ features = (struct mt792x_fw_features *)data;
+ offload_caps = features->data;
+ break;
+ }
+
+ data += le16_to_cpu(rel_info->len) + rel_info->pad_len;
+ }
+
+out:
+ release_firmware(fw);
+
+ return offload_caps;
+}
+
+struct ieee80211_ops *
+mt792x_get_mac80211_ops(struct device *dev,
+ const struct ieee80211_ops *mac80211_ops,
+ void *drv_data, u8 *fw_features)
+{
+ struct ieee80211_ops *ops;
+
+ ops = devm_kmemdup(dev, mac80211_ops, sizeof(struct ieee80211_ops),
+ GFP_KERNEL);
+ if (!ops)
+ return NULL;
+
+ *fw_features = mt792x_get_offload_capability(dev, drv_data);
+ if (!(*fw_features & MT792x_FW_CAP_CNM)) {
+ ops->remain_on_channel = NULL;
+ ops->cancel_remain_on_channel = NULL;
+ ops->add_chanctx = NULL;
+ ops->remove_chanctx = NULL;
+ ops->change_chanctx = NULL;
+ ops->assign_vif_chanctx = NULL;
+ ops->unassign_vif_chanctx = NULL;
+ ops->mgd_prepare_tx = NULL;
+ ops->mgd_complete_tx = NULL;
+ }
+ return ops;
+}
+EXPORT_SYMBOL_GPL(mt792x_get_mac80211_ops);
+
+int mt792x_init_wcid(struct mt792x_dev *dev)
+{
+ int idx;
+
+ /* Beacon and mgmt frames should occupy wcid 0 */
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
+ if (idx)
+ return -ENOSPC;
+
+ dev->mt76.global_wcid.idx = idx;
+ dev->mt76.global_wcid.hw_key_idx = -1;
+ dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
+ rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_init_wcid);
+
+int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err = 0;
+
+ mutex_lock(&pm->mutex);
+
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
+ goto out;
+
+ err = __mt792x_mcu_drv_pmctrl(dev);
+out:
+ mutex_unlock(&pm->mutex);
+
+ if (err)
+ mt792x_reset(&dev->mt76);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mt792x_mcu_drv_pmctrl);
+
+int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err = 0;
+
+ mutex_lock(&pm->mutex);
+
+ if (mt76_connac_skip_fw_pmctrl(mphy, pm))
+ goto out;
+
+ err = __mt792x_mcu_fw_pmctrl(dev);
+out:
+ mutex_unlock(&pm->mutex);
+
+ if (err)
+ mt792x_reset(&dev->mt76);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(mt792x_mcu_fw_pmctrl);
+
+int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev)
+{
+ int i, err = 0;
+
+ for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) {
+ mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
+ if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
+ PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1))
+ break;
+ }
+
+ if (i == MT792x_DRV_OWN_RETRY_COUNT) {
+ dev_err(dev->mt76.dev, "driver own failed\n");
+ err = -EIO;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(__mt792xe_mcu_drv_pmctrl);
+
+int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err;
+
+ err = __mt792xe_mcu_drv_pmctrl(dev);
+ if (err < 0)
+ goto out;
+
+ mt792x_wpdma_reinit_cond(dev);
+ clear_bit(MT76_STATE_PM, &mphy->state);
+
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mt792xe_mcu_drv_pmctrl);
+
+int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i;
+
+ for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) {
+ mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
+ if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
+ PCIE_LPCR_HOST_OWN_SYNC, 4, 50, 1))
+ break;
+ }
+
+ if (i == MT792x_DRV_OWN_RETRY_COUNT) {
+ dev_err(dev->mt76.dev, "firmware own failed\n");
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ return -EIO;
+ }
+
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792xe_mcu_fw_pmctrl);
+
+int mt792x_load_firmware(struct mt792x_dev *dev)
+{
+ int ret;
+
+ ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev));
+ if (ret)
+ return ret;
+
+ if (mt76_is_sdio(&dev->mt76)) {
+ /* activate again */
+ ret = __mt792x_mcu_fw_pmctrl(dev);
+ if (!ret)
+ ret = __mt792x_mcu_drv_pmctrl(dev);
+ }
+
+ ret = mt76_connac2_load_ram(&dev->mt76, mt792x_ram_name(dev), NULL);
+ if (ret)
+ return ret;
+
+ if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
+ MT_TOP_MISC2_FW_N9_RDY, 1500)) {
+ dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
+
+ return -EIO;
+ }
+
+#ifdef CONFIG_PM
+ dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
+#endif /* CONFIG_PM */
+
+ dev_dbg(dev->mt76.dev, "Firmware init done\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_load_firmware);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt792x_debugfs.c
new file mode 100644
index 000000000000..9858d9a93851
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_debugfs.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include "mt792x.h"
+
+static void
+mt792x_ampdu_stat_read_phy(struct mt792x_phy *phy,
+ struct seq_file *file)
+{
+ struct mt792x_dev *dev = file->private;
+ int bound[15], range[4], i;
+
+ if (!phy)
+ return;
+
+ mt792x_mac_update_mib_stats(phy);
+
+ /* Tx ampdu stat */
+ for (i = 0; i < ARRAY_SIZE(range); i++)
+ range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
+
+ for (i = 0; i < ARRAY_SIZE(bound); i++)
+ bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
+
+ seq_puts(file, "\nPhy0\n");
+
+ seq_printf(file, "Length: %8d | ", bound[0]);
+ for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
+ seq_printf(file, "%3d %3d | ", bound[i] + 1, bound[i + 1]);
+
+ seq_puts(file, "\nCount: ");
+ for (i = 0; i < ARRAY_SIZE(bound); i++)
+ seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]);
+ seq_puts(file, "\n");
+
+ seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
+}
+
+int mt792x_tx_stats_show(struct seq_file *file, void *data)
+{
+ struct mt792x_dev *dev = file->private;
+ struct mt792x_phy *phy = &dev->phy;
+ struct mt76_mib_stats *mib = &phy->mib;
+ int i;
+
+ mt792x_mutex_acquire(dev);
+
+ mt792x_ampdu_stat_read_phy(phy, file);
+
+ seq_puts(file, "Tx MSDU stat:\n");
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
+ seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
+ i + 1, mib->tx_amsdu[i]);
+ if (mib->tx_amsdu_cnt)
+ seq_printf(file, "(%3d%%)\n",
+ mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
+ else
+ seq_puts(file, "\n");
+ }
+
+ mt792x_mutex_release(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_tx_stats_show);
+
+int mt792x_queues_acq(struct seq_file *s, void *data)
+{
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ int i;
+
+ mt792x_mutex_acquire(dev);
+
+ for (i = 0; i < 4; i++) {
+ u32 ctrl, val, qlen = 0;
+ int j;
+
+ val = mt76_rr(dev, MT_PLE_AC_QEMPTY(i));
+ ctrl = BIT(31) | BIT(11) | (i << 24);
+
+ for (j = 0; j < 32; j++) {
+ if (val & BIT(j))
+ continue;
+
+ mt76_wr(dev, MT_PLE_FL_Q0_CTRL, ctrl | j);
+ qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
+ GENMASK(11, 0));
+ }
+ seq_printf(s, "AC%d: queued=%d\n", i, qlen);
+ }
+
+ mt792x_mutex_release(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_queues_acq);
+
+int mt792x_queues_read(struct seq_file *s, void *data)
+{
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ struct {
+ struct mt76_queue *q;
+ char *queue;
+ } queue_map[] = {
+ { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
+ { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" },
+ { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
+ struct mt76_queue *q = queue_map[i].q;
+
+ if (!q)
+ continue;
+
+ seq_printf(s,
+ "%s: queued=%d head=%d tail=%d\n",
+ queue_map[i].queue, q->queued, q->head,
+ q->tail);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_queues_read);
+
+int mt792x_pm_stats(struct seq_file *s, void *data)
+{
+ struct mt792x_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_connac_pm *pm = &dev->pm;
+
+ unsigned long awake_time = pm->stats.awake_time;
+ unsigned long doze_time = pm->stats.doze_time;
+
+ if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
+ awake_time += jiffies - pm->stats.last_wake_event;
+ else
+ doze_time += jiffies - pm->stats.last_doze_event;
+
+ seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
+ jiffies_to_msecs(awake_time),
+ jiffies_to_msecs(doze_time));
+
+ seq_printf(s, "low power wakes: %9d\n", pm->stats.lp_wake);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_pm_stats);
+
+int mt792x_pm_idle_timeout_set(void *data, u64 val)
+{
+ struct mt792x_dev *dev = data;
+
+ dev->pm.idle_timeout = msecs_to_jiffies(val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_pm_idle_timeout_set);
+
+int mt792x_pm_idle_timeout_get(void *data, u64 *val)
+{
+ struct mt792x_dev *dev = data;
+
+ *val = jiffies_to_msecs(dev->pm.idle_timeout);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_pm_idle_timeout_get);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
index 4153cd6c2a01..a3dbd3865b2f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
@@ -1,52 +1,93 @@
// SPDX-License-Identifier: ISC
-/* Copyright (C) 2020 MediaTek Inc. */
+/* Copyright (C) 2023 MediaTek Inc. */
-#include "mt7921.h"
-#include "../dma.h"
-#include "../mt76_connac2_mac.h"
+#include <linux/module.h>
+#include <linux/firmware.h>
-static int mt7921_poll_tx(struct napi_struct *napi, int budget)
+#include "mt792x.h"
+#include "dma.h"
+#include "trace.h"
+
+irqreturn_t mt792x_irq_handler(int irq, void *dev_instance)
{
- struct mt7921_dev *dev;
+ struct mt792x_dev *dev = dev_instance;
- dev = container_of(napi, struct mt7921_dev, mt76.tx_napi);
+ mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
- if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
- napi_complete(napi);
- queue_work(dev->mt76.wq, &dev->pm.wake_work);
- return 0;
- }
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
+ return IRQ_NONE;
- mt76_connac_tx_cleanup(&dev->mt76);
- if (napi_complete(napi))
- mt76_connac_irq_enable(&dev->mt76, MT_INT_TX_DONE_ALL);
- mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+ tasklet_schedule(&dev->mt76.irq_tasklet);
- return 0;
+ return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(mt792x_irq_handler);
-static int mt7921_poll_rx(struct napi_struct *napi, int budget)
+void mt792x_irq_tasklet(unsigned long data)
{
- struct mt7921_dev *dev;
- int done;
+ struct mt792x_dev *dev = (struct mt792x_dev *)data;
+ const struct mt792x_irq_map *irq_map = dev->irq_map;
+ u32 intr, mask = 0;
- dev = container_of(napi->dev, struct mt7921_dev, mt76.napi_dev);
+ mt76_wr(dev, irq_map->host_irq_enable, 0);
- if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
- napi_complete(napi);
- queue_work(dev->mt76.wq, &dev->pm.wake_work);
- return 0;
+ intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA);
+ intr &= dev->mt76.mmio.irqmask;
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_STA, intr);
+
+ trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
+
+ mask |= intr & (irq_map->rx.data_complete_mask |
+ irq_map->rx.wm_complete_mask |
+ irq_map->rx.wm2_complete_mask);
+ if (intr & dev->irq_map->tx.mcu_complete_mask)
+ mask |= dev->irq_map->tx.mcu_complete_mask;
+
+ if (intr & MT_INT_MCU_CMD) {
+ u32 intr_sw;
+
+ intr_sw = mt76_rr(dev, MT_MCU_CMD);
+ /* ack MCU2HOST_SW_INT_STA */
+ mt76_wr(dev, MT_MCU_CMD, intr_sw);
+ if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) {
+ mask |= irq_map->rx.data_complete_mask;
+ intr |= irq_map->rx.data_complete_mask;
+ }
}
- done = mt76_dma_rx_poll(napi, budget);
- mt76_connac_pm_unref(&dev->mphy, &dev->pm);
- return done;
+ mt76_set_irq_mask(&dev->mt76, irq_map->host_irq_enable, mask, 0);
+
+ if (intr & dev->irq_map->tx.all_complete_mask)
+ napi_schedule(&dev->mt76.tx_napi);
+
+ if (intr & irq_map->rx.wm_complete_mask)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]);
+
+ if (intr & irq_map->rx.wm2_complete_mask)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]);
+
+ if (intr & irq_map->rx.data_complete_mask)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
}
+EXPORT_SYMBOL_GPL(mt792x_irq_tasklet);
-static void mt7921_dma_prefetch(struct mt7921_dev *dev)
+void mt792x_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
-#define PREFETCH(base, depth) ((base) << 16 | (depth))
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ const struct mt792x_irq_map *irq_map = dev->irq_map;
+
+ if (q == MT_RXQ_MAIN)
+ mt76_connac_irq_enable(mdev, irq_map->rx.data_complete_mask);
+ else if (q == MT_RXQ_MCU_WA)
+ mt76_connac_irq_enable(mdev, irq_map->rx.wm2_complete_mask);
+ else
+ mt76_connac_irq_enable(mdev, irq_map->rx.wm_complete_mask);
+}
+EXPORT_SYMBOL_GPL(mt792x_rx_poll_complete);
+#define PREFETCH(base, depth) ((base) << 16 | (depth))
+static void mt792x_dma_prefetch(struct mt792x_dev *dev)
+{
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x40, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x80, 0x4));
@@ -64,44 +105,10 @@ static void mt7921_dma_prefetch(struct mt7921_dev *dev)
mt76_wr(dev, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4));
}
-static int mt7921_dma_disable(struct mt7921_dev *dev, bool force)
-{
- /* disable WFDMA0 */
- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- if (!mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
- MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1))
- return -ETIMEDOUT;
-
- /* disable dmashdl */
- mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
- MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
- mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
-
- if (force) {
- /* reset */
- mt76_clear(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST |
- MT_WFDMA0_RST_LOGIC_RST);
-
- mt76_set(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST |
- MT_WFDMA0_RST_LOGIC_RST);
- }
-
- return 0;
-}
-
-static int mt7921_dma_enable(struct mt7921_dev *dev)
+int mt792x_dma_enable(struct mt792x_dev *dev)
{
/* configure perfetch settings */
- mt7921_dma_prefetch(dev);
+ mt792x_dma_prefetch(dev);
/* reset dma idx */
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
@@ -124,18 +131,23 @@ static int mt7921_dma_enable(struct mt7921_dev *dev)
/* enable interrupts for TX/RX rings */
mt76_connac_irq_enable(&dev->mt76,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ dev->irq_map->tx.all_complete_mask |
+ dev->irq_map->rx.data_complete_mask |
+ dev->irq_map->rx.wm2_complete_mask |
+ dev->irq_map->rx.wm_complete_mask |
MT_INT_MCU_CMD);
mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_dma_enable);
-static int mt7921_dma_reset(struct mt7921_dev *dev, bool force)
+static int
+mt792x_dma_reset(struct mt792x_dev *dev, bool force)
{
int i, err;
- err = mt7921_dma_disable(dev, force);
+ err = mt792x_dma_disable(dev, force);
if (err)
return err;
@@ -151,23 +163,10 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force)
mt76_tx_status_check(&dev->mt76, true);
- return mt7921_dma_enable(dev);
-}
-
-int mt7921_wfsys_reset(struct mt7921_dev *dev)
-{
- mt76_clear(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B);
- msleep(50);
- mt76_set(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B);
-
- if (!__mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B,
- WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500))
- return -ETIMEDOUT;
-
- return 0;
+ return mt792x_dma_enable(dev);
}
-int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
+int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force)
{
int i, err;
@@ -182,11 +181,11 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
if (force) {
- err = mt7921_wfsys_reset(dev);
+ err = mt792x_wfsys_reset(dev);
if (err)
return err;
}
- err = mt7921_dma_reset(dev, force);
+ err = mt792x_dma_reset(dev, force);
if (err)
return err;
@@ -195,19 +194,20 @@ int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_wpdma_reset);
-int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
+int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev)
{
struct mt76_connac_pm *pm = &dev->pm;
int err;
/* check if the wpdma must be reinitialized */
- if (mt7921_dma_need_reinit(dev)) {
+ if (mt792x_dma_need_reinit(dev)) {
/* disable interrutpts */
- mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, dev->irq_map->host_irq_enable, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
- err = mt7921_wpdma_reset(dev, false);
+ err = mt792x_wpdma_reset(dev, false);
if (err) {
dev_err(dev->mt76.dev, "wpdma reset failed\n");
return err;
@@ -220,73 +220,44 @@ int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_wpdma_reinit_cond);
-int mt7921_dma_init(struct mt7921_dev *dev)
+int mt792x_dma_disable(struct mt792x_dev *dev, bool force)
{
- int ret;
-
- mt76_dma_attach(&dev->mt76);
-
- ret = mt7921_dma_disable(dev, true);
- if (ret)
- return ret;
-
- /* init tx queue */
- ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0,
- MT7921_TX_RING_SIZE,
- MT_TX_RING_BASE, 0);
- if (ret)
- return ret;
-
- mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
-
- /* command to WM */
- ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM,
- MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
- if (ret)
- return ret;
-
- /* firmware download */
- ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL,
- MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
- if (ret)
- return ret;
-
- /* event from WM before firmware download */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
- MT7921_RXQ_MCU_WM,
- MT7921_RX_MCU_RING_SIZE,
- MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
- if (ret)
- return ret;
-
- /* Change mcu queue after firmware download */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
- MT7921_RXQ_MCU_WM,
- MT7921_RX_MCU_RING_SIZE,
- MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
- if (ret)
- return ret;
-
- /* rx data */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
- MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE,
- MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
- if (ret)
- return ret;
-
- ret = mt76_init_queues(dev, mt7921_poll_rx);
- if (ret < 0)
- return ret;
-
- netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
- mt7921_poll_tx);
- napi_enable(&dev->mt76.tx_napi);
-
- return mt7921_dma_enable(dev);
+ /* disable WFDMA0 */
+ mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ if (!mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
+ MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1))
+ return -ETIMEDOUT;
+
+ /* disable dmashdl */
+ mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
+ MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
+ mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
+
+ if (force) {
+ /* reset */
+ mt76_clear(dev, MT_WFDMA0_RST,
+ MT_WFDMA0_RST_DMASHDL_ALL_RST |
+ MT_WFDMA0_RST_LOGIC_RST);
+
+ mt76_set(dev, MT_WFDMA0_RST,
+ MT_WFDMA0_RST_DMASHDL_ALL_RST |
+ MT_WFDMA0_RST_LOGIC_RST);
+ }
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(mt792x_dma_disable);
-void mt7921_dma_cleanup(struct mt7921_dev *dev)
+void mt792x_dma_cleanup(struct mt792x_dev *dev)
{
/* disable */
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
@@ -312,3 +283,62 @@ void mt7921_dma_cleanup(struct mt7921_dev *dev)
mt76_dma_cleanup(&dev->mt76);
}
+EXPORT_SYMBOL_GPL(mt792x_dma_cleanup);
+
+int mt792x_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct mt792x_dev *dev;
+
+ dev = container_of(napi, struct mt792x_dev, mt76.tx_napi);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+
+ mt76_connac_tx_cleanup(&dev->mt76);
+ if (napi_complete(napi))
+ mt76_connac_irq_enable(&dev->mt76,
+ dev->irq_map->tx.all_complete_mask);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_poll_tx);
+
+int mt792x_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct mt792x_dev *dev;
+ int done;
+
+ dev = container_of(napi->dev, struct mt792x_dev, mt76.napi_dev);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+ done = mt76_dma_rx_poll(napi, budget);
+ mt76_connac_pm_unref(&dev->mphy, &dev->pm);
+
+ return done;
+}
+EXPORT_SYMBOL_GPL(mt792x_poll_rx);
+
+int mt792x_wfsys_reset(struct mt792x_dev *dev)
+{
+ u32 addr = is_mt7921(&dev->mt76) ? 0x18000140 : 0x7c000140;
+
+ mt76_clear(dev, addr, WFSYS_SW_RST_B);
+ msleep(50);
+ mt76_set(dev, addr, WFSYS_SW_RST_B);
+
+ if (!__mt76_poll_msec(&dev->mt76, addr, WFSYS_SW_INIT_DONE,
+ WFSYS_SW_INIT_DONE, 500))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_wfsys_reset);
+
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c
new file mode 100644
index 000000000000..5d1f8229fdc1
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#include <linux/module.h>
+
+#include "mt792x.h"
+#include "mt792x_regs.h"
+
+void mt792x_mac_work(struct work_struct *work)
+{
+ struct mt792x_phy *phy;
+ struct mt76_phy *mphy;
+
+ mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
+ mac_work.work);
+ phy = mphy->priv;
+
+ mt792x_mutex_acquire(phy->dev);
+
+ mt76_update_survey(mphy);
+ if (++mphy->mac_work_count == 2) {
+ mphy->mac_work_count = 0;
+
+ mt792x_mac_update_mib_stats(phy);
+ }
+
+ mt792x_mutex_release(phy->dev);
+
+ mt76_tx_status_check(mphy->dev, false);
+ ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
+ MT792x_WATCHDOG_TIME);
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_work);
+
+void mt792x_mac_set_timeing(struct mt792x_phy *phy)
+{
+ s16 coverage_class = phy->coverage_class;
+ struct mt792x_dev *dev = phy->dev;
+ u32 val, reg_offset;
+ u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
+ FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
+ u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
+ FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
+ bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
+ int sifs = is_2ghz ? 10 : 16, offset;
+
+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
+ return;
+
+ mt76_set(dev, MT_ARB_SCR(0),
+ MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
+ udelay(1);
+
+ offset = 3 * coverage_class;
+ reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
+ FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
+
+ mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset);
+ mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset);
+ mt76_wr(dev, MT_TMAC_ICR0(0),
+ FIELD_PREP(MT_IFS_EIFS, 360) |
+ FIELD_PREP(MT_IFS_RIFS, 2) |
+ FIELD_PREP(MT_IFS_SIFS, sifs) |
+ FIELD_PREP(MT_IFS_SLOT, phy->slottime));
+
+ if (phy->slottime < 20 || !is_2ghz)
+ val = MT792x_CFEND_RATE_DEFAULT;
+ else
+ val = MT792x_CFEND_RATE_11B;
+
+ mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val);
+ mt76_clear(dev, MT_ARB_SCR(0),
+ MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_set_timeing);
+
+void mt792x_mac_update_mib_stats(struct mt792x_phy *phy)
+{
+ struct mt76_mib_stats *mib = &phy->mib;
+ struct mt792x_dev *dev = phy->dev;
+ int i, aggr0 = 0, aggr1;
+ u32 val;
+
+ mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0),
+ MT_MIB_SDR3_FCS_ERR_MASK);
+ mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0),
+ MT_MIB_ACK_FAIL_COUNT_MASK);
+ mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0),
+ MT_MIB_BA_FAIL_COUNT_MASK);
+ mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0),
+ MT_MIB_RTS_COUNT_MASK);
+ mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0),
+ MT_MIB_RTS_FAIL_COUNT_MASK);
+
+ mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0));
+ mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0));
+ mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0));
+
+ val = mt76_rr(dev, MT_MIB_SDR32(0));
+ mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val);
+ mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val);
+
+ val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0));
+ mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val);
+ mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val);
+
+ val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0));
+ mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val);
+ mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val);
+ mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val);
+ mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val);
+
+ mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0));
+ mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0));
+ mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0));
+ mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0));
+
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
+ val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
+ mib->tx_amsdu[i] += val;
+ mib->tx_amsdu_cnt += val;
+ }
+
+ for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) {
+ u32 val2;
+
+ val = mt76_rr(dev, MT_TX_AGG_CNT(0, i));
+ val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
+
+ phy->mt76->aggr_stats[aggr0++] += val & 0xffff;
+ phy->mt76->aggr_stats[aggr0++] += val >> 16;
+ phy->mt76->aggr_stats[aggr1++] += val2 & 0xffff;
+ phy->mt76->aggr_stats[aggr1++] += val2 >> 16;
+ }
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_update_mib_stats);
+
+struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx,
+ bool unicast)
+{
+ struct mt792x_sta *sta;
+ struct mt76_wcid *wcid;
+
+ if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+ return NULL;
+
+ wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ if (unicast || !wcid)
+ return wcid;
+
+ if (!wcid->sta)
+ return NULL;
+
+ sta = container_of(wcid, struct mt792x_sta, wcid);
+ if (!sta->vif)
+ return NULL;
+
+ return &sta->vif->sta.wcid;
+}
+EXPORT_SYMBOL_GPL(mt792x_rx_get_wcid);
+
+static void
+mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct sk_buff *skb = priv;
+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
+
+ if (status->signal > 0)
+ return;
+
+ if (!ether_addr_equal(vif->addr, hdr->addr1))
+ return;
+
+ ewma_rssi_add(&mvif->rssi, -status->signal);
+}
+
+void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
+
+ if (!ieee80211_is_assoc_resp(hdr->frame_control) &&
+ !ieee80211_is_auth(hdr->frame_control))
+ return;
+
+ ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt792x_mac_rssi_iter, skb);
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_assoc_rssi);
+
+void mt792x_mac_reset_counters(struct mt792x_phy *phy)
+{
+ struct mt792x_dev *dev = phy->dev;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ mt76_rr(dev, MT_TX_AGG_CNT(0, i));
+ mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
+ }
+
+ dev->mt76.phy.survey_time = ktime_get_boottime();
+ memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
+
+ /* reset airtime counters */
+ mt76_rr(dev, MT_MIB_SDR9(0));
+ mt76_rr(dev, MT_MIB_SDR36(0));
+ mt76_rr(dev, MT_MIB_SDR37(0));
+
+ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
+ mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_reset_counters);
+
+static u8
+mt792x_phy_get_nf(struct mt792x_phy *phy, int idx)
+{
+ return 0;
+}
+
+static void
+mt792x_phy_update_channel(struct mt76_phy *mphy, int idx)
+{
+ struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76);
+ struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
+ struct mt76_channel_state *state;
+ u64 busy_time, tx_time, rx_time, obss_time;
+ int nf;
+
+ busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
+ MT_MIB_SDR9_BUSY_MASK);
+ tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
+ MT_MIB_SDR36_TXTIME_MASK);
+ rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
+ MT_MIB_SDR37_RXTIME_MASK);
+ obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
+ MT_MIB_OBSSTIME_MASK);
+
+ nf = mt792x_phy_get_nf(phy, idx);
+ if (!phy->noise)
+ phy->noise = nf << 4;
+ else if (nf)
+ phy->noise += nf - (phy->noise >> 4);
+
+ state = mphy->chan_state;
+ state->cc_busy += busy_time;
+ state->cc_tx += tx_time;
+ state->cc_rx += rx_time + obss_time;
+ state->cc_bss_rx += rx_time;
+ state->noise = -(phy->noise >> 4);
+}
+
+void mt792x_update_channel(struct mt76_phy *mphy)
+{
+ struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76);
+
+ if (mt76_connac_pm_wake(mphy, &dev->pm))
+ return;
+
+ mt792x_phy_update_channel(mphy, 0);
+ /* reset obss airtime */
+ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
+ mt76_connac_power_save_sched(mphy, &dev->pm);
+}
+EXPORT_SYMBOL_GPL(mt792x_update_channel);
+
+void mt792x_reset(struct mt76_dev *mdev)
+{
+ struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
+ struct mt76_connac_pm *pm = &dev->pm;
+
+ if (!dev->hw_init_done)
+ return;
+
+ if (dev->hw_full_reset)
+ return;
+
+ if (pm->suspended)
+ return;
+
+ queue_work(dev->mt76.wq, &dev->reset_work);
+}
+EXPORT_SYMBOL_GPL(mt792x_reset);
+
+void mt792x_mac_init_band(struct mt792x_dev *dev, u8 band)
+{
+ u32 mask, set;
+
+ mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
+ MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
+ mt76_set(dev, MT_TMAC_CTCR0(band),
+ MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
+ MT_TMAC_CTCR0_INS_DDLMT_EN);
+
+ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
+ mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
+
+ /* enable MIB tx-rx time reporting */
+ mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN);
+ mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN);
+
+ mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
+ /* disable rx rate report by default due to hw issues */
+ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
+
+ /* filter out non-resp frames and get instantaneous signal reporting */
+ mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM;
+ set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
+ FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
+ mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
+}
+EXPORT_SYMBOL_GPL(mt792x_mac_init_band);
+
+void mt792x_pm_wake_work(struct work_struct *work)
+{
+ struct mt792x_dev *dev;
+ struct mt76_phy *mphy;
+
+ dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,
+ pm.wake_work);
+ mphy = dev->phy.mt76;
+
+ if (!mt792x_mcu_drv_pmctrl(dev)) {
+ struct mt76_dev *mdev = &dev->mt76;
+ int i;
+
+ if (mt76_is_sdio(mdev)) {
+ mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
+ mt76_worker_schedule(&mdev->sdio.txrx_worker);
+ } else {
+ local_bh_disable();
+ mt76_for_each_q_rx(mdev, i)
+ napi_schedule(&mdev->napi[i]);
+ local_bh_enable();
+ mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
+ mt76_connac_tx_cleanup(mdev);
+ }
+ if (test_bit(MT76_STATE_RUNNING, &mphy->state))
+ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
+ MT792x_WATCHDOG_TIME);
+ }
+
+ ieee80211_wake_queues(mphy->hw);
+ wake_up(&dev->pm.wait);
+}
+EXPORT_SYMBOL_GPL(mt792x_pm_wake_work);
+
+void mt792x_pm_power_save_work(struct work_struct *work)
+{
+ struct mt792x_dev *dev;
+ unsigned long delta;
+ struct mt76_phy *mphy;
+
+ dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,
+ pm.ps_work.work);
+ mphy = dev->phy.mt76;
+
+ delta = dev->pm.idle_timeout;
+ if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) ||
+ dev->fw_assert)
+ goto out;
+
+ if (mutex_is_locked(&dev->mt76.mutex))
+ /* if mt76 mutex is held we should not put the device
+ * to sleep since we are currently accessing device
+ * register map. We need to wait for the next power_save
+ * trigger.
+ */
+ goto out;
+
+ if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
+ delta = dev->pm.last_activity + delta - jiffies;
+ goto out;
+ }
+
+ if (!mt792x_mcu_fw_pmctrl(dev)) {
+ cancel_delayed_work_sync(&mphy->mac_work);
+ return;
+ }
+out:
+ queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
+}
+EXPORT_SYMBOL_GPL(mt792x_pm_power_save_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
new file mode 100644
index 000000000000..a99af23e4b56
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
@@ -0,0 +1,479 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2023 MediaTek Inc. */
+
+#ifndef __MT792X_REGS_H
+#define __MT792X_REGS_H
+
+/* MCU WFDMA1 */
+#define MT_MCU_WFDMA1_BASE 0x3000
+#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs))
+
+#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108)
+#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0)
+#define MT_MCU_INT_EVENT_DMA_INIT BIT(1)
+#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
+#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
+
+#define MT_PLE_BASE 0x820c0000
+#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
+
+#define MT_PLE_FL_Q0_CTRL MT_PLE(0x3e0)
+#define MT_PLE_FL_Q1_CTRL MT_PLE(0x3e4)
+#define MT_PLE_FL_Q2_CTRL MT_PLE(0x3e8)
+#define MT_PLE_FL_Q3_CTRL MT_PLE(0x3ec)
+
+#define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n))
+#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
+
+/* TMAC: band 0(0x21000), band 1(0xa1000) */
+#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
+#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
+
+#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
+#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25)
+
+#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
+#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094)
+#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
+#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16)
+
+#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4)
+#define MT_IFS_EIFS GENMASK(8, 0)
+#define MT_IFS_RIFS GENMASK(14, 10)
+#define MT_IFS_SIFS GENMASK(22, 16)
+#define MT_IFS_SLOT GENMASK(30, 24)
+
+#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4)
+#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0)
+#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
+#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
+
+#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
+#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
+
+#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000)
+#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
+
+#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
+#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
+#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
+
+/* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */
+#define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000)
+#define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs))
+
+#define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008)
+#define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30)
+#define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24)
+
+/* LPON: band 0(0x24200), band 1(0xa4200) */
+#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
+#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))
+
+#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080)
+#define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084)
+
+#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4)
+#define MT_LPON_TCR_SW_MODE GENMASK(1, 0)
+#define MT_LPON_TCR_SW_WRITE BIT(0)
+
+/* ETBF: band 0(0x24000), band 1(0xa4000) */
+#define MT_WF_ETBF_BASE(_band) ((_band) ? 0x820fa000 : 0x820ea000)
+#define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs))
+
+#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x150)
+#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16)
+#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0)
+
+#define MT_ETBF_RX_FB_CNT(_band) MT_WF_ETBF(_band, 0x158)
+#define MT_ETBF_RX_FB_ALL GENMASK(31, 24)
+#define MT_ETBF_RX_FB_HE GENMASK(23, 16)
+#define MT_ETBF_RX_FB_VHT GENMASK(15, 8)
+#define MT_ETBF_RX_FB_HT GENMASK(7, 0)
+
+/* MIB: band 0(0x24800), band 1(0xa4800) */
+#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000)
+#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
+
+#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
+#define MT_MIB_TXDUR_EN BIT(8)
+#define MT_MIB_RXDUR_EN BIT(9)
+
+#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x698)
+#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(31, 16)
+
+#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x780)
+
+#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
+#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x558)
+#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x564)
+#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x568)
+
+#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
+#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x770)
+#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x774)
+#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x55c)
+
+#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x7a8)
+#define MT_MIB_SDR9_IBF_CNT_MASK GENMASK(31, 16)
+#define MT_MIB_SDR9_EBF_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090)
+#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0)
+
+#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x054)
+#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
+#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x058)
+#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
+#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4)
+#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc)
+
+#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4))
+#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
+
+#define MT_MIB_MB_BSDR0(_band) MT_WF_MIB(_band, 0x688)
+#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
+#define MT_MIB_MB_BSDR1(_band) MT_WF_MIB(_band, 0x690)
+#define MT_MIB_RTS_FAIL_COUNT_MASK GENMASK(15, 0)
+#define MT_MIB_MB_BSDR2(_band) MT_WF_MIB(_band, 0x518)
+#define MT_MIB_BA_FAIL_COUNT_MASK GENMASK(15, 0)
+#define MT_MIB_MB_BSDR3(_band) MT_WF_MIB(_band, 0x520)
+#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4))
+#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0)
+
+#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x7dc + ((n) << 2))
+#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x7ec + ((n) << 2))
+#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
+#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
+
+#define MT_WTBLON_TOP_BASE 0x820d4000
+#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
+
+#define MT_WTBL_UPDATE_BUSY BIT(31)
+
+#define MT_WTBL_ITCR MT_WTBLON_TOP(0x3b0)
+#define MT_WTBL_ITCR_WR BIT(16)
+#define MT_WTBL_ITCR_EXEC BIT(31)
+#define MT_WTBL_ITDR0 MT_WTBLON_TOP(0x3b8)
+#define MT_WTBL_ITDR1 MT_WTBLON_TOP(0x3bc)
+#define MT_WTBL_SPE_IDX_SEL BIT(6)
+
+#define MT_WTBL_BASE 0x820d8000
+#define MT_WTBL_LMAC_ID GENMASK(14, 8)
+#define MT_WTBL_LMAC_DW GENMASK(7, 2)
+#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
+ FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \
+ FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
+
+/* AGG: band 0(0x20800), band 1(0xa0800) */
+#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000)
+#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
+
+#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
+#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4)
+#define MT_AGG_PCR0_MM_PROT BIT(0)
+#define MT_AGG_PCR0_GF_PROT BIT(1)
+#define MT_AGG_PCR0_BW20_PROT BIT(2)
+#define MT_AGG_PCR0_BW40_PROT BIT(4)
+#define MT_AGG_PCR0_BW80_PROT BIT(6)
+#define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8)
+#define MT_AGG_PCR0_VHT_PROT BIT(13)
+#define MT_AGG_PCR0_PTA_WIN_DIS BIT(15)
+
+#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23)
+#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0)
+
+#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084)
+#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
+#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)
+
+#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098)
+#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
+#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
+#define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7)
+#define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24)
+
+#define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0)
+#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
+
+/* ARB: band 0(0x20c00), band 1(0xa0c00) */
+#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000)
+#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
+
+#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
+#define MT_ARB_SCR_TX_DISABLE BIT(8)
+#define MT_ARB_SCR_RX_DISABLE BIT(9)
+
+#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
+
+/* RMAC: band 0(0x21400), band 1(0xa1400) */
+#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
+#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
+
+#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)
+#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0)
+#define MT_WF_RFCR_DROP_FCSFAIL BIT(1)
+#define MT_WF_RFCR_DROP_VERSION BIT(3)
+#define MT_WF_RFCR_DROP_PROBEREQ BIT(4)
+#define MT_WF_RFCR_DROP_MCAST BIT(5)
+#define MT_WF_RFCR_DROP_BCAST BIT(6)
+#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7)
+#define MT_WF_RFCR_DROP_A3_MAC BIT(8)
+#define MT_WF_RFCR_DROP_A3_BSSID BIT(9)
+#define MT_WF_RFCR_DROP_A2_BSSID BIT(10)
+#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11)
+#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12)
+#define MT_WF_RFCR_DROP_CTL_RSV BIT(13)
+#define MT_WF_RFCR_DROP_CTS BIT(14)
+#define MT_WF_RFCR_DROP_RTS BIT(15)
+#define MT_WF_RFCR_DROP_DUPLICATE BIT(16)
+#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17)
+#define MT_WF_RFCR_DROP_OTHER_UC BIT(18)
+#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19)
+#define MT_WF_RFCR_DROP_NDPA BIT(20)
+#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
+
+#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004)
+#define MT_WF_RFCR1_DROP_ACK BIT(4)
+#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
+#define MT_WF_RFCR1_DROP_BA BIT(6)
+#define MT_WF_RFCR1_DROP_CFEND BIT(7)
+#define MT_WF_RFCR1_DROP_CFACK BIT(8)
+
+#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4)
+#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
+#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
+
+#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8)
+#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
+#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
+
+/* WFDMA0 */
+#define MT_WFDMA0_BASE 0xd4000
+#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs))
+
+#define MT_WFDMA0_RST MT_WFDMA0(0x100)
+#define MT_WFDMA0_RST_LOGIC_RST BIT(4)
+#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5)
+
+#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c)
+#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0)
+#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
+#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)
+
+#define MT_MCU_CMD MT_WFDMA0(0x1f0)
+#define MT_MCU_CMD_WAKE_RX_PCIE BIT(0)
+#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
+#define MT_MCU_CMD_STOP_DMA BIT(2)
+#define MT_MCU_CMD_RESET_DONE BIT(3)
+#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
+#define MT_MCU_CMD_NORMAL_STATE BIT(5)
+#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+
+#define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4)
+
+#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200)
+#define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */
+#define HOST_RX_DONE_INT_STS2 BIT(2) /* Rx data */
+#define HOST_RX_DONE_INT_STS4 BIT(22) /* Rx mcu after fw downloaded */
+#define HOST_TX_DONE_INT_STS16 BIT(26)
+#define HOST_TX_DONE_INT_STS17 BIT(27) /* MCU tx done*/
+
+#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
+#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
+#define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1)
+#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
+#define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3)
+#define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6)
+#define MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL BIT(9)
+#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12)
+#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15)
+#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21)
+#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
+#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
+#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS BIT(30)
+
+#define HOST_RX_DONE_INT_ENA0 BIT(0)
+#define HOST_RX_DONE_INT_ENA1 BIT(1)
+#define HOST_RX_DONE_INT_ENA2 BIT(2)
+#define HOST_RX_DONE_INT_ENA3 BIT(3)
+#define HOST_TX_DONE_INT_ENA0 BIT(4)
+#define HOST_TX_DONE_INT_ENA1 BIT(5)
+#define HOST_TX_DONE_INT_ENA2 BIT(6)
+#define HOST_TX_DONE_INT_ENA3 BIT(7)
+#define HOST_TX_DONE_INT_ENA4 BIT(8)
+#define HOST_TX_DONE_INT_ENA5 BIT(9)
+#define HOST_TX_DONE_INT_ENA6 BIT(10)
+#define HOST_TX_DONE_INT_ENA7 BIT(11)
+#define HOST_RX_COHERENT_EN BIT(20)
+#define HOST_TX_COHERENT_EN BIT(21)
+#define MCU2HOST_SW_INT_ENA BIT(29)
+#define HOST_TX_DONE_INT_ENA18 BIT(30)
+
+#define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA
+
+#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c)
+#define MT_WFDMA0_RST_DRX_PTR MT_WFDMA0(0x280)
+#define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
+#define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6)
+#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0)
+
+#define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600)
+#define MT_WFDMA0_TX_RING1_EXT_CTRL MT_WFDMA0(0x604)
+#define MT_WFDMA0_TX_RING2_EXT_CTRL MT_WFDMA0(0x608)
+#define MT_WFDMA0_TX_RING3_EXT_CTRL MT_WFDMA0(0x60c)
+#define MT_WFDMA0_TX_RING4_EXT_CTRL MT_WFDMA0(0x610)
+#define MT_WFDMA0_TX_RING5_EXT_CTRL MT_WFDMA0(0x614)
+#define MT_WFDMA0_TX_RING6_EXT_CTRL MT_WFDMA0(0x618)
+#define MT_WFDMA0_TX_RING15_EXT_CTRL MT_WFDMA0(0x63c)
+#define MT_WFDMA0_TX_RING16_EXT_CTRL MT_WFDMA0(0x640)
+#define MT_WFDMA0_TX_RING17_EXT_CTRL MT_WFDMA0(0x644)
+
+#define MT_WPDMA0_MAX_CNT_MASK GENMASK(7, 0)
+#define MT_WPDMA0_BASE_PTR_MASK GENMASK(31, 16)
+
+#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680)
+#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684)
+#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688)
+#define MT_WFDMA0_RX_RING3_EXT_CTRL MT_WFDMA0(0x68c)
+#define MT_WFDMA0_RX_RING4_EXT_CTRL MT_WFDMA0(0x690)
+#define MT_WFDMA0_RX_RING5_EXT_CTRL MT_WFDMA0(0x694)
+#define MT_WFDMA0_RX_RING6_EXT_CTRL MT_WFDMA0(0x698)
+#define MT_WFDMA0_RX_RING7_EXT_CTRL MT_WFDMA0(0x69c)
+
+#define MT_TX_RING_BASE MT_WFDMA0(0x300)
+#define MT_RX_EVENT_RING_BASE MT_WFDMA0(0x500)
+
+/* WFDMA CSR */
+#define MT_WFDMA_EXT_CSR_BASE 0xd7000
+#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs))
+#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
+#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
+
+#define MT_SWDEF_BASE 0x41f200
+#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
+#define MT_SWDEF_MODE MT_SWDEF(0x3c)
+#define MT_SWDEF_NORMAL_MODE 0
+#define MT_SWDEF_ICAP_MODE 1
+#define MT_SWDEF_SPECTRUM_MODE 2
+
+#define MT_TOP_BASE 0x18060000
+#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
+
+#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10)
+#define MT_TOP_LPCR_HOST_FW_OWN BIT(0)
+#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1)
+
+#define MT_TOP_MISC MT_TOP(0xf0)
+#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+
+#define MT_MCU_WPDMA0_BASE 0x54000000
+#define MT_MCU_WPDMA0(ofs) (MT_MCU_WPDMA0_BASE + (ofs))
+
+#define MT_WFDMA_DUMMY_CR MT_MCU_WPDMA0(0x120)
+#define MT_WFDMA_NEED_REINIT BIT(1)
+
+#define MT_CBTOP_RGU(ofs) (0x70002000 + (ofs))
+#define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600)
+#define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0)
+
+#define MT_HW_BOUND 0x70010020
+#define MT_HW_CHIPID 0x70010200
+#define MT_HW_REV 0x70010204
+
+#define MT_PCIE_MAC_BASE 0x10000
+#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs))
+#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188)
+#define MT_PCIE_MAC_PM MT_PCIE_MAC(0x194)
+#define MT_PCIE_MAC_PM_L0S_DIS BIT(8)
+
+#define MT_DMA_SHDL(ofs) (0x7c026000 + (ofs))
+#define MT_DMASHDL_SW_CONTROL MT_DMA_SHDL(0x004)
+#define MT_DMASHDL_DMASHDL_BYPASS BIT(28)
+#define MT_DMASHDL_OPTIONAL MT_DMA_SHDL(0x008)
+#define MT_DMASHDL_PAGE MT_DMA_SHDL(0x00c)
+#define MT_DMASHDL_GROUP_SEQ_ORDER BIT(16)
+#define MT_DMASHDL_REFILL MT_DMA_SHDL(0x010)
+#define MT_DMASHDL_REFILL_MASK GENMASK(31, 16)
+#define MT_DMASHDL_PKT_MAX_SIZE MT_DMA_SHDL(0x01c)
+#define MT_DMASHDL_PKT_MAX_SIZE_PLE GENMASK(11, 0)
+#define MT_DMASHDL_PKT_MAX_SIZE_PSE GENMASK(27, 16)
+
+#define MT_DMASHDL_GROUP_QUOTA(_n) MT_DMA_SHDL(0x020 + ((_n) << 2))
+#define MT_DMASHDL_GROUP_QUOTA_MIN GENMASK(11, 0)
+#define MT_DMASHDL_GROUP_QUOTA_MAX GENMASK(27, 16)
+
+#define MT_DMASHDL_Q_MAP(_n) MT_DMA_SHDL(0x060 + ((_n) << 2))
+#define MT_DMASHDL_Q_MAP_MASK GENMASK(3, 0)
+#define MT_DMASHDL_Q_MAP_SHIFT(_n) (4 * ((_n) % 8))
+
+#define MT_DMASHDL_SCHED_SET(_n) MT_DMA_SHDL(0x070 + ((_n) << 2))
+
+#define MT_WFDMA_HOST_CONFIG 0x7c027030
+#define MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN BIT(6)
+
+#define MT_UMAC(ofs) (0x74000000 + (ofs))
+#define MT_UDMA_TX_QSEL MT_UMAC(0x008)
+#define MT_FW_DL_EN BIT(3)
+
+#define MT_UDMA_WLCFG_1 MT_UMAC(0x00c)
+#define MT_WL_RX_AGG_PKT_LMT GENMASK(7, 0)
+#define MT_WL_TX_TMOUT_LMT GENMASK(27, 8)
+
+#define MT_UDMA_WLCFG_0 MT_UMAC(0x18)
+#define MT_WL_RX_AGG_TO GENMASK(7, 0)
+#define MT_WL_RX_AGG_LMT GENMASK(15, 8)
+#define MT_WL_TX_TMOUT_FUNC_EN BIT(16)
+#define MT_WL_TX_DPH_CHK_EN BIT(17)
+#define MT_WL_RX_MPSZ_PAD0 BIT(18)
+#define MT_WL_RX_FLUSH BIT(19)
+#define MT_TICK_1US_EN BIT(20)
+#define MT_WL_RX_AGG_EN BIT(21)
+#define MT_WL_RX_EN BIT(22)
+#define MT_WL_TX_EN BIT(23)
+#define MT_WL_RX_BUSY BIT(30)
+#define MT_WL_TX_BUSY BIT(31)
+
+#define MT_UDMA_CONN_INFRA_STATUS MT_UMAC(0xa20)
+#define MT_UDMA_CONN_WFSYS_INIT_DONE BIT(22)
+#define MT_UDMA_CONN_INFRA_STATUS_SEL MT_UMAC(0xa24)
+
+#define MT_SSUSB_EPCTL_CSR(ofs) (0x74011800 + (ofs))
+#define MT_SSUSB_EPCTL_CSR_EP_RST_OPT MT_SSUSB_EPCTL_CSR(0x090)
+
+#define MT_UWFDMA0(ofs) (0x7c024000 + (ofs))
+#define MT_UWFDMA0_GLO_CFG MT_UWFDMA0(0x208)
+#define MT_UWFDMA0_GLO_CFG_EXT0 MT_UWFDMA0(0x2b0)
+#define MT_UWFDMA0_GLO_CFG_EXT1 MT_UWFDMA0(0x2b4)
+#define MT_UWFDMA0_TX_RING_EXT_CTRL(_n) MT_UWFDMA0(0x600 + ((_n) << 2))
+
+#define MT_CONN_STATUS 0x7c053c10
+#define MT_WIFI_PATCH_DL_STATE BIT(0)
+
+#define MT_CONN_ON_LPCTL 0x7c060010
+#define PCIE_LPCR_HOST_SET_OWN BIT(0)
+#define PCIE_LPCR_HOST_CLR_OWN BIT(1)
+#define PCIE_LPCR_HOST_OWN_SYNC BIT(2)
+
+#define MT_CONN_ON_MISC 0x7c0600f0
+#define MT_TOP_MISC2_FW_PWR_ON BIT(0)
+#define MT_TOP_MISC2_FW_N9_ON BIT(1)
+#define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0)
+
+#define MT_WF_SW_DEF_CR(ofs) (0x401a00 + (ofs))
+#define MT_WF_SW_DEF_CR_USB_MCU_EVENT MT_WF_SW_DEF_CR(0x028)
+#define MT_WF_SW_SER_TRIGGER_SUSPEND BIT(6)
+#define MT_WF_SW_SER_DONE_SUSPEND BIT(7)
+
+#define WFSYS_SW_RST_B BIT(0)
+#define WFSYS_SW_INIT_DONE BIT(4)
+
+#endif /* __MT792X_REGS_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_trace.c b/drivers/net/wireless/mediatek/mt76/mt792x_trace.c
new file mode 100644
index 000000000000..b6f284fb929d
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_trace.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2023 Lorenzo Bianconi <lorenzo@kernel.org>
+ */
+
+#include <linux/module.h>
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "mt792x_trace.h"
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(lp_event);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921_trace.h b/drivers/net/wireless/mediatek/mt76/mt792x_trace.h
index 9bc4db67f352..61f2aa260656 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_trace.h
@@ -1,27 +1,27 @@
/* SPDX-License-Identifier: ISC */
/*
- * Copyright (C) 2021 Lorenzo Bianconi <lorenzo@kernel.org>
+ * Copyright (C) 2023 Lorenzo Bianconi <lorenzo@kernel.org>
*/
-#if !defined(__MT7921_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define __MT7921_TRACE_H
+#if !defined(__MT792X_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __MT792X_TRACE_H
#include <linux/tracepoint.h>
-#include "mt7921.h"
+#include "mt792x.h"
#undef TRACE_SYSTEM
-#define TRACE_SYSTEM mt7921
+#define TRACE_SYSTEM mt792x
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \
wiphy_name(mt76_hw(dev)->wiphy), MAXNAME)
#define DEV_PR_FMT "%s"
#define DEV_PR_ARG __entry->wiphy_name
#define LP_STATE_PR_ARG __entry->lp_state ? "lp ready" : "lp not ready"
TRACE_EVENT(lp_event,
- TP_PROTO(struct mt7921_dev *dev, u8 lp_state),
+ TP_PROTO(struct mt792x_dev *dev, u8 lp_state),
TP_ARGS(dev, lp_state),
@@ -46,6 +46,6 @@ TRACE_EVENT(lp_event,
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE mt7921_trace
+#define TRACE_INCLUDE_FILE mt792x_trace
#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
new file mode 100644
index 000000000000..20e7f9c7c88c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2023 MediaTek Inc.
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "mt792x.h"
+#include "mt76_connac2_mac.h"
+
+u32 mt792xu_rr(struct mt76_dev *dev, u32 addr)
+{
+ u32 ret;
+
+ mutex_lock(&dev->usb.usb_ctrl_mtx);
+ ret = ___mt76u_rr(dev, MT_VEND_READ_EXT,
+ USB_DIR_IN | MT_USB_TYPE_VENDOR, addr);
+ mutex_unlock(&dev->usb.usb_ctrl_mtx);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt792xu_rr);
+
+void mt792xu_wr(struct mt76_dev *dev, u32 addr, u32 val)
+{
+ mutex_lock(&dev->usb.usb_ctrl_mtx);
+ ___mt76u_wr(dev, MT_VEND_WRITE_EXT,
+ USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val);
+ mutex_unlock(&dev->usb.usb_ctrl_mtx);
+}
+EXPORT_SYMBOL_GPL(mt792xu_wr);
+
+u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val)
+{
+ mutex_lock(&dev->usb.usb_ctrl_mtx);
+ val |= ___mt76u_rr(dev, MT_VEND_READ_EXT,
+ USB_DIR_IN | MT_USB_TYPE_VENDOR, addr) & ~mask;
+ ___mt76u_wr(dev, MT_VEND_WRITE_EXT,
+ USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val);
+ mutex_unlock(&dev->usb.usb_ctrl_mtx);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(mt792xu_rmw);
+
+void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len)
+{
+ struct mt76_usb *usb = &dev->usb;
+ int ret, i = 0, batch_len;
+ const u8 *val = data;
+
+ len = round_up(len, 4);
+
+ mutex_lock(&usb->usb_ctrl_mtx);
+ while (i < len) {
+ batch_len = min_t(int, usb->data_len, len - i);
+ memcpy(usb->data, val + i, batch_len);
+ ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT,
+ USB_DIR_OUT | MT_USB_TYPE_VENDOR,
+ (offset + i) >> 16, offset + i,
+ usb->data, batch_len);
+ if (ret < 0)
+ break;
+
+ i += batch_len;
+ }
+ mutex_unlock(&usb->usb_ctrl_mtx);
+}
+EXPORT_SYMBOL_GPL(mt792xu_copy);
+
+int mt792xu_mcu_power_on(struct mt792x_dev *dev)
+{
+ int ret;
+
+ ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON,
+ USB_DIR_OUT | MT_USB_TYPE_VENDOR,
+ 0x0, 0x1, NULL, 0);
+ if (ret)
+ return ret;
+
+ if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON,
+ MT_TOP_MISC2_FW_PWR_ON, 500)) {
+ dev_err(dev->mt76.dev, "Timeout for power on\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt792xu_mcu_power_on);
+
+static void mt792xu_cleanup(struct mt792x_dev *dev)
+{
+ clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
+ mt792xu_wfsys_reset(dev);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+ mt76u_queues_deinit(&dev->mt76);
+}
+
+static u32 mt792xu_uhw_rr(struct mt76_dev *dev, u32 addr)
+{
+ u32 ret;
+
+ mutex_lock(&dev->usb.usb_ctrl_mtx);
+ ret = ___mt76u_rr(dev, MT_VEND_DEV_MODE,
+ USB_DIR_IN | MT_USB_TYPE_UHW_VENDOR, addr);
+ mutex_unlock(&dev->usb.usb_ctrl_mtx);
+
+ return ret;
+}
+
+static void mt792xu_uhw_wr(struct mt76_dev *dev, u32 addr, u32 val)
+{
+ mutex_lock(&dev->usb.usb_ctrl_mtx);
+ ___mt76u_wr(dev, MT_VEND_WRITE,
+ USB_DIR_OUT | MT_USB_TYPE_UHW_VENDOR, addr, val);
+ mutex_unlock(&dev->usb.usb_ctrl_mtx);
+}
+
+static void mt792xu_dma_prefetch(struct mt792x_dev *dev)
+{
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0),
+ MT_WPDMA0_BASE_PTR_MASK, 0x80);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1),
+ MT_WPDMA0_BASE_PTR_MASK, 0xc0);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2),
+ MT_WPDMA0_BASE_PTR_MASK, 0x100);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3),
+ MT_WPDMA0_BASE_PTR_MASK, 0x140);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4),
+ MT_WPDMA0_BASE_PTR_MASK, 0x180);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16),
+ MT_WPDMA0_BASE_PTR_MASK, 0x280);
+
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17),
+ MT_WPDMA0_MAX_CNT_MASK, 4);
+ mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17),
+ MT_WPDMA0_BASE_PTR_MASK, 0x2c0);
+}
+
+static void mt792xu_wfdma_init(struct mt792x_dev *dev)
+{
+ mt792xu_dma_prefetch(dev);
+
+ mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_OMIT_RX_INFO);
+ mt76_set(dev, MT_UWFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 |
+ MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL |
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+
+ /* disable dmashdl */
+ mt76_clear(dev, MT_UWFDMA0_GLO_CFG_EXT0,
+ MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
+ mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
+
+ mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
+}
+
+static int mt792xu_dma_rx_evt_ep4(struct mt792x_dev *dev)
+{
+ if (!mt76_poll(dev, MT_UWFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000))
+ return -ETIMEDOUT;
+
+ mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+ MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN);
+ mt76_set(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+
+ return 0;
+}
+
+static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset)
+{
+ u32 val;
+
+ /* usb endpoint reset opt
+ * bits[4,9]: out blk ep 4-9
+ * bits[20,21]: in blk ep 4-5
+ * bits[22]: in int ep 6
+ */
+ val = mt792xu_uhw_rr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT);
+ if (reset)
+ val |= GENMASK(9, 4) | GENMASK(22, 20);
+ else
+ val &= ~(GENMASK(9, 4) | GENMASK(22, 20));
+ mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val);
+}
+
+int mt792xu_dma_init(struct mt792x_dev *dev, bool resume)
+{
+ int err;
+
+ mt792xu_wfdma_init(dev);
+
+ mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH);
+
+ mt76_set(dev, MT_UDMA_WLCFG_0,
+ MT_WL_RX_EN | MT_WL_TX_EN |
+ MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN);
+ mt76_clear(dev, MT_UDMA_WLCFG_0,
+ MT_WL_RX_AGG_TO | MT_WL_RX_AGG_LMT);
+ mt76_clear(dev, MT_UDMA_WLCFG_1, MT_WL_RX_AGG_PKT_LMT);
+
+ if (resume)
+ return 0;
+
+ err = mt792xu_dma_rx_evt_ep4(dev);
+ if (err)
+ return err;
+
+ mt792xu_epctl_rst_opt(dev, false);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792xu_dma_init);
+
+int mt792xu_wfsys_reset(struct mt792x_dev *dev)
+{
+ u32 val;
+ int i;
+
+ mt792xu_epctl_rst_opt(dev, false);
+
+ val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
+ val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
+ mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
+
+ usleep_range(10, 20);
+
+ val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST);
+ val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH;
+ mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val);
+
+ mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0);
+ for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) {
+ val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS);
+ if (val & MT_UDMA_CONN_WFSYS_INIT_DONE)
+ break;
+
+ msleep(100);
+ }
+
+ if (i == MT792x_WFSYS_INIT_RETRY_COUNT)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset);
+
+int mt792xu_init_reset(struct mt792x_dev *dev)
+{
+ set_bit(MT76_RESET, &dev->mphy.state);
+
+ wake_up(&dev->mt76.mcu.wait);
+ skb_queue_purge(&dev->mt76.mcu.res_q);
+
+ mt76u_stop_rx(&dev->mt76);
+ mt76u_stop_tx(&dev->mt76);
+
+ mt792xu_wfsys_reset(dev);
+
+ clear_bit(MT76_RESET, &dev->mphy.state);
+
+ return mt76u_resume_rx(&dev->mt76);
+}
+EXPORT_SYMBOL_GPL(mt792xu_init_reset);
+
+void mt792xu_disconnect(struct usb_interface *usb_intf)
+{
+ struct mt792x_dev *dev = usb_get_intfdata(usb_intf);
+
+ cancel_work_sync(&dev->init_work);
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
+ return;
+
+ mt76_unregister_device(&dev->mt76);
+ mt792xu_cleanup(dev);
+
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ mt76_free_device(&dev->mt76);
+}
+EXPORT_SYMBOL_GPL(mt792xu_disconnect);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
index 1afa2f662e47..bb44d4a5e2dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
@@ -7,7 +7,7 @@ config MT7996E
depends on MAC80211
depends on PCI
help
- This adds support for MT7996-based wireless PCIe devices,
+ This adds support for MT7996-based PCIe wireless devices,
which support concurrent tri-band operation at 6GHz, 5GHz,
and 2.4GHz IEEE 802.11be 4x4:4SS 4096-QAM, 320MHz channels.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 513ab4ba41c9..4d40ec7ff57f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -474,10 +474,10 @@ mt7996_ampdu_stat_read_phy(struct mt7996_phy *phy, struct seq_file *file)
static void
mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
{
+ struct mt76_mib_stats *mib = &phy->mib;
static const char * const bw[] = {
"BW20", "BW40", "BW80", "BW160"
};
- struct mib_stats *mib = &phy->mib;
/* Tx Beamformer monitor */
seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
@@ -523,7 +523,7 @@ mt7996_tx_stats_show(struct seq_file *file, void *data)
{
struct mt7996_phy *phy = file->private;
struct mt7996_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
+ struct mt76_mib_stats *mib = &phy->mib;
int i;
u32 attempts, success, per;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 534143465d9b..586e247a1e06 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -128,7 +128,7 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset)
}
}
-static int mt7996_dma_enable(struct mt7996_dev *dev)
+void mt7996_dma_start(struct mt7996_dev *dev, bool reset)
{
u32 hif1_ofs = 0;
u32 irq_mask;
@@ -136,6 +136,50 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
if (dev->hif2)
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+ /* enable WFDMA Tx/Rx */
+ if (!reset) {
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ if (dev->hif2)
+ mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+ }
+
+ /* enable interrupts for TX/RX rings */
+ irq_mask = MT_INT_MCU_CMD;
+ if (reset)
+ goto done;
+
+ irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU;
+
+ if (!dev->mphy.band_idx)
+ irq_mask |= MT_INT_BAND0_RX_DONE;
+
+ if (dev->dbdc_support)
+ irq_mask |= MT_INT_BAND1_RX_DONE;
+
+ if (dev->tbtc_support)
+ irq_mask |= MT_INT_BAND2_RX_DONE;
+
+done:
+ mt7996_irq_enable(dev, irq_mask);
+ mt7996_irq_disable(dev, 0);
+}
+
+static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
+{
+ u32 hif1_ofs = 0;
+
+ if (dev->hif2)
+ hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+
/* reset dma idx */
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
if (dev->hif2)
@@ -170,13 +214,6 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
- /* set WFDMA Tx/Rx */
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0,
WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
@@ -187,12 +224,6 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
if (dev->hif2) {
- mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
@@ -216,23 +247,7 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
/* TODO: redirect rx ring6 interrupt to pcie0 for wed function */
}
- /* enable interrupts for TX/RX rings */
- irq_mask = MT_INT_RX_DONE_MCU |
- MT_INT_TX_DONE_MCU |
- MT_INT_MCU_CMD;
-
- if (!dev->mphy.band_idx)
- irq_mask |= MT_INT_BAND0_RX_DONE;
-
- if (dev->dbdc_support)
- irq_mask |= MT_INT_BAND1_RX_DONE;
-
- if (dev->tbtc_support)
- irq_mask |= MT_INT_BAND2_RX_DONE;
-
- mt7996_irq_enable(dev, irq_mask);
-
- return 0;
+ mt7996_dma_start(dev, reset);
}
int mt7996_dma_init(struct mt7996_dev *dev)
@@ -293,7 +308,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
/* event from WA */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT_RXQ_ID(MT_RXQ_MCU_WA),
- MT7996_RX_MCU_RING_SIZE,
+ MT7996_RX_MCU_RING_SIZE_WA,
MT_RX_BUF_SIZE,
MT_RXQ_RING_BASE(MT_RXQ_MCU_WA));
if (ret)
@@ -347,7 +362,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
mt7996_poll_tx);
napi_enable(&dev->mt76.tx_napi);
- mt7996_dma_enable(dev);
+ mt7996_dma_enable(dev, false);
return 0;
}
@@ -413,7 +428,7 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
- mt7996_dma_enable(dev);
+ mt7996_dma_enable(dev, !force);
}
void mt7996_dma_cleanup(struct mt7996_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index f1b48cdda58f..26e03b28935f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -4,6 +4,7 @@
*/
#include <linux/etherdevice.h>
+#include <linux/of.h>
#include <linux/thermal.h>
#include "mt7996.h"
#include "mac.h"
@@ -183,6 +184,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
if (!mdev->dev->of_node ||
!of_property_read_bool(mdev->dev->of_node,
@@ -217,6 +219,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
IEEE80211_HT_MPDU_DENSITY_1;
+
+ ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
}
mt76_set_stream_caps(phy->mt76, true);
@@ -853,9 +857,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
INIT_LIST_HEAD(&dev->sta_rc_list);
- INIT_LIST_HEAD(&dev->sta_poll_list);
INIT_LIST_HEAD(&dev->twt_list);
- spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7996_mac_reset_work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 9b0f6053e0fa..ac8759febe48 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -13,10 +13,6 @@
#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
-#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
-#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
- IEEE80211_RADIOTAP_HE_##f)
-
static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
.radar_pattern = {
@@ -111,9 +107,9 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
LIST_HEAD(sta_poll_list);
int i;
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&dev->sta_poll_list, &sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
rcu_read_lock();
@@ -124,15 +120,15 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
s8 rssi[4];
u8 bw;
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&sta_poll_list)) {
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
break;
}
msta = list_first_entry(&sta_poll_list,
- struct mt7996_sta, poll_list);
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ struct mt7996_sta, wcid.poll_list);
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
idx = msta->wcid.idx;
@@ -263,180 +259,6 @@ void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
mt76_wr(dev, MT_WTBL_ITCR, ctrl);
}
-static void
-mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
- struct ieee80211_radiotap_he *he,
- __le32 *rxv)
-{
- u32 ru, offs = 0;
-
- ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC);
-
- status->bw = RATE_INFO_BW_HE_RU;
-
- switch (ru) {
- case 0 ... 36:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
- offs = ru;
- break;
- case 37 ... 52:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
- offs = ru - 37;
- break;
- case 53 ... 60:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
- offs = ru - 53;
- break;
- case 61 ... 64:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
- offs = ru - 61;
- break;
- case 65 ... 66:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
- offs = ru - 65;
- break;
- case 67:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
- break;
- case 68:
- status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
- break;
- }
-
- he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
- he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
- le16_encode_bits(offs,
- IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
-}
-
-static void
-mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
-{
- struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- static const struct ieee80211_radiotap_he_mu mu_known = {
- .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
- HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
- HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
- HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
- .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
- };
- struct ieee80211_radiotap_he_mu *he_mu = NULL;
-
- status->flag |= RX_FLAG_RADIOTAP_HE_MU;
-
- he_mu = skb_push(skb, sizeof(mu_known));
- memcpy(he_mu, &mu_known, sizeof(mu_known));
-
-#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
-
- he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
- if (status->he_dcm)
- he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
-
- he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
- MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
- le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
-
- he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
-
- if (status->bw >= RATE_INFO_BW_40) {
- he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
- he_mu->ru_ch2[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU1) & 0xff;
- }
-
- if (status->bw >= RATE_INFO_BW_80) {
- u32 ru_h, ru_l;
-
- he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
-
- ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
- ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
- he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
- }
-}
-
-static void
-mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
-{
- struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
- static const struct ieee80211_radiotap_he known = {
- .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
- HE_BITS(DATA1_DATA_DCM_KNOWN) |
- HE_BITS(DATA1_STBC_KNOWN) |
- HE_BITS(DATA1_CODING_KNOWN) |
- HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
- HE_BITS(DATA1_DOPPLER_KNOWN) |
- HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
- HE_BITS(DATA1_BSS_COLOR_KNOWN),
- .data2 = HE_BITS(DATA2_GI_KNOWN) |
- HE_BITS(DATA2_TXBF_KNOWN) |
- HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
- HE_BITS(DATA2_TXOP_KNOWN),
- };
- struct ieee80211_radiotap_he *he = NULL;
- u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
-
- status->flag |= RX_FLAG_RADIOTAP_HE;
-
- he = skb_push(skb, sizeof(known));
- memcpy(he, &known, sizeof(known));
-
- he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
- HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
- he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
- he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
- le16_encode_bits(ltf_size,
- IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
- if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
- he->data5 |= HE_BITS(DATA5_TXBF);
- he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
- HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
-
- switch (mode) {
- case MT_PHY_TYPE_HE_SU:
- he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
- HE_BITS(DATA1_UL_DL_KNOWN) |
- HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
- HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-
- he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
- HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
- break;
- case MT_PHY_TYPE_HE_EXT_SU:
- he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
- HE_BITS(DATA1_UL_DL_KNOWN) |
- HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-
- he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
- break;
- case MT_PHY_TYPE_HE_MU:
- he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
- HE_BITS(DATA1_UL_DL_KNOWN);
-
- he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
- he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
-
- mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
- mt7996_mac_decode_he_mu_radiotap(skb, rxv);
- break;
- case MT_PHY_TYPE_HE_TB:
- he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
- HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
- HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
- HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
-
- he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
- HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
- HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
- HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
-
- mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
- break;
- default:
- break;
- }
-}
-
/* The HW does not translate the mac header to 802.3 for mesh point */
static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
{
@@ -681,10 +503,11 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
struct mt7996_sta *msta;
msta = container_of(status->wcid, struct mt7996_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
status->freq = mphy->chandef.chan->center_freq;
@@ -836,14 +659,19 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
skb_pull(skb, hdr_gap);
if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
pad_start = ieee80211_get_hdrlen_from_skb(skb);
- } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR) &&
- get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) {
+ } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
/* When header translation failure is indicated,
* the hardware will insert an extra 2-byte field
* containing the data length after the protocol
- * type field.
+ * type field. This happens either when the LLC-SNAP
+ * pattern did not match, or if a VLAN header was
+ * detected.
*/
- pad_start = 16;
+ pad_start = 12;
+ if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
+ pad_start += 4;
+ else
+ pad_start = 0;
}
if (pad_start) {
@@ -881,7 +709,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
}
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
- mt7996_mac_decode_he_radiotap(skb, rxv, mode);
+ mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
if (!status->wcid || !ieee80211_is_data_qos(fc))
return 0;
@@ -1007,7 +835,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
- struct mt7996_vif *mvif;
+ struct mt76_vif *mvif;
u16 tx_count = 15;
u32 val;
bool beacon = !!(changed & (BSS_CHANGED_BEACON |
@@ -1015,11 +843,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
BSS_CHANGED_FILS_DISCOVERY));
- mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
+ mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
if (mvif) {
- omac_idx = mvif->mt76.omac_idx;
- wmm_idx = mvif->mt76.wmm_idx;
- band_idx = mvif->mt76.band_idx;
+ omac_idx = mvif->omac_idx;
+ wmm_idx = mvif->wmm_idx;
+ band_idx = mvif->band_idx;
}
if (inband_disc) {
@@ -1198,7 +1026,7 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
return;
msta = (struct mt7996_sta *)sta->drv_priv;
- if (!test_and_set_bit(tid, &msta->ampdu_state))
+ if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
}
@@ -1286,10 +1114,11 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
continue;
msta = container_of(wcid, struct mt7996_sta, wcid);
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list,
+ &mdev->sta_poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
continue;
}
@@ -1324,9 +1153,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
}
static bool
-mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
- __le32 *txs_data, struct mt76_sta_stats *stats)
+mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
+ int pid, __le32 *txs_data)
{
+ struct mt76_sta_stats *stats = &wcid->stats;
struct ieee80211_supported_band *sband;
struct mt76_dev *mdev = &dev->mt76;
struct mt76_phy *mphy;
@@ -1488,15 +1318,15 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
msta = container_of(wcid, struct mt7996_sta, wcid);
- mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
+ mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
if (!wcid->sta)
goto out;
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&msta->wcid.poll_list))
+ list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
out:
rcu_read_unlock();
@@ -1609,20 +1439,19 @@ void mt7996_mac_reset_counters(struct mt7996_phy *phy)
mt7996_mcu_get_chan_mib_info(phy, true);
}
-void mt7996_mac_set_timing(struct mt7996_phy *phy)
+void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
{
s16 coverage_class = phy->coverage_class;
struct mt7996_dev *dev = phy->dev;
struct mt7996_phy *phy2 = mt7996_phy2(dev);
struct mt7996_phy *phy3 = mt7996_phy3(dev);
- u32 val, reg_offset;
+ u32 reg_offset;
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
u8 band_idx = phy->mt76->band_idx;
int offset;
- bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
return;
@@ -1635,34 +1464,12 @@ void mt7996_mac_set_timing(struct mt7996_phy *phy)
coverage_class = max_t(s16, coverage_class,
phy3->coverage_class);
- mt76_set(dev, MT_ARB_SCR(band_idx),
- MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
- udelay(1);
-
offset = 3 * coverage_class;
reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
- mt76_wr(dev, MT_TMAC_ICR0(band_idx),
- FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
- FIELD_PREP(MT_IFS_RIFS, 2) |
- FIELD_PREP(MT_IFS_SIFS, 10) |
- FIELD_PREP(MT_IFS_SLOT, phy->slottime));
-
- if (!a_band)
- mt76_wr(dev, MT_TMAC_ICR1(band_idx),
- FIELD_PREP(MT_IFS_EIFS_CCK, 314));
-
- if (phy->slottime < 20 || a_band)
- val = MT7996_CFEND_RATE_DEFAULT;
- else
- val = MT7996_CFEND_RATE_11B;
-
- mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
- mt76_clear(dev, MT_ARB_SCR(band_idx),
- MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
}
void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
@@ -2046,6 +1853,12 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
}
+ mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
+ mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
+
+ /* enable DMA Tx/Tx and interrupt */
+ mt7996_dma_start(dev, false);
+
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
if (phy2)
@@ -2062,9 +1875,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
tasklet_schedule(&dev->mt76.irq_tasklet);
- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
- mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
-
mt76_worker_enable(&dev->mt76.tx_worker);
local_bh_disable();
@@ -2191,8 +2001,8 @@ void mt7996_reset(struct mt7996_dev *dev)
void mt7996_mac_update_stats(struct mt7996_phy *phy)
{
+ struct mt76_mib_stats *mib = &phy->mib;
struct mt7996_dev *dev = phy->dev;
- struct mib_stats *mib = &phy->mib;
u8 band_idx = phy->mt76->band_idx;
u32 cnt;
int i;
@@ -2339,7 +2149,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
u32 changed;
LIST_HEAD(list);
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
list_splice_init(&dev->sta_rc_list, &list);
while (!list_empty(&list)) {
@@ -2347,7 +2157,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
list_del_init(&msta->rc_list);
changed = msta->changed;
msta->changed = 0;
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
@@ -2359,10 +2169,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
/* TODO: smps change */
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
}
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
void mt7996_mac_work(struct work_struct *work)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.h b/drivers/net/wireless/mediatek/mt76/mt7996/mac.h
index bc4e6c55373e..e629324a5617 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.h
@@ -6,320 +6,7 @@
#ifndef __MT7996_MAC_H
#define __MT7996_MAC_H
-#define MT_CT_PARSE_LEN 72
-#define MT_CT_DMA_BUF_NUM 2
-
-#define MT_RXD0_LENGTH GENMASK(15, 0)
-#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
-
-#define MT_RXD0_MESH BIT(18)
-#define MT_RXD0_MHCP BIT(19)
-#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
-#define MT_RXD0_NORMAL_IP_SUM BIT(23)
-#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
-
-#define MT_RXD0_SW_PKT_TYPE_MASK GENMASK(31, 16)
-#define MT_RXD0_SW_PKT_TYPE_MAP 0x380F
-#define MT_RXD0_SW_PKT_TYPE_FRAME 0x3801
-
-/* RXD DW1 */
-#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(11, 0)
-#define MT_RXD1_NORMAL_GROUP_1 BIT(16)
-#define MT_RXD1_NORMAL_GROUP_2 BIT(17)
-#define MT_RXD1_NORMAL_GROUP_3 BIT(18)
-#define MT_RXD1_NORMAL_GROUP_4 BIT(19)
-#define MT_RXD1_NORMAL_GROUP_5 BIT(20)
-#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21)
-#define MT_RXD1_NORMAL_CM BIT(23)
-#define MT_RXD1_NORMAL_CLM BIT(24)
-#define MT_RXD1_NORMAL_ICV_ERR BIT(25)
-#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26)
-#define MT_RXD1_NORMAL_BAND_IDX GENMASK(28, 27)
-#define MT_RXD1_NORMAL_SPP_EN BIT(29)
-#define MT_RXD1_NORMAL_ADD_OM BIT(30)
-#define MT_RXD1_NORMAL_SEC_DONE BIT(31)
-
-/* RXD DW2 */
-#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0)
-#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8)
-#define MT_RXD2_NORMAL_HDR_TRANS BIT(7)
-#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 13)
-#define MT_RXD2_NORMAL_SEC_MODE GENMASK(20, 16)
-#define MT_RXD2_NORMAL_MU_BAR BIT(21)
-#define MT_RXD2_NORMAL_SW_BIT BIT(22)
-#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23)
-#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24)
-#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25)
-#define MT_RXD2_NORMAL_INT_FRAME BIT(26)
-#define MT_RXD2_NORMAL_FRAG BIT(27)
-#define MT_RXD2_NORMAL_NULL_FRAME BIT(28)
-#define MT_RXD2_NORMAL_NDATA BIT(29)
-#define MT_RXD2_NORMAL_NON_AMPDU BIT(30)
-#define MT_RXD2_NORMAL_BF_REPORT BIT(31)
-
-/* RXD DW3 */
-#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0)
-#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8)
-#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16)
-#define MT_RXD3_NORMAL_U2M BIT(0)
-#define MT_RXD3_NORMAL_HTC_VLD BIT(18)
-#define MT_RXD3_NORMAL_BEACON_MC BIT(20)
-#define MT_RXD3_NORMAL_BEACON_UC BIT(21)
-#define MT_RXD3_NORMAL_CO_ANT BIT(22)
-#define MT_RXD3_NORMAL_FCS_ERR BIT(24)
-#define MT_RXD3_NORMAL_VLAN2ETH BIT(31)
-
-/* RXD DW4 */
-#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0)
-#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0)
-#define MT_RXD4_MID_AMSDU_FRAME BIT(1)
-#define MT_RXD4_LAST_AMSDU_FRAME BIT(0)
-
-#define MT_RXV_HDR_BAND_IDX BIT(24)
-
-/* RXD GROUP4 */
-#define MT_RXD8_FRAME_CONTROL GENMASK(15, 0)
-
-#define MT_RXD10_SEQ_CTRL GENMASK(15, 0)
-#define MT_RXD10_QOS_CTL GENMASK(31, 16)
-
-#define MT_RXD11_HT_CONTROL GENMASK(31, 0)
-
-/* P-RXV */
-#define MT_PRXV_TX_RATE GENMASK(6, 0)
-#define MT_PRXV_TX_DCM BIT(4)
-#define MT_PRXV_TX_ER_SU_106T BIT(5)
-#define MT_PRXV_NSTS GENMASK(10, 7)
-#define MT_PRXV_TXBF BIT(11)
-#define MT_PRXV_HT_AD_CODE BIT(12)
-#define MT_PRXV_HE_RU_ALLOC GENMASK(30, 22)
-#define MT_PRXV_RCPI3 GENMASK(31, 24)
-#define MT_PRXV_RCPI2 GENMASK(23, 16)
-#define MT_PRXV_RCPI1 GENMASK(15, 8)
-#define MT_PRXV_RCPI0 GENMASK(7, 0)
-#define MT_PRXV_HT_SHORT_GI GENMASK(4, 3)
-#define MT_PRXV_HT_STBC GENMASK(10, 9)
-#define MT_PRXV_TX_MODE GENMASK(14, 11)
-#define MT_PRXV_FRAME_MODE GENMASK(2, 0)
-#define MT_PRXV_DCM BIT(5)
-
-/* C-RXV */
-#define MT_CRXV_HE_NUM_USER GENMASK(26, 20)
-#define MT_CRXV_HE_LTF_SIZE GENMASK(28, 27)
-#define MT_CRXV_HE_LDPC_EXT_SYM BIT(30)
-
-#define MT_CRXV_HE_PE_DISAMBIG BIT(1)
-#define MT_CRXV_HE_UPLINK BIT(2)
-
-#define MT_CRXV_HE_MU_AID GENMASK(27, 17)
-#define MT_CRXV_HE_BEAM_CHNG BIT(29)
-
-#define MT_CRXV_HE_DOPPLER BIT(0)
-#define MT_CRXV_HE_BSS_COLOR GENMASK(15, 10)
-#define MT_CRXV_HE_TXOP_DUR GENMASK(19, 17)
-
-#define MT_CRXV_HE_SR_MASK GENMASK(11, 8)
-#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12)
-#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17)
-#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21)
-
-#define MT_CRXV_HE_RU0 GENMASK(8, 0)
-#define MT_CRXV_HE_RU1 GENMASK(17, 9)
-#define MT_CRXV_HE_RU2 GENMASK(26, 18)
-#define MT_CRXV_HE_RU3_L GENMASK(31, 27)
-#define MT_CRXV_HE_RU3_H GENMASK(3, 0)
-
-enum tx_header_format {
- MT_HDR_FORMAT_802_3,
- MT_HDR_FORMAT_CMD,
- MT_HDR_FORMAT_802_11,
- MT_HDR_FORMAT_802_11_EXT,
-};
-
-enum tx_pkt_type {
- MT_TX_TYPE_CT,
- MT_TX_TYPE_SF,
- MT_TX_TYPE_CMD,
- MT_TX_TYPE_FW,
-};
-
-enum tx_port_idx {
- MT_TX_PORT_IDX_LMAC,
- MT_TX_PORT_IDX_MCU
-};
-
-enum tx_mcu_port_q_idx {
- MT_TX_MCU_PORT_RX_Q0 = 0x20,
- MT_TX_MCU_PORT_RX_Q1,
- MT_TX_MCU_PORT_RX_Q2,
- MT_TX_MCU_PORT_RX_Q3,
- MT_TX_MCU_PORT_RX_FWDL = 0x3e
-};
-
-enum tx_mgnt_type {
- MT_TX_NORMAL,
- MT_TX_TIMING,
- MT_TX_ADDBA,
-};
-
-#define MT_CT_INFO_APPLY_TXD BIT(0)
-#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1)
-#define MT_CT_INFO_MGMT_FRAME BIT(2)
-#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3)
-#define MT_CT_INFO_HSR2_TX BIT(4)
-#define MT_CT_INFO_FROM_HOST BIT(7)
-
-#define MT_TXD_SIZE (8 * 4)
-
-#define MT_TXD0_Q_IDX GENMASK(31, 25)
-#define MT_TXD0_PKT_FMT GENMASK(24, 23)
-#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
-#define MT_TXD0_TX_BYTES GENMASK(15, 0)
-
-#define MT_TXD1_FIXED_RATE BIT(31)
-#define MT_TXD1_OWN_MAC GENMASK(30, 25)
-#define MT_TXD1_TID GENMASK(24, 21)
-#define MT_TXD1_BIP BIT(24)
-#define MT_TXD1_ETH_802_3 BIT(20)
-#define MT_TXD1_HDR_INFO GENMASK(20, 16)
-#define MT_TXD1_HDR_FORMAT GENMASK(15, 14)
-#define MT_TXD1_TGID GENMASK(13, 12)
-#define MT_TXD1_WLAN_IDX GENMASK(11, 0)
-
-#define MT_TXD2_POWER_OFFSET GENMASK(31, 26)
-#define MT_TXD2_MAX_TX_TIME GENMASK(25, 16)
-#define MT_TXD2_FRAG GENMASK(15, 14)
-#define MT_TXD2_HTC_VLD BIT(13)
-#define MT_TXD2_DURATION BIT(12)
-#define MT_TXD2_HDR_PAD GENMASK(11, 10)
-#define MT_TXD2_RTS BIT(9)
-#define MT_TXD2_OWN_MAC_MAP BIT(8)
-#define MT_TXD2_BF_TYPE GENMASK(6, 7)
-#define MT_TXD2_FRAME_TYPE GENMASK(5, 4)
-#define MT_TXD2_SUB_TYPE GENMASK(3, 0)
-
-#define MT_TXD3_SN_VALID BIT(31)
-#define MT_TXD3_PN_VALID BIT(30)
-#define MT_TXD3_SW_POWER_MGMT BIT(29)
-#define MT_TXD3_BA_DISABLE BIT(28)
-#define MT_TXD3_SEQ GENMASK(27, 16)
-#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11)
-#define MT_TXD3_TX_COUNT GENMASK(10, 6)
-#define MT_TXD3_HW_AMSDU BIT(5)
-#define MT_TXD3_BCM BIT(4)
-#define MT_TXD3_EEOSP BIT(3)
-#define MT_TXD3_EMRD BIT(2)
-#define MT_TXD3_PROTECT_FRAME BIT(1)
-#define MT_TXD3_NO_ACK BIT(0)
-
-#define MT_TXD4_PN_LOW GENMASK(31, 0)
-
-#define MT_TXD5_PN_HIGH GENMASK(31, 16)
-#define MT_TXD5_FL BIT(15)
-#define MT_TXD5_BYPASS_TBB BIT(14)
-#define MT_TXD5_BYPASS_RBB BIT(13)
-#define MT_TXD5_BSS_COLOR_ZERO BIT(12)
-#define MT_TXD5_TX_STATUS_HOST BIT(10)
-#define MT_TXD5_TX_STATUS_MCU BIT(9)
-#define MT_TXD5_TX_STATUS_FMT BIT(8)
-#define MT_TXD5_PID GENMASK(7, 0)
-
-#define MT_TXD6_TX_SRC GENMASK(31, 30)
-#define MT_TXD6_VTA BIT(28)
-#define MT_TXD6_BW GENMASK(25, 22)
-#define MT_TXD6_TX_RATE GENMASK(21, 16)
-#define MT_TXD6_TIMESTAMP_OFS_EN BIT(15)
-#define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10)
-#define MT_TXD6_MSDU_CNT GENMASK(9, 4)
-#define MT_TXD6_DIS_MAT BIT(3)
-#define MT_TXD6_DAS BIT(2)
-#define MT_TXD6_AMSDU_CAP BIT(1)
-
-#define MT_TXD7_TXD_LEN GENMASK(31, 30)
-#define MT_TXD7_IP_SUM BIT(29)
-#define MT_TXD7_DROP_BY_SDO BIT(28)
-#define MT_TXD7_MAC_TXD BIT(27)
-#define MT_TXD7_CTXD BIT(26)
-#define MT_TXD7_CTXD_CNT GENMASK(25, 22)
-#define MT_TXD7_UDP_TCP_SUM BIT(15)
-#define MT_TXD7_TX_TIME GENMASK(9, 0)
-
-#define MT_TX_RATE_STBC BIT(14)
-#define MT_TX_RATE_NSS GENMASK(13, 10)
-#define MT_TX_RATE_MODE GENMASK(9, 6)
-#define MT_TX_RATE_SU_EXT_TONE BIT(5)
-#define MT_TX_RATE_DCM BIT(4)
-/* VHT/HE only use bits 0-3 */
-#define MT_TX_RATE_IDX GENMASK(5, 0)
-
-#define MT_TXFREE0_PKT_TYPE GENMASK(31, 27)
-#define MT_TXFREE0_MSDU_CNT GENMASK(25, 16)
-#define MT_TXFREE0_RX_BYTE GENMASK(15, 0)
-
-#define MT_TXFREE1_VER GENMASK(18, 16)
-
-#define MT_TXFREE_INFO_PAIR BIT(31)
-#define MT_TXFREE_INFO_HEADER BIT(30)
-#define MT_TXFREE_INFO_WLAN_ID GENMASK(23, 12)
-#define MT_TXFREE_INFO_MSDU_ID GENMASK(14, 0)
-
-#define MT_TXS0_BW GENMASK(31, 29)
-#define MT_TXS0_TID GENMASK(28, 26)
-#define MT_TXS0_AMPDU BIT(25)
-#define MT_TXS0_TXS_FORMAT GENMASK(24, 23)
-#define MT_TXS0_BA_ERROR BIT(22)
-#define MT_TXS0_PS_FLAG BIT(21)
-#define MT_TXS0_TXOP_TIMEOUT BIT(20)
-#define MT_TXS0_BIP_ERROR BIT(19)
-
-#define MT_TXS0_QUEUE_TIMEOUT BIT(18)
-#define MT_TXS0_RTS_TIMEOUT BIT(17)
-#define MT_TXS0_ACK_TIMEOUT BIT(16)
-#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
-
-#define MT_TXS0_TX_STATUS_HOST BIT(15)
-#define MT_TXS0_TX_STATUS_MCU BIT(14)
-#define MT_TXS0_TX_RATE GENMASK(13, 0)
-
-#define MT_TXS1_SEQNO GENMASK(31, 20)
-#define MT_TXS1_RESP_RATE GENMASK(19, 16)
-#define MT_TXS1_RXV_SEQNO GENMASK(15, 8)
-#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0)
-
-#define MT_TXS2_BF_STATUS GENMASK(31, 30)
-#define MT_TXS2_BAND GENMASK(29, 28)
-#define MT_TXS2_WCID GENMASK(27, 16)
-#define MT_TXS2_TX_DELAY GENMASK(15, 0)
-
-#define MT_TXS3_PID GENMASK(31, 24)
-#define MT_TXS3_RATE_STBC BIT(7)
-#define MT_TXS3_FIXED_RATE BIT(6)
-#define MT_TXS3_SRC GENMASK(5, 4)
-#define MT_TXS3_SHARED_ANTENNA BIT(3)
-#define MT_TXS3_LAST_TX_RATE GENMASK(2, 0)
-
-#define MT_TXS4_TIMESTAMP GENMASK(31, 0)
-
-#define MT_TXS5_F0_FINAL_MPDU BIT(31)
-#define MT_TXS5_F0_QOS BIT(30)
-#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25)
-#define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0)
-#define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24)
-#define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0)
-
-#define MT_TXS6_F0_NOISE_3 GENMASK(31, 24)
-#define MT_TXS6_F0_NOISE_2 GENMASK(23, 16)
-#define MT_TXS6_F0_NOISE_1 GENMASK(15, 8)
-#define MT_TXS6_F0_NOISE_0 GENMASK(7, 0)
-#define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24)
-#define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0)
-
-#define MT_TXS7_F0_RCPI_3 GENMASK(31, 24)
-#define MT_TXS7_F0_RCPI_2 GENMASK(23, 16)
-#define MT_TXS7_F0_RCPI_1 GENMASK(15, 8)
-#define MT_TXS7_F0_RCPI_0 GENMASK(7, 0)
-#define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24)
-#define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0)
+#include "../mt76_connac3_mac.h"
struct mt7996_dfs_pulse {
u32 max_width; /* us */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index f306e9c50ea3..c3a479dc3f53 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -43,6 +43,10 @@ int mt7996_run(struct ieee80211_hw *hw)
if (ret)
goto out;
+ ret = mt7996_mcu_set_radio_en(phy, true);
+ if (ret)
+ goto out;
+
ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
if (ret)
goto out;
@@ -82,6 +86,8 @@ static void mt7996_stop(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
+ mt7996_mcu_set_radio_en(phy, false);
+
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
mutex_unlock(&dev->mt76.mutex);
@@ -190,17 +196,13 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out;
- ret = mt7996_mcu_set_radio_en(phy, true);
- if (ret)
- goto out;
-
dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
idx = MT7996_WTBL_RESERVED - mvif->mt76.idx;
INIT_LIST_HEAD(&mvif->sta.rc_list);
- INIT_LIST_HEAD(&mvif->sta.poll_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.phy_idx = band_idx;
mvif->sta.wcid.hw_key_idx = -1;
@@ -221,9 +223,9 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
- mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
+ mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
else
- mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL;
+ mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
mt7996_init_bitrate_mask(vif);
@@ -253,7 +255,6 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
phy->monitor_vif = NULL;
mt7996_mcu_add_dev_info(phy, vif, false);
- mt7996_mcu_set_radio_en(phy, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
@@ -262,10 +263,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
mutex_unlock(&dev->mt76.mutex);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
mt76_packet_id_flush(&dev->mt76, &msta->wcid);
}
@@ -286,7 +287,6 @@ int mt7996_set_channel(struct mt7996_phy *phy)
if (ret)
goto out;
- mt7996_mac_set_timing(phy);
ret = mt7996_dfs_init_radar_detector(phy);
mt7996_mac_cca_stats_reset(phy);
@@ -505,7 +505,7 @@ static u8
mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
struct mt76_phy *mphy = hw->priv;
u16 rate;
u8 i, idx, ht;
@@ -517,7 +517,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct mt7996_dev *dev = mt7996_hw_dev(hw);
/* must odd index */
- idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->mt76.idx % 20);
+ idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
mt7996_mac_set_fixed_rate_table(dev, idx, rate);
return idx;
}
@@ -530,12 +530,32 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return mvif->basic_rates_idx;
}
+static void
+mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ u8 band = mvif->mt76.band_idx;
+ u32 *mu;
+
+ mu = (u32 *)info->mu_group.membership;
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]);
+
+ mu = (u32 *)info->mu_group.position;
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]);
+}
+
static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u64 changed)
{
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_dev *dev = mt7996_hw_dev(hw);
@@ -563,7 +583,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
if (slottime != phy->slottime) {
phy->slottime = slottime;
- mt7996_mac_set_timing(phy);
+ mt7996_mcu_set_timing(phy, vif);
}
}
@@ -602,6 +622,9 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
changed & BSS_CHANGED_FILS_DISCOVERY)
mt7996_mcu_beacon_inband_discov(dev, vif, changed);
+ if (changed & BSS_CHANGED_MU_GROUPS)
+ mt7996_update_mu_group(hw, vif, info);
+
mutex_unlock(&dev->mt76.mutex);
}
@@ -631,7 +654,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
return -ENOSPC;
INIT_LIST_HEAD(&msta->rc_list);
- INIT_LIST_HEAD(&msta->poll_list);
+ INIT_LIST_HEAD(&msta->wcid.poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
@@ -666,12 +689,12 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
mt7996_mac_twt_teardown_flow(dev, msta, i);
- spin_lock_bh(&dev->sta_poll_lock);
- if (!list_empty(&msta->poll_list))
- list_del_init(&msta->poll_list);
+ spin_lock_bh(&mdev->sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+ list_del_init(&msta->wcid.poll_list);
if (!list_empty(&msta->rc_list))
list_del_init(&msta->rc_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&mdev->sta_poll_lock);
}
static void mt7996_tx(struct ieee80211_hw *hw,
@@ -751,16 +774,16 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
ret = mt7996_mcu_add_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
- set_bit(tid, &msta->ampdu_state);
+ set_bit(tid, &msta->wcid.ampdu_state);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
- clear_bit(tid, &msta->ampdu_state);
+ clear_bit(tid, &msta->wcid.ampdu_state);
ret = mt7996_mcu_add_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
@@ -792,7 +815,7 @@ mt7996_get_stats(struct ieee80211_hw *hw,
{
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_dev *dev = mt7996_hw_dev(hw);
- struct mib_stats *mib = &phy->mib;
+ struct mt76_mib_stats *mib = &phy->mib;
mutex_lock(&dev->mt76.mutex);
@@ -903,7 +926,7 @@ mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
mutex_lock(&dev->mt76.mutex);
phy->coverage_class = max_t(s16, coverage_class, 0);
- mt7996_mac_set_timing(phy);
+ mt7996_mac_set_coverage_class(phy);
mutex_unlock(&dev->mt76.mutex);
}
@@ -952,18 +975,19 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct rate_info *txrate = &msta->wcid.rate;
- if (!txrate->legacy && !txrate->flags)
- return;
-
- if (txrate->legacy) {
- sinfo->txrate.legacy = txrate->legacy;
- } else {
- sinfo->txrate.mcs = txrate->mcs;
- sinfo->txrate.nss = txrate->nss;
- sinfo->txrate.bw = txrate->bw;
- sinfo->txrate.he_gi = txrate->he_gi;
- sinfo->txrate.he_dcm = txrate->he_dcm;
- sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ if (txrate->legacy || txrate->flags) {
+ if (txrate->legacy) {
+ sinfo->txrate.legacy = txrate->legacy;
+ } else {
+ sinfo->txrate.mcs = txrate->mcs;
+ sinfo->txrate.nss = txrate->nss;
+ sinfo->txrate.bw = txrate->bw;
+ sinfo->txrate.he_gi = txrate->he_gi;
+ sinfo->txrate.he_dcm = txrate->he_dcm;
+ sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ }
+ sinfo->txrate.flags = txrate->flags;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
@@ -981,11 +1005,11 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
struct mt7996_dev *dev = msta->vif->phy->dev;
u32 *changed = data;
- spin_lock_bh(&dev->sta_poll_lock);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
msta->changed |= *changed;
if (list_empty(&msta->rc_list))
list_add_tail(&msta->rc_list, &dev->sta_rc_list);
- spin_unlock_bh(&dev->sta_poll_lock);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
}
static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
@@ -1153,6 +1177,10 @@ static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = {
"v_tx_mcs_11",
"v_tx_mcs_12",
"v_tx_mcs_13",
+ "v_tx_nss_1",
+ "v_tx_nss_2",
+ "v_tx_nss_3",
+ "v_tx_nss_4",
};
#define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats)
@@ -1186,7 +1214,7 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
if (msta->vif->mt76.idx != wi->idx)
return;
- mt76_ethtool_worker(wi, &msta->stats, true);
+ mt76_ethtool_worker(wi, &msta->wcid.stats, true);
}
static
@@ -1197,11 +1225,11 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw,
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt76_mib_stats *mib = &phy->mib;
struct mt76_ethtool_worker_info wi = {
.data = data,
.idx = mvif->mt76.idx,
};
- struct mib_stats *mib = &phy->mib;
/* See mt7996_ampdu_stat_read_phy, etc */
int i, ei = 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 88e2f9d0e513..4a30db49ef33 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -339,7 +339,11 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys))
return;
- mphy = dev->mt76.phys[r->band_idx];
+ if (dev->rdd2_phy && r->band_idx == MT_RX_SEL2)
+ mphy = dev->rdd2_phy->mt76;
+ else
+ mphy = dev->mt76.phys[r->band_idx];
+
if (!mphy)
return;
@@ -600,7 +604,7 @@ static void
mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
struct mt7996_phy *phy)
{
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
struct bss_rate_tlv *bmc;
struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
enum nl80211_band band = chandef->chan->band;
@@ -701,6 +705,34 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
sizeof(req), true);
}
+static void
+mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_phy *phy = mvif->phy;
+ struct bss_ifs_time_tlv *ifs_time;
+ struct tlv *tlv;
+ bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));
+
+ ifs_time = (struct bss_ifs_time_tlv *)tlv;
+ ifs_time->slot_valid = true;
+ ifs_time->sifs_valid = true;
+ ifs_time->rifs_valid = true;
+ ifs_time->eifs_valid = true;
+
+ ifs_time->slot_time = cpu_to_le16(phy->slottime);
+ ifs_time->sifs_time = cpu_to_le16(10);
+ ifs_time->rifs_time = cpu_to_le16(2);
+ ifs_time->eifs_time = cpu_to_le16(is_2ghz ? 78 : 84);
+
+ if (is_2ghz) {
+ ifs_time->eifs_cck_valid = true;
+ ifs_time->eifs_cck_time = cpu_to_le16(314);
+ }
+}
+
static int
mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
@@ -712,6 +744,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
struct cfg80211_chan_def *chandef = &phy->chandef;
struct mt76_connac_bss_basic_tlv *bss;
u32 type = CONNECTION_INFRA_AP;
+ u16 sta_wlan_idx = wlan_idx;
struct tlv *tlv;
int idx;
@@ -731,7 +764,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
struct mt76_wcid *wcid;
wcid = (struct mt76_wcid *)sta->drv_priv;
- wlan_idx = wcid->idx;
+ sta_wlan_idx = wcid->idx;
}
rcu_read_unlock();
}
@@ -751,7 +784,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
bss->dtim_period = vif->bss_conf.dtim_period;
bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
- bss->sta_idx = cpu_to_le16(wlan_idx);
+ bss->sta_idx = cpu_to_le16(sta_wlan_idx);
bss->conn_type = cpu_to_le32(type);
bss->omac_idx = mvif->omac_idx;
bss->band_idx = mvif->band_idx;
@@ -825,6 +858,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
mt7996_mcu_bss_ra_tlv(skb, vif, phy);
mt7996_mcu_bss_txcmd_tlv(skb, true);
+ mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
if (vif->bss_conf.he_support)
mt7996_mcu_bss_he_tlv(skb, vif, phy);
@@ -837,6 +871,23 @@ out:
MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
}
+int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = phy->dev;
+ struct sk_buff *skb;
+
+ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
+ MT7996_BSS_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+}
+
static int
mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
struct ieee80211_ampdu_params *params,
@@ -1050,6 +1101,59 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
}
}
+static void
+mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+ struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
+ struct sta_rec_muru *muru;
+ struct tlv *tlv;
+
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
+
+ muru = (struct sta_rec_muru *)tlv;
+ muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer ||
+ vif->bss_conf.he_mu_beamformer ||
+ vif->bss_conf.vht_mu_beamformer ||
+ vif->bss_conf.vht_mu_beamformee;
+ muru->cfg.ofdma_dl_en = true;
+
+ if (sta->deflink.vht_cap.vht_supported)
+ muru->mimo_dl.vht_mu_bfee =
+ !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+
+ if (!sta->deflink.he_cap.has_he)
+ return;
+
+ muru->mimo_dl.partial_bw_dl_mimo =
+ HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
+
+ muru->mimo_ul.full_ul_mimo =
+ HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
+ muru->mimo_ul.partial_ul_mimo =
+ HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
+
+ muru->ofdma_dl.punc_pream_rx =
+ HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
+ muru->ofdma_dl.he_20m_in_40m_2g =
+ HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
+ muru->ofdma_dl.he_20m_in_160m =
+ HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
+ muru->ofdma_dl.he_80m_in_160m =
+ HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
+
+ muru->ofdma_ul.t_frame_dur =
+ HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
+ muru->ofdma_ul.mu_cascading =
+ HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
+ muru->ofdma_ul.uo_ra =
+ HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
+}
+
static inline bool
mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
@@ -1727,7 +1831,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mcu_sta_he_6g_tlv(skb, sta);
/* starec eht */
mt7996_mcu_sta_eht_tlv(skb, sta);
- /* TODO: starec muru */
+ /* starec muru */
+ mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta);
/* starec bfee */
mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
/* starec hdr trans */
@@ -2155,7 +2260,7 @@ out:
static int
mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
const struct mt7996_fw_trailer *hdr,
- const u8 *data, bool is_wa)
+ const u8 *data, enum mt7996_ram_type type)
{
int i, offset = 0;
u32 override = 0, option = 0;
@@ -2167,8 +2272,10 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
region = (const struct mt7996_fw_region *)((const u8 *)hdr -
(hdr->n_region - i) * sizeof(*region));
+ /* DSP and WA use same mode */
mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
- region->feature_set, is_wa);
+ region->feature_set,
+ type != MT7996_RAM_TYPE_WM);
len = le32_to_cpu(region->len);
addr = le32_to_cpu(region->addr);
@@ -2195,19 +2302,22 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
if (override)
option |= FW_START_OVERRIDE;
- if (is_wa)
+ if (type == MT7996_RAM_TYPE_WA)
option |= FW_START_WORKING_PDA_CR4;
+ else if (type == MT7996_RAM_TYPE_DSP)
+ option |= FW_START_WORKING_PDA_DSP;
return mt76_connac_mcu_start_firmware(&dev->mt76, override, option);
}
-static int mt7996_load_ram(struct mt7996_dev *dev)
+static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
+ const char *fw_file, enum mt7996_ram_type ram_type)
{
const struct mt7996_fw_trailer *hdr;
const struct firmware *fw;
int ret;
- ret = request_firmware(&fw, MT7996_FIRMWARE_WM, dev->mt76.dev);
+ ret = request_firmware(&fw, fw_file, dev->mt76.dev);
if (ret)
return ret;
@@ -2217,37 +2327,13 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
goto out;
}
- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
+ hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
+ dev_info(dev->mt76.dev, "%s Firmware Version: %.10s, Build Time: %.15s\n",
+ fw_type, hdr->fw_ver, hdr->build_date);
- dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
- hdr->fw_ver, hdr->build_date);
-
- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, false);
+ ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, ram_type);
if (ret) {
- dev_err(dev->mt76.dev, "Failed to start WM firmware\n");
- goto out;
- }
-
- release_firmware(fw);
-
- ret = request_firmware(&fw, MT7996_FIRMWARE_WA, dev->mt76.dev);
- if (ret)
- return ret;
-
- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
- dev_err(dev->mt76.dev, "Invalid firmware\n");
- ret = -EINVAL;
- goto out;
- }
-
- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
-
- dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n",
- hdr->fw_ver, hdr->build_date);
-
- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, true);
- if (ret) {
- dev_err(dev->mt76.dev, "Failed to start WA firmware\n");
+ dev_err(dev->mt76.dev, "Failed to start %s firmware\n", fw_type);
goto out;
}
@@ -2261,6 +2347,24 @@ out:
return ret;
}
+static int mt7996_load_ram(struct mt7996_dev *dev)
+{
+ int ret;
+
+ ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM,
+ MT7996_RAM_TYPE_WM);
+ if (ret)
+ return ret;
+
+ ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP,
+ MT7996_RAM_TYPE_DSP);
+ if (ret)
+ return ret;
+
+ return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA,
+ MT7996_RAM_TYPE_WA);
+}
+
static int
mt7996_firmware_state(struct mt7996_dev *dev, bool wa)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index d7075a4d0667..078f82858621 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -317,6 +317,22 @@ struct bss_sec_tlv {
u8 __rsv2[1];
} __packed;
+struct bss_ifs_time_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 slot_valid;
+ u8 sifs_valid;
+ u8 rifs_valid;
+ u8 eifs_valid;
+ __le16 slot_time;
+ __le16 sifs_time;
+ __le16 rifs_time;
+ __le16 eifs_time;
+ u8 eifs_cck_valid;
+ u8 rsv;
+ __le16 eifs_cck_time;
+} __packed;
+
struct bss_power_save {
__le16 tag;
__le16 len;
@@ -552,6 +568,7 @@ enum {
sizeof(struct bss_txcmd_tlv) + \
sizeof(struct bss_power_save) + \
sizeof(struct bss_sec_tlv) + \
+ sizeof(struct bss_ifs_time_tlv) + \
sizeof(struct bss_mld_tlv))
#define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 4d7dcb95a620..7354e5cf8e67 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -26,15 +26,17 @@
#define MT7996_RX_RING_SIZE 1536
#define MT7996_RX_MCU_RING_SIZE 512
+#define MT7996_RX_MCU_RING_SIZE_WA 1024
#define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
#define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
+#define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
#define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
#define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
-#define MT7996_TOKEN_SIZE 8192
+#define MT7996_TOKEN_SIZE 16384
#define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
@@ -52,6 +54,12 @@ struct mt7996_sta;
struct mt7996_dfs_pulse;
struct mt7996_dfs_pattern;
+enum mt7996_ram_type {
+ MT7996_RAM_TYPE_WM,
+ MT7996_RAM_TYPE_WA,
+ MT7996_RAM_TYPE_DSP,
+};
+
enum mt7996_txq_id {
MT7996_TXQ_FWDL = 16,
MT7996_TXQ_MCU_WM,
@@ -95,7 +103,6 @@ struct mt7996_sta {
struct mt7996_vif *vif;
- struct list_head poll_list;
struct list_head rc_list;
u32 airtime_ac[8];
@@ -104,9 +111,6 @@ struct mt7996_sta {
unsigned long changed;
unsigned long jiffies;
- unsigned long ampdu_state;
-
- struct mt76_sta_stats stats;
struct mt76_connac_sta_key_conf bip;
@@ -124,64 +128,6 @@ struct mt7996_vif {
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
struct cfg80211_bitrate_mask bitrate_mask;
-
- u8 basic_rates_idx;
- u8 mcast_rates_idx;
- u8 beacon_rates_idx;
-};
-
-/* per-phy stats. */
-struct mib_stats {
- u32 ack_fail_cnt;
- u32 fcs_err_cnt;
- u32 rts_cnt;
- u32 rts_retries_cnt;
- u32 ba_miss_cnt;
- u32 tx_mu_bf_cnt;
- u32 tx_mu_mpdu_cnt;
- u32 tx_mu_acked_mpdu_cnt;
- u32 tx_su_acked_mpdu_cnt;
- u32 tx_bf_ibf_ppdu_cnt;
- u32 tx_bf_ebf_ppdu_cnt;
-
- u32 tx_bf_rx_fb_all_cnt;
- u32 tx_bf_rx_fb_eht_cnt;
- u32 tx_bf_rx_fb_he_cnt;
- u32 tx_bf_rx_fb_vht_cnt;
- u32 tx_bf_rx_fb_ht_cnt;
-
- u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
- u32 tx_bf_rx_fb_nc_cnt;
- u32 tx_bf_rx_fb_nr_cnt;
- u32 tx_bf_fb_cpl_cnt;
- u32 tx_bf_fb_trig_cnt;
-
- u32 tx_ampdu_cnt;
- u32 tx_stop_q_empty_cnt;
- u32 tx_mpdu_attempts_cnt;
- u32 tx_mpdu_success_cnt;
- /* BF counter is PPDU-based, so remove MPDU-based BF counter */
-
- u32 tx_rwp_fail_cnt;
- u32 tx_rwp_need_cnt;
-
- /* rx stats */
- u32 rx_fifo_full_cnt;
- u32 channel_idle_cnt;
- u32 rx_vector_mismatch_cnt;
- u32 rx_delimiter_fail_cnt;
- u32 rx_len_mismatch_cnt;
- u32 rx_mpdu_cnt;
- u32 rx_ampdu_cnt;
- u32 rx_ampdu_bytes_cnt;
- u32 rx_ampdu_valid_subframe_cnt;
- u32 rx_ampdu_valid_subframe_bytes_cnt;
- u32 rx_pfdrop_cnt;
- u32 rx_vec_queue_overflow_drop_cnt;
- u32 rx_ba_cnt;
-
- u32 tx_amsdu[8];
- u32 tx_amsdu_cnt;
};
/* crash-dump */
@@ -222,7 +168,7 @@ struct mt7996_phy {
u32 rx_ampdu_ts;
u32 ampdu_ref;
- struct mib_stats mib;
+ struct mt76_mib_stats mib;
struct mt76_channel_state state_ts;
};
@@ -272,9 +218,7 @@ struct mt7996_dev {
#endif
struct list_head sta_rc_list;
- struct list_head sta_poll_list;
struct list_head twt_list;
- spinlock_t sta_poll_lock;
u32 hw_pattern;
@@ -311,20 +255,6 @@ enum {
};
enum {
- MT_CTX0,
- MT_HIF0 = 0x0,
-
- MT_LMAC_AC00 = 0x0,
- MT_LMAC_AC01,
- MT_LMAC_AC02,
- MT_LMAC_AC03,
- MT_LMAC_ALTX0 = 0x10,
- MT_LMAC_BMC0,
- MT_LMAC_BCN0,
- MT_LMAC_PSMP0,
-};
-
-enum {
MT_RX_SEL0,
MT_RX_SEL1,
MT_RX_SEL2, /* monitor chain */
@@ -405,6 +335,7 @@ int mt7996_dma_init(struct mt7996_dev *dev);
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
void mt7996_dma_cleanup(struct mt7996_dev *dev);
+void mt7996_dma_start(struct mt7996_dev *dev, bool reset);
void mt7996_init_txpower(struct mt7996_dev *dev,
struct ieee80211_supported_band *sband);
int mt7996_txbf_init(struct mt7996_dev *dev);
@@ -456,6 +387,7 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
const struct mt7996_dfs_pattern *pattern);
int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
u8 rx_sel, u8 val);
@@ -519,7 +451,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed);
-void mt7996_mac_set_timing(struct mt7996_phy *phy);
+void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index 64aee3fb5445..c5301050ff8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -219,4 +219,5 @@ MODULE_DEVICE_TABLE(pci, mt7996_pci_device_table);
MODULE_DEVICE_TABLE(pci, mt7996_hif_device_table);
MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
MODULE_FIRMWARE(MT7996_ROM_PATCH);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
index d1d3d154195d..97beab924517 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
@@ -557,22 +557,29 @@ enum base_rev {
#define MT_PCIE1_MAC_INT_ENABLE MT_PCIE1_MAC(0x188)
+/* PHYRX CSD */
+#define MT_WF_PHYRX_CSD_BASE 0x83000000
+#define MT_WF_PHYRX_CSD(_band, _wf, ofs) (MT_WF_PHYRX_CSD_BASE + \
+ ((_band) << 20) + \
+ ((_wf) << 16) + (ofs))
+#define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
+
/* PHYRX CTRL */
#define MT_WF_PHYRX_BAND_BASE 0x83080000
#define MT_WF_PHYRX_BAND(_band, ofs) (MT_WF_PHYRX_BAND_BASE + \
((_band) << 20) + (ofs))
+#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHYRX_BAND(_band, 0x1054)
+#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHYRX_BAND(_band, 0x1058)
+#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHYRX_BAND(_band, 0x105c)
+#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHYRX_BAND(_band, 0x1060)
+#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHYRX_BAND(_band, 0x1064)
+#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHYRX_BAND(_band, 0x1068)
+
#define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHYRX_BAND(_band, 0x2004)
#define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN GENMASK(2, 0)
#define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
-/* PHYRX CSD */
-#define MT_WF_PHYRX_CSD_BASE 0x83000000
-#define MT_WF_PHYRX_CSD(_band, _wf, ofs) (MT_WF_PHYRX_CSD_BASE + \
- ((_band) << 20) + \
- ((_wf) << 16) + (ofs))
-#define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
-
/* PHYRX CSD BAND */
#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHYRX_BAND(_band, 0x8230)
#define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index 0accc71a91c9..4644dace9bb3 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -8,6 +8,7 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_RESET] = { .type = NLA_FLAG },
[MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
+ [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
[MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 },
diff --git a/drivers/net/wireless/mediatek/mt76/trace.h b/drivers/net/wireless/mediatek/mt76/trace.h
index c3d0ef8e2890..109a07f9733a 100644
--- a/drivers/net/wireless/mediatek/mt76/trace.h
+++ b/drivers/net/wireless/mediatek/mt76/trace.h
@@ -14,7 +14,7 @@
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
-#define DEVICE_ASSIGN strlcpy(__entry->wiphy_name, \
+#define DEVICE_ASSIGN strscpy(__entry->wiphy_name, \
wiphy_name(dev->hw->wiphy), MAXNAME)
#define DEV_PR_FMT "%s"
#define DEV_PR_ARG __entry->wiphy_name
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 72b3ec715e47..6cc26cc6c517 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -121,6 +121,7 @@ int
mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct sk_buff *skb)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
int pid;
@@ -134,8 +135,14 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
return MT_PACKET_ID_NO_ACK;
if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
- IEEE80211_TX_CTL_RATE_CTRL_PROBE)))
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE))) {
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ||
+ ieee80211_is_data(hdr->frame_control)))
+ return MT_PACKET_ID_WED;
+
return MT_PACKET_ID_NO_SKB;
+ }
spin_lock_bh(&dev->status_lock);
@@ -263,8 +270,15 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
#endif
if (cb->pktid < MT_PACKET_ID_FIRST) {
+ struct ieee80211_rate_status rs = {};
+
hw = mt76_tx_status_get_hw(dev, skb);
status.sta = wcid_to_sta(wcid);
+ if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
+ rs.rate_idx = wcid->rate;
+ status.rates = &rs;
+ status.n_rates = 1;
+ }
spin_lock_bh(&dev->rx_lock);
ieee80211_tx_status_ext(hw, &status);
spin_unlock_bh(&dev->rx_lock);
diff --git a/drivers/net/wireless/mediatek/mt76/usb_trace.h b/drivers/net/wireless/mediatek/mt76/usb_trace.h
index f5ab3215af80..7b261ddb2ac6 100644
--- a/drivers/net/wireless/mediatek/mt76/usb_trace.h
+++ b/drivers/net/wireless/mediatek/mt76/usb_trace.h
@@ -14,7 +14,7 @@
#define MAXNAME 32
#define DEV_ENTRY __array(char, wiphy_name, 32)
-#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \
+#define DEV_ASSIGN strscpy(__entry->wiphy_name, \
wiphy_name(dev->hw->wiphy), MAXNAME)
#define DEV_PR_FMT "%s "
#define DEV_PR_ARG __entry->wiphy_name
diff --git a/drivers/net/wireless/mediatek/mt7601u/Kconfig b/drivers/net/wireless/mediatek/mt7601u/Kconfig
index 4a8b96280670..4880fc053d9d 100644
--- a/drivers/net/wireless/mediatek/mt7601u/Kconfig
+++ b/drivers/net/wireless/mediatek/mt7601u/Kconfig
@@ -4,4 +4,4 @@ config MT7601U
depends on MAC80211
depends on USB
help
- This adds support for MT7601U-based wireless USB dongles.
+ This adds support for MT7601U-based USB wireless dongles.
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
index 37b294cb3b37..8c65951cfaf9 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
@@ -8,15 +8,12 @@
#define WILC_CFG80211_H
#include "netdev.h"
-struct wiphy *wilc_cfg_alloc(void);
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);
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);
-struct wilc_vif *wilc_netdev_interface(struct wilc *wl, const char *name,
- enum nl80211_iftype type);
void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked);
struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
const char *name,
@@ -24,7 +21,6 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct mgmt_frame_regs *upd);
-struct wilc_vif *wilc_get_interface(struct wilc *wl);
struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
void wlan_deinit_locks(struct wilc *wilc);
#endif
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index a05bda7b9a3b..87948ba69a22 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -28,7 +28,6 @@ struct wilc_sdio {
bool irq_gpio;
u32 block_size;
bool isinit;
- int has_thrpt_enh3;
u8 *cmd53_buf;
};
@@ -722,21 +721,12 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
* make sure can read back chip id correctly
**/
if (!resume) {
- int rev;
-
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);
- rev = FIELD_GET(WILC_CHIP_REV_FIELD, chipid);
- if (rev > FIELD_GET(WILC_CHIP_REV_FIELD, WILC_1000_BASE_ID_2A))
- sdio_priv->has_thrpt_enh3 = 1;
- else
- sdio_priv->has_thrpt_enh3 = 0;
- dev_info(&func->dev, "has_thrpt_enh3 = %d...\n",
- sdio_priv->has_thrpt_enh3);
}
sdio_priv->isinit = true;
@@ -809,102 +799,29 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
struct wilc_sdio *sdio_priv = wilc->bus_data;
int ret;
- int vmm_ctl;
-
- if (sdio_priv->has_thrpt_enh3) {
- u32 reg = 0;
-
- 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 (reg) {
- struct sdio_cmd52 cmd;
-
- cmd.read_write = 1;
- cmd.function = 0;
- cmd.raw = 0;
- cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
- cmd.data = reg;
-
- ret = wilc_sdio_cmd52(wilc, &cmd);
- if (ret) {
- dev_err(&func->dev,
- "Failed cmd52, set (%02x) data (%d) ...\n",
- cmd.address, __LINE__);
- return ret;
- }
- }
- return 0;
- }
- if (sdio_priv->irq_gpio) {
- /* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
- /*
- * Cannot clear multiple interrupts.
- * Must clear each interrupt individually.
- */
- u32 flags;
- int i;
-
- flags = val & (BIT(MAX_NUM_INT) - 1);
- for (i = 0; i < NUM_INT_EXT && flags; i++) {
- if (flags & BIT(i)) {
- struct sdio_cmd52 cmd;
-
- cmd.read_write = 1;
- cmd.function = 0;
- cmd.raw = 0;
- cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
- cmd.data = BIT(i);
-
- ret = wilc_sdio_cmd52(wilc, &cmd);
- if (ret) {
- dev_err(&func->dev,
- "Failed cmd52, set (%02x) data (%d) ...\n",
- cmd.address, __LINE__);
- return ret;
- }
- flags &= ~BIT(i);
- }
- }
+ u32 reg = 0;
- for (i = NUM_INT_EXT; i < MAX_NUM_INT && flags; i++) {
- if (flags & BIT(i)) {
- dev_err(&func->dev,
- "Unexpected interrupt cleared %d...\n",
- i);
- flags &= ~BIT(i);
- }
- }
- }
+ if (sdio_priv->irq_gpio)
+ reg = val & (BIT(MAX_NUM_INT) - 1);
- vmm_ctl = 0;
/* select VMM table 0 */
if (val & SEL_VMM_TBL0)
- vmm_ctl |= BIT(0);
+ reg |= BIT(5);
/* select VMM table 1 */
if (val & SEL_VMM_TBL1)
- vmm_ctl |= BIT(1);
+ reg |= BIT(6);
/* enable VMM */
if (val & EN_VMM)
- vmm_ctl |= BIT(2);
-
- if (vmm_ctl) {
+ reg |= BIT(7);
+ if (reg) {
struct sdio_cmd52 cmd;
cmd.read_write = 1;
cmd.function = 0;
cmd.raw = 0;
- cmd.address = WILC_SDIO_VMM_TBL_CTRL_REG;
- cmd.data = vmm_ctl;
+ cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
+ cmd.data = reg;
+
ret = wilc_sdio_cmd52(wilc, &cmd);
if (ret) {
dev_err(&func->dev,
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index b0fc5e68feec..77b4cdff73c3 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -74,6 +74,7 @@ static int wilc_spi_reset(struct wilc *wilc);
#define CMD_SINGLE_READ 0xca
#define CMD_RESET 0xcf
+#define SPI_RETRY_MAX_LIMIT 10
#define SPI_ENABLE_VMM_RETRY_LIMIT 2
/* SPI response fields (section 11.1.2 in ATWILC1000 User Guide): */
@@ -830,59 +831,91 @@ static int wilc_spi_special_cmd(struct wilc *wilc, u8 cmd)
return 0;
}
+static void wilc_spi_reset_cmd_sequence(struct wilc *wl, u8 attempt, u32 addr)
+{
+ struct spi_device *spi = to_spi_device(wl->dev);
+ struct wilc_spi *spi_priv = wl->bus_data;
+
+ if (!spi_priv->probing_crc)
+ dev_err(&spi->dev, "Reset and retry %d %x\n", attempt, addr);
+
+ usleep_range(1000, 1100);
+ wilc_spi_reset(wl);
+ usleep_range(1000, 1100);
+}
+
static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
{
struct spi_device *spi = to_spi_device(wilc->dev);
int result;
u8 cmd = CMD_SINGLE_READ;
u8 clockless = 0;
+ u8 i;
- if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
+ if (addr <= WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
/* Clockless register */
cmd = CMD_INTERNAL_READ;
clockless = 1;
}
- result = wilc_spi_single_read(wilc, cmd, addr, data, clockless);
- if (result) {
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_single_read(wilc, cmd, addr, data, clockless);
+ if (!result) {
+ le32_to_cpus(data);
+ return 0;
+ }
+
+ /* retry is not applicable for clockless registers */
+ if (clockless)
+ break;
+
dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
- return result;
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
}
- le32_to_cpus(data);
-
- return 0;
+ return result;
}
static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct spi_device *spi = to_spi_device(wilc->dev);
int result;
+ u8 i;
if (size <= 4)
return -EINVAL;
- result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size);
- if (result) {
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr,
+ buf, size);
+ if (!result)
+ return 0;
+
dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
- return result;
+
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
}
- return 0;
+ return result;
}
static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat)
{
struct spi_device *spi = to_spi_device(wilc->dev);
int result;
+ u8 i;
- result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0);
- if (result) {
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr,
+ dat, 0);
+ if (!result)
+ return 0;
dev_err(&spi->dev, "Failed internal write cmd...\n");
- return result;
+
+ wilc_spi_reset_cmd_sequence(wilc, i, adr);
}
- return 0;
+ return result;
}
static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
@@ -890,17 +923,22 @@ static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
struct spi_device *spi = to_spi_device(wilc->dev);
struct wilc_spi *spi_priv = wilc->bus_data;
int result;
+ u8 i;
- result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0);
- if (result) {
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr,
+ data, 0);
+ if (!result) {
+ le32_to_cpus(data);
+ return 0;
+ }
if (!spi_priv->probing_crc)
dev_err(&spi->dev, "Failed internal read cmd...\n");
- return result;
- }
- le32_to_cpus(data);
+ wilc_spi_reset_cmd_sequence(wilc, i, adr);
+ }
- return 0;
+ return result;
}
/********************************************
@@ -915,20 +953,27 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
int result;
u8 cmd = CMD_SINGLE_WRITE;
u8 clockless = 0;
+ u8 i;
- if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
+ if (addr <= WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
/* Clockless register */
cmd = CMD_INTERNAL_WRITE;
clockless = 1;
}
- result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless);
- if (result) {
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless);
+ if (!result)
+ return 0;
+
dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr);
- return result;
- }
- return 0;
+ if (clockless)
+ break;
+
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
+ }
+ return result;
}
static int spi_data_rsp(struct wilc *wilc, u8 cmd)
@@ -981,6 +1026,7 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
{
struct spi_device *spi = to_spi_device(wilc->dev);
int result;
+ u8 i;
/*
* has to be greated than 4
@@ -988,26 +1034,38 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
if (size <= 4)
return -EINVAL;
- result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size);
- if (result) {
- dev_err(&spi->dev,
- "Failed cmd, write block (%08x)...\n", addr);
- return result;
- }
+ for (i = 0; i < SPI_RETRY_MAX_LIMIT; i++) {
+ result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr,
+ NULL, size);
+ if (result) {
+ dev_err(&spi->dev,
+ "Failed cmd, write block (%08x)...\n", addr);
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
+ continue;
+ }
- /*
- * Data
- */
- result = spi_data_write(wilc, buf, size);
- if (result) {
- dev_err(&spi->dev, "Failed block data write...\n");
- return result;
- }
+ /*
+ * Data
+ */
+ result = spi_data_write(wilc, buf, size);
+ if (result) {
+ dev_err(&spi->dev, "Failed block data write...\n");
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
+ continue;
+ }
- /*
- * Data response
- */
- return spi_data_rsp(wilc, CMD_DMA_EXT_WRITE);
+ /*
+ * Data response
+ */
+ result = spi_data_rsp(wilc, CMD_DMA_EXT_WRITE);
+ if (result) {
+ dev_err(&spi->dev, "Failed block data rsp...\n");
+ wilc_spi_reset_cmd_sequence(wilc, i, addr);
+ continue;
+ }
+ break;
+ }
+ return result;
}
/********************************************
diff --git a/drivers/net/wireless/purelifi/plfxlc/Kconfig b/drivers/net/wireless/purelifi/plfxlc/Kconfig
index 4e0be27a5e0e..dd5fca480d7e 100644
--- a/drivers/net/wireless/purelifi/plfxlc/Kconfig
+++ b/drivers/net/wireless/purelifi/plfxlc/Kconfig
@@ -3,7 +3,7 @@ config PLFXLC
tristate "pureLiFi X, XL, XC device support"
depends on CFG80211 && MAC80211 && USB
help
- This option adds support for pureLiFi LiFi wireless USB
+ This option adds support for pureLiFi LiFi USB wireless
adapters. The pureLiFi X, XL, XC USB devices are based on
802.11 OFDM PHY but uses light as the transmission medium.
The driver supports common 802.11 encryption/authentication
diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig
index dcccc290a7f5..d1fd66d44a7e 100644
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -170,7 +170,7 @@ config RT2800USB_RT35XX
config RT2800USB_RT3573
bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)"
help
- This enables support for RT3573 chipset based wireless USB devices
+ This enables support for RT3573 chipset based USB wireless devices
in the rt2800usb driver.
config RT2800USB_RT53XX
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 1226a883cd67..e65cc00fa17c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3865,28 +3865,51 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev,
}
}
-static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_channel *chan,
- int power_level) {
- u16 eeprom, target_power, max_power;
+static void rt2800_config_alc_rt6352(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_channel *chan,
+ int power_level)
+{
+ int cur_channel = rt2x00dev->rf_channel;
+ u16 eeprom, chan_power, rate_power, target_power;
+ u16 tx_power[2];
+ s8 *power_group[2];
u32 mac_sys_ctrl;
- u32 reg;
+ u32 cnt, reg;
u8 bbp;
- /* hardware unit is 0.5dBm, limited to 23.5dBm */
- power_level *= 2;
- if (power_level > 0x2f)
- power_level = 0x2f;
+ if (WARN_ON(cur_channel < 1 || cur_channel > 14))
+ return;
+
+ /* get per chain power, 2 chains in total, unit is 0.5dBm */
+ power_level = (power_level - 3) * 2;
- max_power = chan->max_power * 2;
- if (max_power > 0x2f)
- max_power = 0x2f;
+ /* We can't get the accurate TX power. Based on some tests, the real
+ * TX power is approximately equal to channel_power + (max)rate_power.
+ * Usually max rate_power is the gain of the OFDM 6M rate. The antenna
+ * gain and externel PA gain are not included as we are unable to
+ * obtain these values.
+ */
+ rate_power = rt2800_eeprom_read_from_array(rt2x00dev,
+ EEPROM_TXPOWER_BYRATE, 1);
+ rate_power &= 0x3f;
+ power_level -= rate_power;
+ if (power_level < 1)
+ power_level = 1;
+
+ power_group[0] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+ power_group[1] = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+ for (cnt = 0; cnt < 2; cnt++) {
+ chan_power = power_group[cnt][cur_channel - 1];
+ if (chan_power >= 0x20 || chan_power == 0)
+ chan_power = 0x10;
+ tx_power[cnt] = power_level < chan_power ? power_level : chan_power;
+ }
reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_0);
- rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, power_level);
- rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, power_level);
- rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, max_power);
- rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, max_power);
+ rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_0, tx_power[0]);
+ rt2x00_set_field32(&reg, TX_ALC_CFG_0_CH_INIT_1, tx_power[1]);
+ rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_0, 0x2f);
+ rt2x00_set_field32(&reg, TX_ALC_CFG_0_LIMIT_1, 0x2f);
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_INTERNAL_TX_ALC)) {
@@ -5268,7 +5291,7 @@ static void rt2800_config_txpower_rt6352(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&pwreg, TX_PWR_CFG_9B_STBC_MCS7, t);
rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, pwreg);
- rt2800_config_alc(rt2x00dev, chan, power_level);
+ rt2800_config_alc_rt6352(rt2x00dev, chan, power_level);
/* TODO: temperature compensation code! */
}
@@ -8561,7 +8584,7 @@ static void rt2800_r_calibration(struct rt2x00_dev *rt2x00dev)
rt2x00_warn(rt2x00dev, "Wait MAC Tx Status to MAX !!!\n");
maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
- maccfg &= (~0x04);
+ maccfg &= (~0x08);
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_RX)))
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
index f673aa9ba15a..47bcaec6f2db 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
@@ -1767,6 +1767,8 @@ struct rtl8xxxu_fileops rtl8192eu_fops = {
.has_s0s1 = 0,
.gen2_thermal_meter = 1,
.needs_full_init = 1,
+ .supports_ap = 1,
+ .max_macid_num = 128,
.adda_1t_init = 0x0fc01616,
.adda_1t_path_on = 0x0fc01616,
.adda_2t_path_on_a = 0x0fc01616,
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
index 18dc5221a9c0..28e93835e05a 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
@@ -2079,6 +2079,8 @@ struct rtl8xxxu_fileops rtl8192fu_fops = {
.ampdu_max_time = 0x5e,
.ustime_tsf_edca = 0x50,
.max_aggr_num = 0x1f1f,
+ .supports_ap = 1,
+ .max_macid_num = 128,
.trxff_boundary = 0x3f3f,
.pbp_rx = PBP_PAGE_SIZE_256,
.pbp_tx = PBP_PAGE_SIZE_256,
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c
index f0d17b75c5f1..871b8cca8a18 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c
@@ -1875,6 +1875,8 @@ struct rtl8xxxu_fileops rtl8710bu_fops = {
*/
.ustime_tsf_edca = 0x28,
.max_aggr_num = 0x0c14,
+ .supports_ap = 1,
+ .max_macid_num = 16,
.adda_1t_init = 0x03c00016,
.adda_1t_path_on = 0x03c00016,
.trxff_boundary = 0x3f7f,
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
index 13ad5d5b73f4..954369ed6226 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
@@ -1742,6 +1742,8 @@ struct rtl8xxxu_fileops rtl8723bu_fops = {
.ampdu_max_time = 0x5e,
.ustime_tsf_edca = 0x50,
.max_aggr_num = 0x0c14,
+ .supports_ap = 1,
+ .max_macid_num = 128,
.adda_1t_init = 0x01c00014,
.adda_1t_path_on = 0x01c00014,
.adda_2t_path_on_a = 0x01c00014,
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
index 4fb16f5f6f83..3835b639d453 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -1656,7 +1656,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
memcpy(rtlpriv->sec.key_buf[key_idx],
key->key, key->keylen);
rtlpriv->sec.key_len[key_idx] = key->keylen;
- memcpy(mac_addr, bcast_addr, ETH_ALEN);
+ eth_broadcast_addr(mac_addr);
} else { /* pairwise key */
rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,
"set pairwise key\n");
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
index 36c00b89ccae..50b79cf8fb3c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
@@ -215,31 +215,3 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rtl8723_download_fw);
-bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
- struct sk_buff *skb)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- struct rtl8192_tx_ring *ring;
- struct rtl_tx_desc *pdesc;
- struct sk_buff *pskb = NULL;
- unsigned long flags;
-
- ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
- pskb = __skb_dequeue(&ring->queue);
- kfree_skb(pskb);
- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
- pdesc = &ring->desc[0];
- rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
-
- __skb_queue_tail(&ring->queue, skb);
-
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
- rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
- return true;
-}
-EXPORT_SYMBOL_GPL(rtl8723_cmd_send_packet);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.h
index b527fcbbdf08..c8e04f9722ae 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.h
@@ -66,7 +66,5 @@ void rtl8723_write_fw(struct ieee80211_hw *hw,
u8 *buffer, u32 size, u8 max_page);
int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be, int count);
int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be, int count);
-bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
- struct sk_buff *skb);
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 567bbedd8ee0..a1b674e3caaa 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -140,7 +140,7 @@ struct rtw_beacon_filter_iter_data {
u8 *payload;
};
-static void rtw_fw_bcn_filter_notify_vif_iter(void *data, u8 *mac,
+static void rtw_fw_bcn_filter_notify_vif_iter(void *data,
struct ieee80211_vif *vif)
{
struct rtw_beacon_filter_iter_data *iter_data = data;
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index c853e2f2d448..4a33d2e47f33 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -185,8 +185,7 @@ static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
bf_info->cur_csi_rpt_rate = new_csi_rate_idx;
}
-static void rtw_vif_watch_dog_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif)
{
struct rtw_watch_dog_iter_data *iter_data = data;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
@@ -1303,7 +1302,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
si->stbc_en = stbc_en;
si->ldpc_en = ldpc_en;
si->rf_type = rf_type;
- si->wireless_set = wireless_set;
si->sgi_enable = is_support_sgi;
si->vht_enable = is_vht_enable;
si->ra_mask = ra_mask;
@@ -2183,10 +2181,12 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
release_firmware(wow_fw->firmware);
destroy_workqueue(rtwdev->tx_wq);
+ timer_delete_sync(&rtwdev->tx_report.purge_timer);
spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags);
skb_queue_purge(&rtwdev->tx_report.queue);
- skb_queue_purge(&rtwdev->coex.queue);
spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags);
+ skb_queue_purge(&rtwdev->coex.queue);
+ skb_queue_purge(&rtwdev->c2h_queue);
list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list,
build_list) {
@@ -2329,7 +2329,7 @@ struct rtw_iter_port_switch_data {
struct rtw_vif *rtwvif_ap;
};
-static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void rtw_port_switch_iter(void *data, struct ieee80211_vif *vif)
{
struct rtw_iter_port_switch_data *iter_data = data;
struct rtw_dev *rtwdev = iter_data->rtwdev;
@@ -2381,8 +2381,7 @@ void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)
rtw_iterate_vifs(rtwdev, rtw_port_switch_iter, &iter_data);
}
-static void rtw_check_sta_active_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rtw_check_sta_active_iter(void *data, struct ieee80211_vif *vif)
{
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
bool *active = data;
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index f9dd2ab941c8..c42ef8294d59 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -511,12 +511,6 @@ struct rtw_txpwr_idx {
struct rtw_5g_txpwr_idx pwr_idx_5g;
};
-struct rtw_timer_list {
- struct timer_list timer;
- void (*function)(void *data);
- void *args;
-};
-
struct rtw_channel_params {
u8 center_chan;
u8 primary_chan;
@@ -734,9 +728,7 @@ struct rtw_ra_report {
struct rtw_txq {
struct list_head list;
-
unsigned long flags;
- unsigned long last_push;
};
#define RTW_BC_MC_MACID 1
@@ -754,7 +746,6 @@ struct rtw_sta_info {
u8 rate_id;
enum rtw_bandwidth bw_mode;
enum rtw_rf_type rf_type;
- enum rtw_wireless_set wireless_set;
u8 stbc_en:2;
u8 ldpc_en:2;
bool sgi_enable;
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 44a8fff34cdd..2bfc0e822b8d 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1828,5 +1828,5 @@ void rtw_pci_shutdown(struct pci_dev *pdev)
EXPORT_SYMBOL(rtw_pci_shutdown);
MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ac wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index 43e80a3a8136..07e8cbd436cd 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -37,8 +37,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
return 0;
}
-static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rtw_restore_port_cfg_iter(void *data, struct ieee80211_vif *vif)
{
struct rtw_dev *rtwdev = data;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
@@ -320,8 +319,7 @@ static void __rtw_vif_recalc_lps(struct rtw_vif_recalc_lps_iter_data *data,
data->found_vif = vif;
}
-static void rtw_vif_recalc_lps_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rtw_vif_recalc_lps_iter(void *data, struct ieee80211_vif *vif)
{
__rtw_vif_recalc_lps(data, vif);
}
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index 2821119dc930..f63900b6621d 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -606,8 +606,6 @@ static int rtw_txq_push_skb(struct rtw_dev *rtwdev,
rtw_err(rtwdev, "failed to write TX skb to HCI\n");
return ret;
}
- rtwtxq->last_push = jiffies;
-
return 0;
}
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 4a57efdba97b..d879d7e3dc81 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -142,7 +142,6 @@ static int rtw_usb_parse(struct rtw_dev *rtwdev,
struct usb_host_interface *host_interface = &interface->altsetting[0];
struct usb_interface_descriptor *interface_desc = &host_interface->desc;
struct usb_endpoint_descriptor *endpoint;
- struct usb_device *usbd = interface_to_usbdev(interface);
int num_out_pipes = 0;
int i;
u8 num;
@@ -184,22 +183,6 @@ static int rtw_usb_parse(struct rtw_dev *rtwdev,
}
}
- switch (usbd->speed) {
- case USB_SPEED_LOW:
- case USB_SPEED_FULL:
- rtwusb->bulkout_size = RTW_USB_FULL_SPEED_BULK_SIZE;
- break;
- case USB_SPEED_HIGH:
- rtwusb->bulkout_size = RTW_USB_HIGH_SPEED_BULK_SIZE;
- break;
- case USB_SPEED_SUPER:
- rtwusb->bulkout_size = RTW_USB_SUPER_SPEED_BULK_SIZE;
- break;
- default:
- rtw_err(rtwdev, "failed to detect usb speed\n");
- return -EINVAL;
- }
-
rtwdev->hci.bulkout_num = num_out_pipes;
if (num_out_pipes < 1 || num_out_pipes > 4) {
@@ -654,7 +637,6 @@ static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb)
for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
- rxcb->n = i;
rxcb->rtwdev = rtwusb->rtwdev;
rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rxcb->rx_urb)
@@ -844,7 +826,7 @@ int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
ret = rtw_core_init(rtwdev);
if (ret)
- goto err_release_hw;
+ goto err_free_rx_bufs;
ret = rtw_usb_intf_init(rtwdev, intf);
if (ret) {
@@ -890,6 +872,9 @@ err_destroy_usb:
err_deinit_core:
rtw_core_deinit(rtwdev);
+err_free_rx_bufs:
+ rtw_usb_free_rx_bufs(rtwusb);
+
err_release_hw:
ieee80211_free_hw(hw);
@@ -927,5 +912,5 @@ void rtw_usb_disconnect(struct usb_interface *intf)
EXPORT_SYMBOL(rtw_usb_disconnect);
MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
+MODULE_DESCRIPTION("Realtek USB 802.11ac wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/usb.h b/drivers/net/wireless/realtek/rtw88/usb.h
index ad1d7955c6a5..86697a5c0103 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.h
+++ b/drivers/net/wireless/realtek/rtw88/usb.h
@@ -18,10 +18,6 @@
#define RTW_USB_VENQT_CMD_IDX 0x00
-#define RTW_USB_SUPER_SPEED_BULK_SIZE 1024
-#define RTW_USB_HIGH_SPEED_BULK_SIZE 512
-#define RTW_USB_FULL_SPEED_BULK_SIZE 64
-
#define RTW_USB_TX_SEL_HQ BIT(0)
#define RTW_USB_TX_SEL_LQ BIT(1)
#define RTW_USB_TX_SEL_NQ BIT(2)
@@ -58,7 +54,6 @@ struct rx_usb_ctrl_block {
struct rtw_dev *rtwdev;
struct urb *rx_urb;
struct sk_buff *rx_skb;
- int n;
};
struct rtw_usb_tx_data {
@@ -74,12 +69,10 @@ struct rtw_usb {
__le32 *usb_data;
unsigned int usb_data_index;
- u32 bulkout_size;
u8 pipe_interrupt;
u8 pipe_in;
u8 out_ep[RTW_USB_EP_MAX];
int qsel_to_ep[TX_DESC_QSEL_MAX];
- u8 usb_txagg_num;
struct workqueue_struct *txwq, *rxwq;
diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c
index ff3c269fb1a7..e222d3c01a77 100644
--- a/drivers/net/wireless/realtek/rtw88/util.c
+++ b/drivers/net/wireless/realtek/rtw88/util.c
@@ -159,7 +159,6 @@ void rtw_iterate_stas(struct rtw_dev *rtwdev,
struct rtw_vifs_entry {
struct list_head list;
struct ieee80211_vif *vif;
- u8 mac[ETH_ALEN];
};
struct rtw_iter_vifs_data {
@@ -177,13 +176,11 @@ static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
return;
vifs_entry->vif = vif;
- ether_addr_copy(vifs_entry->mac, mac);
list_add_tail(&vifs_entry->list, &iter_stas->list);
}
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
+ void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data)
{
struct rtw_iter_vifs_data iter_data;
@@ -204,7 +201,7 @@ void rtw_iterate_vifs(struct rtw_dev *rtwdev,
list_for_each_entry_safe(vif_entry, tmp, &iter_data.list,
list) {
list_del_init(&vif_entry->list);
- iterator(data, vif_entry->mac, vif_entry->vif);
+ iterator(data, vif_entry->vif);
kfree(vif_entry);
}
}
diff --git a/drivers/net/wireless/realtek/rtw88/util.h b/drivers/net/wireless/realtek/rtw88/util.h
index dc8965525400..f8399128a9a3 100644
--- a/drivers/net/wireless/realtek/rtw88/util.h
+++ b/drivers/net/wireless/realtek/rtw88/util.h
@@ -18,8 +18,7 @@ struct rtw_dev;
ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data)
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
+ void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data);
void rtw_iterate_stas(struct rtw_dev *rtwdev,
void (*iterator)(void *data,
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 4663db4ce2f6..e1bc3606f9ae 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -4,6 +4,8 @@
#include "chan.h"
#include "debug.h"
+#include "fw.h"
+#include "ps.h"
#include "util.h"
static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
@@ -116,6 +118,7 @@ bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
rcd->prev_primary_channel = chan->primary_channel;
rcd->prev_band_type = chan->band_type;
band_changed = new->band_type != chan->band_type;
+ rcd->band_changed = band_changed;
*chan = *new;
return band_changed;
@@ -193,8 +196,12 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev)
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
+ const struct cfg80211_chan_def *chandef;
enum rtw89_entity_mode mode;
+ struct rtw89_chan chan;
u8 weight;
+ u8 last;
+ u8 idx;
weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
switch (weight) {
@@ -206,14 +213,121 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
rtw89_config_default_chandef(rtwdev);
fallthrough;
case 1:
+ last = RTW89_SUB_ENTITY_0;
mode = RTW89_ENTITY_MODE_SCC;
break;
+ case 2:
+ last = RTW89_SUB_ENTITY_1;
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ break;
+
+ mode = RTW89_ENTITY_MODE_MCC_PREPARE;
+ break;
+ }
+
+ for (idx = 0; idx <= last; idx++) {
+ chandef = rtw89_chandef_get(rtwdev, idx);
+ rtw89_get_channel_params(chandef, &chan);
+ if (chan.channel == 0) {
+ WARN(1, "Invalid channel on chanctx %d\n", idx);
+ return RTW89_ENTITY_MODE_INVALID;
+ }
+
+ rtw89_assign_entity_chan(rtwdev, idx, &chan);
}
rtw89_set_entity_mode(rtwdev, mode);
return mode;
}
+static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_state state)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
+ int i;
+
+ if (!listener)
+ return;
+
+ for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
+ if (!listener->callbacks[i])
+ continue;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "chanctx notify listener: cb %d, state %d\n",
+ i, state);
+
+ listener->callbacks[i](rtwdev, state);
+ }
+}
+
+static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
+{
+ if (rtwdev->scanning)
+ rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
+ rtw89_leave_lps(rtwdev);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n");
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);
+ return 0;
+}
+
+static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n");
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
+}
+
+void rtw89_chanctx_work(struct work_struct *work)
+{
+ struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
+ chanctx_work.work);
+ enum rtw89_entity_mode mode;
+ int ret;
+
+ mutex_lock(&rtwdev->mutex);
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC);
+ rtw89_set_channel(rtwdev);
+
+ ret = rtw89_mcc_start(rtwdev);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_entity_mode mode;
+ u32 delay;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ default:
+ return;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
+ break;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "queue chanctx work for mode %d with delay %d us\n",
+ mode, delay);
+ ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work,
+ usecs_to_jiffies(delay));
+}
+
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx)
{
@@ -238,6 +352,7 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ enum rtw89_entity_mode mode;
struct rtw89_vif *rtwvif;
u8 drop, roll;
@@ -267,6 +382,15 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
drop = roll;
out:
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC:
+ rtw89_mcc_stop(rtwdev);
+ break;
+ default:
+ break;
+ }
+
clear_bit(drop, hal->entity_map);
rtw89_set_channel(rtwdev);
}
diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h
index bdf369db5041..448e6c5df9f1 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.h
+++ b/drivers/net/wireless/realtek/rtw89/chan.h
@@ -7,6 +7,9 @@
#include "core.h"
+/* The dwell time in TU before doing rtw89_chanctx_work(). */
+#define RTW89_CHANCTX_TIME_MCC_PREPARE 100
+
static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -50,6 +53,8 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
const struct cfg80211_chan_def *chandef);
void rtw89_entity_init(struct rtw89_dev *rtwdev);
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev);
+void rtw89_chanctx_work(struct work_struct *work);
+void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev);
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx);
void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index bda0e1e99a8c..4ba8b3df70ae 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -5666,7 +5666,8 @@ enum btc_wl_mode {
void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta, enum btc_role_state state)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
struct rtw89_btc *btc = &rtwdev->btc;
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index f16421cb30ef..e76153709793 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -193,4 +193,13 @@ static inline u8 rtw89_btc_path_phymap(struct rtw89_dev *rtwdev,
return rtw89_btc_phymap(rtwdev, phy_idx, BIT(path));
}
+/* return bt req len in TU */
+static inline u16 rtw89_coex_query_bt_req_len(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+
+ return btc->bt_req_len;
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 69b181fa2966..133bf289bacb 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -256,8 +256,8 @@ void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef)
NL80211_CHAN_NO_HT);
}
-static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
- struct rtw89_chan *chan)
+void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
+ struct rtw89_chan *chan)
{
struct ieee80211_channel *channel = chandef->chan;
enum nl80211_chan_width width = chandef->width;
@@ -318,9 +318,11 @@ static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_chan *chan;
enum rtw89_sub_entity_idx sub_entity_idx;
+ enum rtw89_sub_entity_idx roc_idx;
enum rtw89_phy_idx phy_idx;
enum rtw89_entity_mode mode;
bool entity_active;
@@ -330,10 +332,23 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
return;
mode = rtw89_get_entity_mode(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
+ switch (mode) {
+ case RTW89_ENTITY_MODE_SCC:
+ case RTW89_ENTITY_MODE_MCC:
+ sub_entity_idx = RTW89_SUB_ENTITY_0;
+ break;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ sub_entity_idx = RTW89_SUB_ENTITY_1;
+ break;
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
return;
+ }
+
+ roc_idx = atomic_read(&hal->roc_entity_idx);
+ if (roc_idx != RTW89_SUB_ENTITY_IDLE)
+ sub_entity_idx = roc_idx;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
phy_idx = RTW89_PHY_0;
chan = rtw89_chan_get(rtwdev, sub_entity_idx);
chip->ops->set_txpwr(rtwdev, chan, phy_idx);
@@ -341,43 +356,54 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
void rtw89_set_channel(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct cfg80211_chan_def *chandef;
+ const struct rtw89_chan_rcd *chan_rcd;
+ const struct rtw89_chan *chan;
enum rtw89_sub_entity_idx sub_entity_idx;
+ enum rtw89_sub_entity_idx roc_idx;
enum rtw89_mac_idx mac_idx;
enum rtw89_phy_idx phy_idx;
- struct rtw89_chan chan;
struct rtw89_channel_help_params bak;
enum rtw89_entity_mode mode;
- bool band_changed;
bool entity_active;
entity_active = rtw89_get_entity_state(rtwdev);
mode = rtw89_entity_recalc(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
+ switch (mode) {
+ case RTW89_ENTITY_MODE_SCC:
+ case RTW89_ENTITY_MODE_MCC:
+ sub_entity_idx = RTW89_SUB_ENTITY_0;
+ break;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ sub_entity_idx = RTW89_SUB_ENTITY_1;
+ break;
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
return;
+ }
+
+ roc_idx = atomic_read(&hal->roc_entity_idx);
+ if (roc_idx != RTW89_SUB_ENTITY_IDLE)
+ sub_entity_idx = roc_idx;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
mac_idx = RTW89_MAC_0;
phy_idx = RTW89_PHY_0;
- chandef = rtw89_chandef_get(rtwdev, sub_entity_idx);
- rtw89_get_channel_params(chandef, &chan);
- if (WARN(chan.channel == 0, "Invalid channel\n"))
- return;
- band_changed = rtw89_assign_entity_chan(rtwdev, sub_entity_idx, &chan);
+ chan = rtw89_chan_get(rtwdev, sub_entity_idx);
+ chan_rcd = rtw89_chan_rcd_get(rtwdev, sub_entity_idx);
- rtw89_chip_set_channel_prepare(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx);
- chip->ops->set_channel(rtwdev, &chan, mac_idx, phy_idx);
+ chip->ops->set_channel(rtwdev, chan, mac_idx, phy_idx);
- chip->ops->set_txpwr(rtwdev, &chan, phy_idx);
+ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
- rtw89_chip_set_channel_done(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ rtw89_chip_set_channel_done(rtwdev, &bak, chan, mac_idx, phy_idx);
- if (!entity_active || band_changed) {
- rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan.band_type);
+ if (!entity_active || chan_rcd->band_changed) {
+ rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan->band_type);
rtw89_chip_rfk_band_changed(rtwdev, phy_idx);
}
@@ -523,12 +549,12 @@ rtw89_core_tx_update_sec_key(struct rtw89_dev *rtwdev,
}
static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
- struct rtw89_core_tx_request *tx_req)
+ struct rtw89_core_tx_request *tx_req,
+ const struct rtw89_chan *chan)
{
struct sk_buff *skb = tx_req->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = tx_info->control.vif;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 lowest_rate;
if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE ||
@@ -567,7 +593,8 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif = tx_req->vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
u8 qsel, ch_dma;
qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : RTW89_TX_QSEL_B0_MGMT;
@@ -584,7 +611,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
desc_info->en_wd_info = true;
desc_info->use_rate = true;
desc_info->dis_data_fb = true;
- desc_info->data_rate = rtw89_core_get_mgmt_rate(rtwdev, tx_req);
+ desc_info->data_rate = rtw89_core_get_mgmt_rate(rtwdev, tx_req, chan);
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"tx mgmt frame with rate 0x%x on channel %d (band %d, bw %d)\n",
@@ -603,7 +630,8 @@ rtw89_core_tx_update_h2c_info(struct rtw89_dev *rtwdev,
desc_info->ch_dma = RTW89_DMA_H2C;
}
-static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc)
+static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc,
+ const struct rtw89_chan *chan)
{
static const u8 rtw89_bandwidth_to_om[] = {
[RTW89_CHANNEL_WIDTH_20] = HTC_OM_CHANNEL_WIDTH_20,
@@ -614,7 +642,6 @@ static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc
};
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u8 om_bandwidth;
if (!chip->dis_2g_40m_ul_ofdma ||
@@ -1456,16 +1483,16 @@ static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev,
bool ret;
data_rate = desc_info->data_rate;
- data_rate_mode = GET_DATA_RATE_MODE(data_rate);
+ data_rate_mode = rtw89_get_data_rate_mode(rtwdev, data_rate);
if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
- rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate);
+ rate_idx = rtw89_get_data_not_ht_idx(rtwdev, data_rate);
/* rate_idx is still hardware value here */
} else if (data_rate_mode == DATA_RATE_MODE_HT) {
- rate_idx = GET_DATA_RATE_HT_IDX(data_rate);
+ rate_idx = rtw89_get_data_ht_mcs(rtwdev, data_rate);
} else if (data_rate_mode == DATA_RATE_MODE_VHT) {
- rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
+ rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
} else if (data_rate_mode == DATA_RATE_MODE_HE) {
- rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
+ rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
} else {
rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
}
@@ -1659,8 +1686,7 @@ static void rtw89_correct_cck_chan(struct rtw89_dev *rtwdev,
const struct rtw89_chan_rcd *rcd =
rtw89_chan_rcd_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 chan = rcd->prev_primary_channel;
- u8 band = rcd->prev_band_type == RTW89_BAND_2G ?
- NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+ u8 band = rtw89_hw_to_nl80211_band(rcd->prev_band_type);
if (status->band != NL80211_BAND_2GHZ &&
status->encoding == RX_ENC_LEGACY &&
@@ -1900,7 +1926,6 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
{
const struct cfg80211_chan_def *chandef =
rtw89_chandef_get(rtwdev, RTW89_SUB_ENTITY_0);
- const struct rtw89_chan *cur = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 data_rate;
u8 data_rate_mode;
@@ -1910,6 +1935,7 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
if (rtwdev->scanning &&
RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
+ const struct rtw89_chan *cur = rtw89_scan_chan_get(rtwdev);
u8 chan = cur->primary_channel;
u8 band = cur->band_type;
enum nl80211_band nl_band;
@@ -1929,26 +1955,26 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
rx_status->bw = rtw89_hw_to_rate_info_bw(desc_info->bw);
data_rate = desc_info->data_rate;
- data_rate_mode = GET_DATA_RATE_MODE(data_rate);
+ data_rate_mode = rtw89_get_data_rate_mode(rtwdev, data_rate);
if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
rx_status->encoding = RX_ENC_LEGACY;
- rx_status->rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate);
+ rx_status->rate_idx = rtw89_get_data_not_ht_idx(rtwdev, data_rate);
/* convert rate_idx after we get the correct band */
} else if (data_rate_mode == DATA_RATE_MODE_HT) {
rx_status->encoding = RX_ENC_HT;
- rx_status->rate_idx = GET_DATA_RATE_HT_IDX(data_rate);
+ rx_status->rate_idx = rtw89_get_data_ht_mcs(rtwdev, data_rate);
if (desc_info->gi_ltf)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
} else if (data_rate_mode == DATA_RATE_MODE_VHT) {
rx_status->encoding = RX_ENC_VHT;
- rx_status->rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
- rx_status->nss = GET_DATA_RATE_NSS(data_rate) + 1;
+ rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
+ rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
if (desc_info->gi_ltf)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
} else if (data_rate_mode == DATA_RATE_MODE_HE) {
rx_status->encoding = RX_ENC_HE;
- rx_status->rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
- rx_status->nss = GET_DATA_RATE_NSS(data_rate) + 1;
+ rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
+ rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
} else {
rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
}
@@ -2451,6 +2477,7 @@ out:
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 cfg80211_chan_def roc_chan;
@@ -2478,7 +2505,7 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, &roc_chan);
rtw89_set_channel(rtwdev);
rtw89_write32_clr(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
ieee80211_ready_on_channel(hw);
@@ -2486,6 +2513,7 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
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;
@@ -2499,7 +2527,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_leave_lps(rtwdev);
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
rtwdev->hal.rx_fltr);
@@ -2682,6 +2710,7 @@ static void rtw89_track_work(struct work_struct *work)
rtw89_phy_tx_path_div_track(rtwdev);
rtw89_phy_antdiv_track(rtwdev);
rtw89_phy_ul_tb_ctrl_track(rtwdev);
+ rtw89_tas_track(rtwdev);
if (rtwdev->lps_enabled && !rtwdev->btc.lps)
rtw89_enter_lps_track(rtwdev);
@@ -2970,6 +2999,8 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
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 rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
int ret;
if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
@@ -3023,7 +3054,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
BTC_ROLE_MSTS_STA_CONN_END);
- rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template);
+ rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan);
rtw89_phy_ul_tb_assoc(rtwdev, rtwvif);
ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
@@ -3463,6 +3494,27 @@ void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
complete(&wait->completion);
}
+void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event)
+{
+ u16 bt_req_len;
+
+ switch (event) {
+ case RTW89_BTC_HMSG_SET_BT_REQ_SLOT:
+ bt_req_len = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "coex updates BT req len to %d TU\n", bt_req_len);
+ break;
+ default:
+ if (event < NUM_OF_RTW89_BTC_HMSG)
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "unhandled BTC HMSG event: %d\n", event);
+ else
+ rtw89_warn(rtwdev,
+ "unrecognized BTC HMSG event: %d\n", event);
+ break;
+ }
+}
+
int rtw89_core_start(struct rtw89_dev *rtwdev)
{
int ret;
@@ -3496,6 +3548,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
+ rtw89_tas_reset(rtwdev);
+
ret = rtw89_hci_start(rtwdev);
if (ret) {
rtw89_err(rtwdev, "failed to start hci\n");
@@ -3508,7 +3562,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
set_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
- rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.fw_log_enable);
+ rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable);
rtw89_fw_h2c_init_ba_cam(rtwdev);
return 0;
@@ -3536,6 +3590,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
cancel_work_sync(&btc->icmp_notify_work);
cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
cancel_delayed_work_sync(&rtwdev->track_work);
+ cancel_delayed_work_sync(&rtwdev->chanctx_work);
cancel_delayed_work_sync(&rtwdev->coex_act1_work);
cancel_delayed_work_sync(&rtwdev->coex_bt_devinfo_work);
cancel_delayed_work_sync(&rtwdev->coex_rfk_chk_work);
@@ -3572,6 +3627,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work);
+ INIT_DELAYED_WORK(&rtwdev->chanctx_work, rtw89_chanctx_work);
INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
INIT_DELAYED_WORK(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work);
INIT_DELAYED_WORK(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work);
@@ -3612,6 +3668,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtw89_ser_init(rtwdev);
rtw89_entity_init(rtwdev);
+ rtw89_tas_init(rtwdev);
return 0;
}
@@ -3632,7 +3689,8 @@ EXPORT_SYMBOL(rtw89_core_deinit);
void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
const u8 *mac_addr, bool hw_scan)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
@@ -3779,6 +3837,12 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
return ret;
}
+ ret = rtw89_fw_recognize_elements(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to recognize firmware elements\n");
+ return ret;
+ }
+
ret = rtw89_chip_efuse_info_setup(rtwdev);
if (ret)
return ret;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index d2c67db97db1..04ce221730f9 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -14,6 +14,8 @@
struct rtw89_dev;
struct rtw89_pci_info;
+struct rtw89_mac_gen_def;
+struct rtw89_phy_gen_def;
extern const struct ieee80211_ops rtw89_ops;
@@ -109,6 +111,14 @@ enum rtw89_core_chip_id {
RTL8852B,
RTL8852C,
RTL8851B,
+ RTL8922A,
+};
+
+enum rtw89_chip_gen {
+ RTW89_CHIP_AX,
+ RTW89_CHIP_BE,
+
+ RTW89_CHIP_GEN_NUM,
};
enum rtw89_cv {
@@ -387,10 +397,201 @@ enum rtw89_hw_rate {
RTW89_HW_RATE_HE_NSS4_MCS9 = 0x1B9,
RTW89_HW_RATE_HE_NSS4_MCS10 = 0x1BA,
RTW89_HW_RATE_HE_NSS4_MCS11 = 0x1BB,
+
+ RTW89_HW_RATE_V1_MCS0 = 0x100,
+ RTW89_HW_RATE_V1_MCS1 = 0x101,
+ RTW89_HW_RATE_V1_MCS2 = 0x102,
+ RTW89_HW_RATE_V1_MCS3 = 0x103,
+ RTW89_HW_RATE_V1_MCS4 = 0x104,
+ RTW89_HW_RATE_V1_MCS5 = 0x105,
+ RTW89_HW_RATE_V1_MCS6 = 0x106,
+ RTW89_HW_RATE_V1_MCS7 = 0x107,
+ RTW89_HW_RATE_V1_MCS8 = 0x108,
+ RTW89_HW_RATE_V1_MCS9 = 0x109,
+ RTW89_HW_RATE_V1_MCS10 = 0x10A,
+ RTW89_HW_RATE_V1_MCS11 = 0x10B,
+ RTW89_HW_RATE_V1_MCS12 = 0x10C,
+ RTW89_HW_RATE_V1_MCS13 = 0x10D,
+ RTW89_HW_RATE_V1_MCS14 = 0x10E,
+ RTW89_HW_RATE_V1_MCS15 = 0x10F,
+ RTW89_HW_RATE_V1_MCS16 = 0x110,
+ RTW89_HW_RATE_V1_MCS17 = 0x111,
+ RTW89_HW_RATE_V1_MCS18 = 0x112,
+ RTW89_HW_RATE_V1_MCS19 = 0x113,
+ RTW89_HW_RATE_V1_MCS20 = 0x114,
+ RTW89_HW_RATE_V1_MCS21 = 0x115,
+ RTW89_HW_RATE_V1_MCS22 = 0x116,
+ RTW89_HW_RATE_V1_MCS23 = 0x117,
+ RTW89_HW_RATE_V1_MCS24 = 0x118,
+ RTW89_HW_RATE_V1_MCS25 = 0x119,
+ RTW89_HW_RATE_V1_MCS26 = 0x11A,
+ RTW89_HW_RATE_V1_MCS27 = 0x11B,
+ RTW89_HW_RATE_V1_MCS28 = 0x11C,
+ RTW89_HW_RATE_V1_MCS29 = 0x11D,
+ RTW89_HW_RATE_V1_MCS30 = 0x11E,
+ RTW89_HW_RATE_V1_MCS31 = 0x11F,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS0 = 0x200,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS1 = 0x201,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS2 = 0x202,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS3 = 0x203,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS4 = 0x204,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS5 = 0x205,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS6 = 0x206,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS7 = 0x207,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS8 = 0x208,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS9 = 0x209,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS10 = 0x20A,
+ RTW89_HW_RATE_V1_VHT_NSS1_MCS11 = 0x20B,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS0 = 0x220,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS1 = 0x221,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS2 = 0x222,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS3 = 0x223,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS4 = 0x224,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS5 = 0x225,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS6 = 0x226,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS7 = 0x227,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS8 = 0x228,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS9 = 0x229,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS10 = 0x22A,
+ RTW89_HW_RATE_V1_VHT_NSS2_MCS11 = 0x22B,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS0 = 0x240,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS1 = 0x241,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS2 = 0x242,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS3 = 0x243,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS4 = 0x244,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS5 = 0x245,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS6 = 0x246,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS7 = 0x247,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS8 = 0x248,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS9 = 0x249,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS10 = 0x24A,
+ RTW89_HW_RATE_V1_VHT_NSS3_MCS11 = 0x24B,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS0 = 0x260,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS1 = 0x261,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS2 = 0x262,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS3 = 0x263,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS4 = 0x264,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS5 = 0x265,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS6 = 0x266,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS7 = 0x267,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS8 = 0x268,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS9 = 0x269,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS10 = 0x26A,
+ RTW89_HW_RATE_V1_VHT_NSS4_MCS11 = 0x26B,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS0 = 0x300,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS1 = 0x301,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS2 = 0x302,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS3 = 0x303,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS4 = 0x304,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS5 = 0x305,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS6 = 0x306,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS7 = 0x307,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS8 = 0x308,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS9 = 0x309,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS10 = 0x30A,
+ RTW89_HW_RATE_V1_HE_NSS1_MCS11 = 0x30B,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS0 = 0x320,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS1 = 0x321,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS2 = 0x322,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS3 = 0x323,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS4 = 0x324,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS5 = 0x325,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS6 = 0x326,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS7 = 0x327,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS8 = 0x328,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS9 = 0x329,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS10 = 0x32A,
+ RTW89_HW_RATE_V1_HE_NSS2_MCS11 = 0x32B,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS0 = 0x340,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS1 = 0x341,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS2 = 0x342,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS3 = 0x343,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS4 = 0x344,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS5 = 0x345,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS6 = 0x346,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS7 = 0x347,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS8 = 0x348,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS9 = 0x349,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS10 = 0x34A,
+ RTW89_HW_RATE_V1_HE_NSS3_MCS11 = 0x34B,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS0 = 0x360,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS1 = 0x361,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS2 = 0x362,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS3 = 0x363,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS4 = 0x364,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS5 = 0x365,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS6 = 0x366,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS7 = 0x367,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS8 = 0x368,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS9 = 0x369,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS10 = 0x36A,
+ RTW89_HW_RATE_V1_HE_NSS4_MCS11 = 0x36B,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS0 = 0x400,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS1 = 0x401,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS2 = 0x402,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS3 = 0x403,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS4 = 0x404,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS5 = 0x405,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS6 = 0x406,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS7 = 0x407,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS8 = 0x408,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS9 = 0x409,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS10 = 0x40A,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS11 = 0x40B,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS12 = 0x40C,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS13 = 0x40D,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS14 = 0x40E,
+ RTW89_HW_RATE_V1_EHT_NSS1_MCS15 = 0x40F,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS0 = 0x420,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS1 = 0x421,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS2 = 0x422,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS3 = 0x423,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS4 = 0x424,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS5 = 0x425,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS6 = 0x426,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS7 = 0x427,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS8 = 0x428,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS9 = 0x429,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS10 = 0x42A,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS11 = 0x42B,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS12 = 0x42C,
+ RTW89_HW_RATE_V1_EHT_NSS2_MCS13 = 0x42D,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS0 = 0x440,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS1 = 0x441,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS2 = 0x442,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS3 = 0x443,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS4 = 0x444,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS5 = 0x445,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS6 = 0x446,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS7 = 0x447,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS8 = 0x448,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS9 = 0x449,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS10 = 0x44A,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS11 = 0x44B,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS12 = 0x44C,
+ RTW89_HW_RATE_V1_EHT_NSS3_MCS13 = 0x44D,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS0 = 0x460,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS1 = 0x461,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS2 = 0x462,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS3 = 0x463,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS4 = 0x464,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS5 = 0x465,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS6 = 0x466,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS7 = 0x467,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS8 = 0x468,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS9 = 0x469,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS10 = 0x46A,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS11 = 0x46B,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS12 = 0x46C,
+ RTW89_HW_RATE_V1_EHT_NSS4_MCS13 = 0x46D,
+
RTW89_HW_RATE_NR,
+ RTW89_HW_RATE_INVAL,
RTW89_HW_RATE_MASK_MOD = GENMASK(8, 7),
RTW89_HW_RATE_MASK_VAL = GENMASK(6, 0),
+ RTW89_HW_RATE_V1_MASK_MOD = GENMASK(10, 8),
+ RTW89_HW_RATE_V1_MASK_VAL = GENMASK(7, 0),
};
/* 2G channels,
@@ -590,6 +791,7 @@ enum rtw89_phy_idx {
enum rtw89_sub_entity_idx {
RTW89_SUB_ENTITY_0 = 0,
+ RTW89_SUB_ENTITY_1 = 1,
NUM_OF_RTW89_SUB_ENTITY,
RTW89_SUB_ENTITY_IDLE = NUM_OF_RTW89_SUB_ENTITY,
@@ -701,6 +903,7 @@ struct rtw89_chan {
struct rtw89_chan_rcd {
u8 prev_primary_channel;
enum rtw89_band prev_band_type;
+ bool band_changed;
};
struct rtw89_channel_help_params {
@@ -2457,6 +2660,17 @@ struct rtw89_btc {
bool lps;
};
+enum rtw89_btc_hmsg {
+ RTW89_BTC_HMSG_TMR_EN = 0x0,
+ RTW89_BTC_HMSG_BT_REG_READBACK = 0x1,
+ RTW89_BTC_HMSG_SET_BT_REQ_SLOT = 0x2,
+ RTW89_BTC_HMSG_FW_EV = 0x3,
+ RTW89_BTC_HMSG_BT_LINK_CHG = 0x4,
+ RTW89_BTC_HMSG_SET_BT_REQ_STBC = 0x5,
+
+ NUM_OF_RTW89_BTC_HMSG,
+};
+
enum rtw89_ra_mode {
RTW89_RA_MODE_CCK = BIT(0),
RTW89_RA_MODE_OFDM = BIT(1),
@@ -2504,9 +2718,10 @@ struct rtw89_ra_info {
* Bit2 : HT
* Bit3 : VHT
* Bit4 : HE
+ * Bit5 : EHT
*/
- u8 mode_ctrl:5;
- u8 bw_cap:2;
+ u8 mode_ctrl:6;
+ u8 bw_cap:3; /* enum rtw89_bandwidth */
u8 macid;
u8 dcm_cap:1;
u8 er_cap:1;
@@ -2685,6 +2900,32 @@ struct rtw89_roc {
#define RTW89_P2P_MAX_NOA_NUM 2
+struct rtw89_p2p_ie_head {
+ u8 eid;
+ u8 ie_len;
+ u8 oui[3];
+ u8 oui_type;
+} __packed;
+
+struct rtw89_noa_attr_head {
+ u8 attr_type;
+ __le16 attr_len;
+ u8 index;
+ u8 oppps_ctwindow;
+} __packed;
+
+struct rtw89_p2p_noa_ie {
+ struct rtw89_p2p_ie_head p2p_head;
+ struct rtw89_noa_attr_head noa_head;
+ struct ieee80211_p2p_noa_desc noa_desc[RTW89_P2P_MAX_NOA_NUM];
+} __packed;
+
+struct rtw89_p2p_noa_setter {
+ struct rtw89_p2p_noa_ie ie;
+ u8 noa_count;
+ u8 noa_index;
+};
+
struct rtw89_vif {
struct list_head list;
struct rtw89_dev *rtwdev;
@@ -2727,6 +2968,7 @@ struct rtw89_vif {
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;
};
enum rtw89_lv1_rcvy_step {
@@ -3139,6 +3381,10 @@ struct rtw89_dig_regs {
u32 seg0_pd_reg;
u32 pd_lower_bound_mask;
u32 pd_spatial_reuse_en;
+ u32 bmode_pd_reg;
+ u32 bmode_cca_rssi_limit_en;
+ u32 bmode_pd_lower_bound_reg;
+ u32 bmode_rssi_nocca_low_th_mask;
struct rtw89_reg_def p0_lna_init;
struct rtw89_reg_def p1_lna_init;
struct rtw89_reg_def p0_tia_init;
@@ -3175,12 +3421,32 @@ struct rtw89_antdiv_info {
bool get_stats;
};
+enum rtw89_chanctx_state {
+ RTW89_CHANCTX_STATE_MCC_START,
+ RTW89_CHANCTX_STATE_MCC_STOP,
+};
+
+enum rtw89_chanctx_callbacks {
+ RTW89_CHANCTX_CALLBACK_PLACEHOLDER,
+
+ NUM_OF_RTW89_CHANCTX_CALLBACKS,
+};
+
+struct rtw89_chanctx_listener {
+ void (*callbacks[NUM_OF_RTW89_CHANCTX_CALLBACKS])
+ (struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state);
+};
+
struct rtw89_chip_info {
enum rtw89_core_chip_id chip_id;
+ enum rtw89_chip_gen chip_gen;
const struct rtw89_chip_ops *ops;
+ const struct rtw89_mac_gen_def *mac_def;
+ const struct rtw89_phy_gen_def *phy_def;
const char *fw_basename;
u8 fw_format_max;
bool try_ce_fw;
+ u32 needed_fw_elms;
u32 fifo_size;
bool small_fifo_size;
u32 dle_scc_rsvd_size;
@@ -3232,6 +3498,7 @@ struct rtw89_chip_info {
/* NULL if no rfe-specific, or a null-terminated array by rfe_parms */
const struct rtw89_rfe_parms_conf *rfe_parms_conf;
const struct rtw89_rfe_parms *dflt_parms;
+ const struct rtw89_chanctx_listener *chanctx_listener;
u8 txpwr_factor_rf;
u8 txpwr_factor_mac;
@@ -3347,6 +3614,9 @@ enum rtw89_fw_type {
RTW89_FW_NORMAL = 1,
RTW89_FW_WOWLAN = 3,
RTW89_FW_NORMAL_CE = 5,
+ RTW89_FW_BBMCU0 = 64,
+ RTW89_FW_BBMCU1 = 65,
+ RTW89_FW_LOGFMT = 255,
};
enum rtw89_fw_feature {
@@ -3361,6 +3631,7 @@ enum rtw89_fw_feature {
};
struct rtw89_fw_suit {
+ enum rtw89_fw_type type;
const u8 *data;
u32 size;
u8 major_ver;
@@ -3373,6 +3644,8 @@ struct rtw89_fw_suit {
u16 build_hour;
u16 build_min;
u8 cmd_ver;
+ u8 hdr_ver;
+ u32 commitid;
};
#define RTW89_FW_VER_CODE(major, minor, sub, idx) \
@@ -3397,6 +3670,22 @@ struct rtw89_fw_req_info {
struct completion completion;
};
+struct rtw89_fw_log {
+ struct rtw89_fw_suit suit;
+ bool enable;
+ u32 last_fmt_id;
+ u32 fmt_count;
+ const __le32 *fmt_ids;
+ const char *(*fmts)[];
+};
+
+struct rtw89_fw_elm_info {
+ struct rtw89_phy_table *bb_tbl;
+ struct rtw89_phy_table *bb_gain;
+ struct rtw89_phy_table *rf_radio[RF_PATH_MAX];
+ struct rtw89_phy_table *rf_nctl;
+};
+
struct rtw89_fw_info {
struct rtw89_fw_req_info req;
int fw_format;
@@ -3406,8 +3695,11 @@ struct rtw89_fw_info {
u8 c2h_counter;
struct rtw89_fw_suit normal;
struct rtw89_fw_suit wowlan;
- bool fw_log_enable;
+ struct rtw89_fw_suit bbmcu0;
+ struct rtw89_fw_suit bbmcu1;
+ struct rtw89_fw_log log;
u32 feature_map;
+ struct rtw89_fw_elm_info elm_info;
};
#define RTW89_CHK_FW_FEATURE(_feat, _fw) \
@@ -3463,12 +3755,34 @@ struct rtw89_sar_info {
};
};
+enum rtw89_tas_state {
+ RTW89_TAS_STATE_DPR_OFF,
+ RTW89_TAS_STATE_DPR_ON,
+ RTW89_TAS_STATE_DPR_FORBID,
+};
+
+#define RTW89_TAS_MAX_WINDOW 50
+struct rtw89_tas_info {
+ s16 txpwr_history[RTW89_TAS_MAX_WINDOW];
+ s32 total_txpwr;
+ u8 cur_idx;
+ s8 dpr_gap;
+ s8 delta;
+ enum rtw89_tas_state state;
+ bool enable;
+};
+
struct rtw89_chanctx_cfg {
enum rtw89_sub_entity_idx idx;
};
enum rtw89_entity_mode {
RTW89_ENTITY_MODE_SCC,
+ RTW89_ENTITY_MODE_MCC_PREPARE,
+ RTW89_ENTITY_MODE_MCC,
+
+ NUM_OF_RTW89_ENTITY_MODE,
+ RTW89_ENTITY_MODE_INVALID = NUM_OF_RTW89_ENTITY_MODE,
};
struct rtw89_sub_entity {
@@ -4125,6 +4439,7 @@ struct rtw89_dev {
struct rtw89_antdiv_info antdiv;
struct delayed_work track_work;
+ struct delayed_work chanctx_work;
struct delayed_work coex_act1_work;
struct delayed_work coex_bt_devinfo_work;
struct delayed_work coex_rfk_chk_work;
@@ -4138,6 +4453,7 @@ struct rtw89_dev {
struct rtw89_regulatory_info regulatory;
struct rtw89_sar_info sar;
+ struct rtw89_tas_info tas;
struct rtw89_btc btc;
enum rtw89_ps_mode ps_mode;
@@ -4673,6 +4989,18 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev,
return &hal->sub[idx].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);
+
+ if (rtwvif)
+ return rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx);
+ else
+ return rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+}
+
static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -4940,8 +5268,19 @@ static inline struct rtw89_fw_suit *rtw89_fw_suit_get(struct rtw89_dev *rtwdev,
{
struct rtw89_fw_info *fw_info = &rtwdev->fw;
- if (type == RTW89_FW_WOWLAN)
+ switch (type) {
+ case RTW89_FW_WOWLAN:
return &fw_info->wowlan;
+ case RTW89_FW_LOGFMT:
+ return &fw_info->log.suit;
+ case RTW89_FW_BBMCU0:
+ return &fw_info->bbmcu0;
+ case RTW89_FW_BBMCU1:
+ return &fw_info->bbmcu1;
+ default:
+ break;
+ }
+
return &fw_info->normal;
}
@@ -5035,6 +5374,8 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev);
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);
void rtw89_set_channel(struct rtw89_dev *rtwdev);
void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_chan *chan);
@@ -5069,5 +5410,6 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif, bool hw_scan);
void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, bool active);
+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 a4bbac916e22..d162e64f6064 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -572,9 +572,9 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev,
seq_puts(m, #_regd "\n"); \
break
-static void __print_regd(struct seq_file *m, struct rtw89_dev *rtwdev)
+static void __print_regd(struct seq_file *m, struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u8 band = chan->band_type;
u8 regd = rtw89_regd_get(rtwdev, band);
@@ -604,16 +604,21 @@ static int rtw89_debug_priv_txpwr_table_get(struct seq_file *m, void *v)
{
struct rtw89_debugfs_priv *debugfs_priv = m->private;
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ const struct rtw89_chan *chan;
int ret = 0;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
+ chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
seq_puts(m, "[Regulatory] ");
- __print_regd(m, rtwdev);
+ __print_regd(m, rtwdev, chan);
seq_puts(m, "[SAR]\n");
- rtw89_print_sar(m, rtwdev);
+ rtw89_print_sar(m, rtwdev, chan->freq);
+
+ seq_puts(m, "[TAS]\n");
+ rtw89_print_tas(m, rtwdev);
seq_puts(m, "\n[TX power byrate]\n");
ret = __print_txpwr_map(m, rtwdev, &__txpwr_map_byr);
@@ -790,6 +795,9 @@ static void rtw89_debug_dump_mac_mem(struct seq_file *m,
struct rtw89_dev *rtwdev,
u8 sel, u32 start_addr, u32 len)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 filter_model_addr = mac->filter_model_addr;
+ u32 indir_access_addr = mac->indir_access_addr;
u32 base_addr, start_page, residue;
u32 i, j, p, pages;
u32 dump_len, remain;
@@ -799,17 +807,17 @@ static void rtw89_debug_dump_mac_mem(struct seq_file *m,
pages = len / MAC_MEM_DUMP_PAGE_SIZE + 1;
start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE;
residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE;
- base_addr = rtw89_mac_mem_base_addrs[sel];
+ base_addr = mac->mem_base_addrs[sel];
base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE;
for (p = 0; p < pages; p++) {
dump_len = min_t(u32, remain, MAC_MEM_DUMP_PAGE_SIZE);
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr);
- for (i = R_AX_INDIR_ACCESS_ENTRY + residue;
- i < R_AX_INDIR_ACCESS_ENTRY + dump_len;) {
+ rtw89_write32(rtwdev, filter_model_addr, base_addr);
+ for (i = indir_access_addr + residue;
+ i < indir_access_addr + dump_len;) {
seq_printf(m, "%08xh:", i);
for (j = 0;
- j < 4 && i < R_AX_INDIR_ACCESS_ENTRY + dump_len;
+ j < 4 && i < indir_access_addr + dump_len;
j++, i += 4) {
val = rtw89_read32(rtwdev, i);
seq_printf(m, " %08x", val);
@@ -3193,29 +3201,33 @@ static ssize_t rtw89_debug_priv_btc_manual_set(struct file *filp,
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
struct rtw89_btc *btc = &rtwdev->btc;
bool btc_manual;
+ int ret;
- if (kstrtobool_from_user(user_buf, count, &btc_manual))
- goto out;
+ ret = kstrtobool_from_user(user_buf, count, &btc_manual);
+ if (ret)
+ return ret;
btc->ctrl.manual = btc_manual;
-out:
+
return count;
}
-static ssize_t rtw89_debug_fw_log_btc_manual_set(struct file *filp,
- const char __user *user_buf,
- size_t count, loff_t *loff)
+static ssize_t rtw89_debug_fw_log_manual_set(struct file *filp,
+ const char __user *user_buf,
+ size_t count, loff_t *loff)
{
struct rtw89_debugfs_priv *debugfs_priv = filp->private_data;
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
- struct rtw89_fw_info *fw_info = &rtwdev->fw;
+ struct rtw89_fw_log *log = &rtwdev->fw.log;
bool fw_log_manual;
if (kstrtobool_from_user(user_buf, count, &fw_log_manual))
goto out;
mutex_lock(&rtwdev->mutex);
- fw_info->fw_log_enable = fw_log_manual;
+ log->enable = fw_log_manual;
+ if (log->enable)
+ rtw89_fw_log_prepare(rtwdev);
rtw89_fw_h2c_fw_log(rtwdev, fw_log_manual);
mutex_unlock(&rtwdev->mutex);
out:
@@ -3323,20 +3335,26 @@ rtw89_debug_append_rx_rate(struct seq_file *m, struct rtw89_pkt_stat *pkt_stat,
pkt_stat->rx_rate_cnt[first_rate + i]);
}
+#define FIRST_RATE_SAME(rate) {RTW89_HW_RATE_ ## rate, RTW89_HW_RATE_ ## rate}
+#define FIRST_RATE_ENUM(rate) {RTW89_HW_RATE_ ## rate, RTW89_HW_RATE_V1_ ## rate}
+#define FIRST_RATE_GEV1(rate) {RTW89_HW_RATE_INVAL, RTW89_HW_RATE_V1_ ## rate}
+
static const struct rtw89_rx_rate_cnt_info {
- enum rtw89_hw_rate first_rate;
+ enum rtw89_hw_rate first_rate[RTW89_CHIP_GEN_NUM];
int len;
int ext;
const char *rate_mode;
} rtw89_rx_rate_cnt_infos[] = {
- {RTW89_HW_RATE_CCK1, 4, 0, "Legacy:"},
- {RTW89_HW_RATE_OFDM6, 8, 0, "OFDM:"},
- {RTW89_HW_RATE_MCS0, 8, 0, "HT 0:"},
- {RTW89_HW_RATE_MCS8, 8, 0, "HT 1:"},
- {RTW89_HW_RATE_VHT_NSS1_MCS0, 10, 2, "VHT 1SS:"},
- {RTW89_HW_RATE_VHT_NSS2_MCS0, 10, 2, "VHT 2SS:"},
- {RTW89_HW_RATE_HE_NSS1_MCS0, 12, 0, "HE 1SS:"},
- {RTW89_HW_RATE_HE_NSS2_MCS0, 12, 0, "HE 2ss:"},
+ {FIRST_RATE_SAME(CCK1), 4, 0, "Legacy:"},
+ {FIRST_RATE_SAME(OFDM6), 8, 0, "OFDM:"},
+ {FIRST_RATE_ENUM(MCS0), 8, 0, "HT 0:"},
+ {FIRST_RATE_ENUM(MCS8), 8, 0, "HT 1:"},
+ {FIRST_RATE_ENUM(VHT_NSS1_MCS0), 10, 2, "VHT 1SS:"},
+ {FIRST_RATE_ENUM(VHT_NSS2_MCS0), 10, 2, "VHT 2SS:"},
+ {FIRST_RATE_ENUM(HE_NSS1_MCS0), 12, 0, "HE 1SS:"},
+ {FIRST_RATE_ENUM(HE_NSS2_MCS0), 12, 0, "HE 2SS:"},
+ {FIRST_RATE_GEV1(EHT_NSS1_MCS0), 14, 2, "EHT 1SS:"},
+ {FIRST_RATE_GEV1(EHT_NSS2_MCS0), 14, 0, "EHT 2SS:"},
};
static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
@@ -3345,7 +3363,9 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
struct rtw89_traffic_stats *stats = &rtwdev->stats;
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;
+ enum rtw89_hw_rate first_rate;
int i;
seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n",
@@ -3357,15 +3377,20 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
stats->rx_avg_len);
seq_puts(m, "RX count:\n");
+
for (i = 0; i < ARRAY_SIZE(rtw89_rx_rate_cnt_infos); i++) {
info = &rtw89_rx_rate_cnt_infos[i];
+ first_rate = info->first_rate[chip->chip_gen];
+ if (first_rate >= RTW89_HW_RATE_NR)
+ continue;
+
seq_printf(m, "%10s [", info->rate_mode);
rtw89_debug_append_rx_rate(m, pkt_stat,
- info->first_rate, info->len);
+ first_rate, info->len);
if (info->ext) {
seq_puts(m, "][");
rtw89_debug_append_rx_rate(m, pkt_stat,
- info->first_rate + info->len, info->ext);
+ first_rate + info->len, info->ext);
}
seq_puts(m, "]\n");
}
@@ -3569,7 +3594,7 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_btc_manual = {
};
static struct rtw89_debugfs_priv rtw89_debug_priv_fw_log_manual = {
- .cb_write = rtw89_debug_fw_log_btc_manual_set,
+ .cb_write = rtw89_debug_fw_log_manual_set,
};
static struct rtw89_debugfs_priv rtw89_debug_priv_phy_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 9637f5e48d84..df1dc2f43c86 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -9,6 +9,7 @@
#include "fw.h"
#include "mac.h"
#include "phy.h"
+#include "ps.h"
#include "reg.h"
#include "util.h"
@@ -86,8 +87,8 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
return 0;
}
-static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
- struct rtw89_fw_bin_info *info)
+static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
+ struct rtw89_fw_bin_info *info)
{
const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw;
struct rtw89_fw_hdr_section_info *section_info;
@@ -154,6 +155,94 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
return 0;
}
+static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
+ struct rtw89_fw_bin_info *info)
+{
+ const struct rtw89_fw_hdr_v1 *fw_hdr = (const struct rtw89_fw_hdr_v1 *)fw;
+ struct rtw89_fw_hdr_section_info *section_info;
+ const struct rtw89_fw_dynhdr_hdr *fwdynhdr;
+ const struct rtw89_fw_hdr_section_v1 *section;
+ const u8 *fw_end = fw + len;
+ const u8 *bin;
+ u32 base_hdr_len;
+ u32 mssc_len = 0;
+ u32 i;
+
+ info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_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_V1_W7_DYN_HDR);
+
+ if (info->dynamic_hdr_en) {
+ info->hdr_len = le32_get_bits(fw_hdr->w5, FW_HDR_V1_W5_HDR_SIZE);
+ info->dynamic_hdr_len = info->hdr_len - base_hdr_len;
+ fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len);
+ if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) {
+ rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n");
+ return -EINVAL;
+ }
+ } else {
+ info->hdr_len = base_hdr_len;
+ info->dynamic_hdr_len = 0;
+ }
+
+ bin = fw + info->hdr_len;
+
+ /* jump to section header */
+ section_info = info->section_info;
+ for (i = 0; i < info->section_num; i++) {
+ section = &fw_hdr->sections[i];
+ section_info->type =
+ le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SECTIONTYPE);
+ if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
+ section_info->mssc =
+ le32_get_bits(section->w2, FWSECTION_HDR_V1_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_V1_W1_SEC_SIZE);
+ if (le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_CHECKSUM))
+ section_info->len += FWDL_SECTION_CHKSUM_LEN;
+ section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_REDL);
+ section_info->dladdr =
+ le32_get_bits(section->w0, FWSECTION_HDR_V1_W0_DL_ADDR);
+ section_info->addr = bin;
+ bin += section_info->len;
+ section_info++;
+ }
+
+ if (fw_end != bin + mssc_len) {
+ rtw89_err(rtwdev, "[ERR]fw bin size\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit,
+ struct rtw89_fw_bin_info *info)
+{
+ const u8 *fw = fw_suit->data;
+ u32 len = fw_suit->size;
+
+ if (!fw || !len) {
+ rtw89_err(rtwdev, "fw type %d isn't recognized\n", fw_suit->type);
+ return -ENOENT;
+ }
+
+ switch (fw_suit->hdr_ver) {
+ case 0:
+ return rtw89_fw_hdr_parser_v0(rtwdev, fw, len, info);
+ case 1:
+ return rtw89_fw_hdr_parser_v1(rtwdev, fw, len, info);
+ default:
+ return -ENOENT;
+ }
+}
+
static
int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
struct rtw89_fw_suit *fw_suit, bool nowarn)
@@ -178,42 +267,110 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
for (i = 0; i < mfw_hdr->fw_nr; i++) {
mfw_info = &mfw_hdr->info[i];
- if (mfw_info->cv != rtwdev->hal.cv ||
- mfw_info->type != type ||
- mfw_info->mp)
- continue;
-
- fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
- fw_suit->size = le32_to_cpu(mfw_info->size);
- return 0;
+ if (mfw_info->type == type) {
+ if (mfw_info->cv == rtwdev->hal.cv && !mfw_info->mp)
+ goto found;
+ if (type == RTW89_FW_LOGFMT)
+ goto found;
+ }
}
if (!nowarn)
rtw89_err(rtwdev, "no suitable firmware found\n");
return -ENOENT;
+
+found:
+ fw_suit->data = mfw + le32_to_cpu(mfw_info->shift);
+ fw_suit->size = le32_to_cpu(mfw_info->size);
+ return 0;
}
-static void rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
- enum rtw89_fw_type type,
- struct rtw89_fw_suit *fw_suit)
+static u32 rtw89_mfw_get_size(struct rtw89_dev *rtwdev)
{
- const struct rtw89_fw_hdr *hdr = (const struct rtw89_fw_hdr *)fw_suit->data;
+ struct rtw89_fw_info *fw_info = &rtwdev->fw;
+ const struct firmware *firmware = fw_info->req.firmware;
+ const struct rtw89_mfw_hdr *mfw_hdr =
+ (const struct rtw89_mfw_hdr *)firmware->data;
+ const struct rtw89_mfw_info *mfw_info;
+ u32 size;
+
+ if (mfw_hdr->sig != RTW89_MFW_SIG) {
+ rtw89_warn(rtwdev, "not mfw format\n");
+ return 0;
+ }
+
+ mfw_info = &mfw_hdr->info[mfw_hdr->fw_nr - 1];
+ size = le32_to_cpu(mfw_info->shift) + le32_to_cpu(mfw_info->size);
+ return size;
+}
+
+static void rtw89_fw_update_ver_v0(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_suit *fw_suit,
+ const struct rtw89_fw_hdr *hdr)
+{
fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MAJOR_VERSION);
fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MINOR_VERSION);
fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_W1_SUBVERSION);
fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_W1_SUBINDEX);
+ fw_suit->commitid = le32_get_bits(hdr->w2, FW_HDR_W2_COMMITID);
fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_W5_YEAR);
fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_W4_MONTH);
fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_W4_DATE);
fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_W4_HOUR);
fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_W4_MIN);
fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_W7_CMD_VERSERION);
+}
+
+static void rtw89_fw_update_ver_v1(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_suit *fw_suit,
+ const struct rtw89_fw_hdr_v1 *hdr)
+{
+ fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_MAJOR_VERSION);
+ fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_MINOR_VERSION);
+ fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_V1_W1_SUBVERSION);
+ fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_V1_W1_SUBINDEX);
+ fw_suit->commitid = le32_get_bits(hdr->w2, FW_HDR_V1_W2_COMMITID);
+ fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_V1_W5_YEAR);
+ fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_V1_W4_MONTH);
+ fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_V1_W4_DATE);
+ fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_V1_W4_HOUR);
+ fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_V1_W4_MIN);
+ fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_V1_W3_CMD_VERSERION);
+}
+
+static int rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
+ enum rtw89_fw_type type,
+ struct rtw89_fw_suit *fw_suit)
+{
+ const struct rtw89_fw_hdr *v0 = (const struct rtw89_fw_hdr *)fw_suit->data;
+ const struct rtw89_fw_hdr_v1 *v1 = (const struct rtw89_fw_hdr_v1 *)fw_suit->data;
+
+ if (type == RTW89_FW_LOGFMT)
+ return 0;
+
+ fw_suit->type = type;
+ fw_suit->hdr_ver = le32_get_bits(v0->w3, FW_HDR_W3_HDR_VER);
+
+ switch (fw_suit->hdr_ver) {
+ case 0:
+ rtw89_fw_update_ver_v0(rtwdev, fw_suit, v0);
+ break;
+ case 1:
+ rtw89_fw_update_ver_v1(rtwdev, fw_suit, v1);
+ break;
+ default:
+ rtw89_err(rtwdev, "Unknown firmware header version %u\n",
+ fw_suit->hdr_ver);
+ return -ENOENT;
+ }
rtw89_info(rtwdev,
- "Firmware version %u.%u.%u.%u, cmd version %u, type %u\n",
+ "Firmware version %u.%u.%u.%u (%08x), cmd version %u, type %u\n",
fw_suit->major_ver, fw_suit->minor_ver, fw_suit->sub_ver,
- fw_suit->sub_idex, fw_suit->cmd_ver, type);
+ fw_suit->sub_idex, fw_suit->commitid, fw_suit->cmd_ver, type);
+
+ return 0;
}
static
@@ -227,9 +384,22 @@ int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
if (ret)
return ret;
- rtw89_fw_update_ver(rtwdev, type, fw_suit);
+ return rtw89_fw_update_ver(rtwdev, type, fw_suit);
+}
- return 0;
+static
+int __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const void *data)
+{
+ enum rtw89_fw_type type = (enum rtw89_fw_type)data;
+ struct rtw89_fw_suit *fw_suit;
+
+ fw_suit = rtw89_fw_suit_get(rtwdev, type);
+ fw_suit->data = elm->u.common.contents;
+ fw_suit->size = le32_to_cpu(elm->size);
+
+ return rtw89_fw_update_ver(rtwdev, type, fw_suit);
}
#define __DEF_FW_FEAT_COND(__cond, __op) \
@@ -312,31 +482,17 @@ rtw89_early_fw_feature_recognize(struct device *device,
struct rtw89_fw_info *early_fw,
int *used_fw_format)
{
- union rtw89_compat_fw_hdr buf = {};
const struct firmware *firmware;
- bool full_req = false;
char fw_name[64];
int fw_format;
u32 ver_code;
int ret;
- /* If SECURITY_LOADPIN_ENFORCE is enabled, reading partial files will
- * be denied (-EPERM). Then, we don't get right firmware things as
- * expected. So, in this case, we have to request full firmware here.
- */
- if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE))
- full_req = true;
-
for (fw_format = chip->fw_format_max; fw_format >= 0; fw_format--) {
rtw89_fw_get_filename(fw_name, sizeof(fw_name),
chip->fw_basename, fw_format);
- if (full_req)
- ret = request_firmware(&firmware, fw_name, device);
- else
- ret = request_partial_firmware_into_buf(&firmware, fw_name,
- device, &buf, sizeof(buf),
- 0);
+ ret = request_firmware(&firmware, fw_name, device);
if (!ret) {
dev_info(device, "loaded firmware %s\n", fw_name);
*used_fw_format = fw_format;
@@ -349,10 +505,7 @@ rtw89_early_fw_feature_recognize(struct device *device,
return NULL;
}
- if (full_req)
- ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data);
- else
- ver_code = rtw89_compat_fw_hdr_ver_code(&buf);
+ ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data);
if (!ver_code)
goto out;
@@ -360,11 +513,7 @@ rtw89_early_fw_feature_recognize(struct device *device,
rtw89_fw_iterate_feature_cfg(early_fw, chip, ver_code);
out:
- if (full_req)
- return firmware;
-
- release_firmware(firmware);
- return NULL;
+ return firmware;
}
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
@@ -386,6 +535,9 @@ normal_done:
/* It still works if wowlan firmware isn't existing. */
__rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN, false);
+ /* It still works if log format file isn't existing. */
+ __rtw89_fw_recognize(rtwdev, RTW89_FW_LOGFMT, true);
+
rtw89_fw_recognize_features(rtwdev);
rtw89_coex_recognize_ver(rtwdev);
@@ -393,6 +545,153 @@ normal_done:
return 0;
}
+static
+int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const void *data)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ struct rtw89_phy_table *tbl;
+ struct rtw89_reg2_def *regs;
+ enum rtw89_rf_path rf_path;
+ u32 n_regs, i;
+ u8 idx;
+
+ tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ return -ENOMEM;
+
+ switch (le32_to_cpu(elm->id)) {
+ case RTW89_FW_ELEMENT_ID_BB_REG:
+ elm_info->bb_tbl = tbl;
+ break;
+ case RTW89_FW_ELEMENT_ID_BB_GAIN:
+ elm_info->bb_gain = tbl;
+ break;
+ case RTW89_FW_ELEMENT_ID_RADIO_A:
+ case RTW89_FW_ELEMENT_ID_RADIO_B:
+ case RTW89_FW_ELEMENT_ID_RADIO_C:
+ case RTW89_FW_ELEMENT_ID_RADIO_D:
+ rf_path = (enum rtw89_rf_path)data;
+ idx = elm->u.reg2.idx;
+
+ elm_info->rf_radio[idx] = tbl;
+ tbl->rf_path = rf_path;
+ tbl->config = rtw89_phy_config_rf_reg_v1;
+ break;
+ case RTW89_FW_ELEMENT_ID_RF_NCTL:
+ elm_info->rf_nctl = tbl;
+ break;
+ default:
+ kfree(tbl);
+ return -ENOENT;
+ }
+
+ n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]);
+ regs = kcalloc(n_regs, sizeof(tbl->regs[0]), GFP_KERNEL);
+ if (!regs)
+ goto out;
+
+ for (i = 0; i < n_regs; i++) {
+ regs[i].addr = le32_to_cpu(elm->u.reg2.regs[i].addr);
+ regs[i].data = le32_to_cpu(elm->u.reg2.regs[i].data);
+ }
+
+ tbl->n_regs = n_regs;
+ tbl->regs = regs;
+
+ return 0;
+
+out:
+ kfree(tbl);
+ return -ENOMEM;
+}
+
+struct rtw89_fw_element_handler {
+ int (*fn)(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm, const void *data);
+ const void *data;
+ const char *name;
+};
+
+static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
+ [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
+ (const void *)RTW89_FW_BBMCU0, NULL},
+ [RTW89_FW_ELEMENT_ID_BBMCU1] = {__rtw89_fw_recognize_from_elm,
+ (const void *)RTW89_FW_BBMCU1, NULL},
+ [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, NULL, "BB"},
+ [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, NULL, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_A] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_A, "radio A"},
+ [RTW89_FW_ELEMENT_ID_RADIO_B] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_B, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_C] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_C, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_D] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_D, NULL},
+ [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, NULL, "NCTL"},
+};
+
+int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_info *fw_info = &rtwdev->fw;
+ const struct firmware *firmware = fw_info->req.firmware;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 unrecognized_elements = chip->needed_fw_elms;
+ const struct rtw89_fw_element_handler *handler;
+ const struct rtw89_fw_element_hdr *hdr;
+ u32 elm_size;
+ u32 elem_id;
+ u32 offset;
+ int ret;
+
+ BUILD_BUG_ON(sizeof(chip->needed_fw_elms) * 8 < RTW89_FW_ELEMENT_ID_NUM);
+
+ offset = rtw89_mfw_get_size(rtwdev);
+ offset = ALIGN(offset, RTW89_FW_ELEMENT_ALIGN);
+ if (offset == 0)
+ return -EINVAL;
+
+ while (offset + sizeof(*hdr) < firmware->size) {
+ hdr = (const struct rtw89_fw_element_hdr *)(firmware->data + offset);
+
+ elm_size = le32_to_cpu(hdr->size);
+ if (offset + elm_size >= firmware->size) {
+ rtw89_warn(rtwdev, "firmware element size exceeds\n");
+ break;
+ }
+
+ elem_id = le32_to_cpu(hdr->id);
+ if (elem_id >= ARRAY_SIZE(__fw_element_handlers))
+ goto next;
+
+ handler = &__fw_element_handlers[elem_id];
+ if (!handler->fn)
+ goto next;
+
+ ret = handler->fn(rtwdev, hdr, handler->data);
+ if (ret)
+ return ret;
+
+ if (handler->name)
+ rtw89_info(rtwdev, "Firmware element %s version: %4ph\n",
+ handler->name, hdr->ver);
+
+ unrecognized_elements &= ~BIT(elem_id);
+next:
+ offset += sizeof(*hdr) + elm_size;
+ offset = ALIGN(offset, RTW89_FW_ELEMENT_ALIGN);
+ }
+
+ if (unrecognized_elements) {
+ rtw89_err(rtwdev, "Firmware elements 0x%08x are unrecognized\n",
+ unrecognized_elements);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
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)
@@ -593,8 +892,6 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
struct rtw89_fw_info *fw_info = &rtwdev->fw;
struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
struct rtw89_fw_bin_info info;
- const u8 *fw = fw_suit->data;
- u32 len = fw_suit->size;
u8 val;
int ret;
@@ -603,12 +900,7 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
if (ret)
return ret;
- if (!fw || !len) {
- rtw89_err(rtwdev, "fw type %d isn't recognized\n", type);
- return -ENOENT;
- }
-
- ret = rtw89_fw_hdr_parser(rtwdev, fw, len, &info);
+ ret = rtw89_fw_hdr_parser(rtwdev, fw_suit, &info);
if (ret) {
rtw89_err(rtwdev, "parse fw header fail\n");
goto fwdl_err;
@@ -622,13 +914,14 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
goto fwdl_err;
}
- ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len - info.dynamic_hdr_len);
+ ret = rtw89_fw_download_hdr(rtwdev, fw_suit->data, info.hdr_len -
+ info.dynamic_hdr_len);
if (ret) {
ret = -EBUSY;
goto fwdl_err;
}
- ret = rtw89_fw_download_main(rtwdev, fw, &info);
+ ret = rtw89_fw_download_main(rtwdev, fw_suit->data, &info);
if (ret) {
ret = -EBUSY;
goto fwdl_err;
@@ -695,6 +988,27 @@ void rtw89_load_firmware_work(struct work_struct *work)
rtw89_load_firmware_req(rtwdev, &rtwdev->fw.req, fw_name, false);
}
+static void rtw89_free_phy_tbl_from_elm(struct rtw89_phy_table *tbl)
+{
+ if (!tbl)
+ return;
+
+ kfree(tbl->regs);
+ kfree(tbl);
+}
+
+static void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ int i;
+
+ rtw89_free_phy_tbl_from_elm(elm_info->bb_tbl);
+ rtw89_free_phy_tbl_from_elm(elm_info->bb_gain);
+ for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++)
+ rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]);
+ rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl);
+}
+
void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
{
struct rtw89_fw_info *fw = &rtwdev->fw;
@@ -709,6 +1023,151 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
*/
fw->req.firmware = NULL;
}
+
+ kfree(fw->log.fmts);
+ rtw89_unload_firmware_elements(rtwdev);
+}
+
+static u32 rtw89_fw_log_get_fmt_idx(struct rtw89_dev *rtwdev, u32 fmt_id)
+{
+ struct rtw89_fw_log *fw_log = &rtwdev->fw.log;
+ u32 i;
+
+ if (fmt_id > fw_log->last_fmt_id)
+ return 0;
+
+ for (i = 0; i < fw_log->fmt_count; i++) {
+ if (le32_to_cpu(fw_log->fmt_ids[i]) == fmt_id)
+ return i;
+ }
+ return 0;
+}
+
+static int rtw89_fw_log_create_fmts_dict(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_log *log = &rtwdev->fw.log;
+ const struct rtw89_fw_logsuit_hdr *suit_hdr;
+ struct rtw89_fw_suit *suit = &log->suit;
+ const void *fmts_ptr, *fmts_end_ptr;
+ u32 fmt_count;
+ int i;
+
+ suit_hdr = (const struct rtw89_fw_logsuit_hdr *)suit->data;
+ fmt_count = le32_to_cpu(suit_hdr->count);
+ log->fmt_ids = suit_hdr->ids;
+ fmts_ptr = &suit_hdr->ids[fmt_count];
+ fmts_end_ptr = suit->data + suit->size;
+ log->fmts = kcalloc(fmt_count, sizeof(char *), GFP_KERNEL);
+ if (!log->fmts)
+ return -ENOMEM;
+
+ for (i = 0; i < fmt_count; i++) {
+ fmts_ptr = memchr_inv(fmts_ptr, 0, fmts_end_ptr - fmts_ptr);
+ if (!fmts_ptr)
+ break;
+
+ (*log->fmts)[i] = fmts_ptr;
+ log->last_fmt_id = le32_to_cpu(log->fmt_ids[i]);
+ log->fmt_count++;
+ fmts_ptr += strlen(fmts_ptr);
+ }
+
+ return 0;
+}
+
+int rtw89_fw_log_prepare(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_log *log = &rtwdev->fw.log;
+ struct rtw89_fw_suit *suit = &log->suit;
+
+ if (!suit || !suit->data) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "no log format file\n");
+ return -EINVAL;
+ }
+ if (log->fmts)
+ return 0;
+
+ return rtw89_fw_log_create_fmts_dict(rtwdev);
+}
+
+static void rtw89_fw_log_dump_data(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_c2h_log_fmt *log_fmt,
+ u32 fmt_idx, u8 para_int, bool raw_data)
+{
+ const char *(*fmts)[] = rtwdev->fw.log.fmts;
+ char str_buf[RTW89_C2H_FW_LOG_STR_BUF_SIZE];
+ u32 args[RTW89_C2H_FW_LOG_MAX_PARA_NUM] = {0};
+ int i;
+
+ if (log_fmt->argc > RTW89_C2H_FW_LOG_MAX_PARA_NUM) {
+ rtw89_warn(rtwdev, "C2H log: Arg count is unexpected %d\n",
+ log_fmt->argc);
+ return;
+ }
+
+ if (para_int)
+ for (i = 0 ; i < log_fmt->argc; i++)
+ args[i] = le32_to_cpu(log_fmt->u.argv[i]);
+
+ if (raw_data) {
+ if (para_int)
+ snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE,
+ "fw_enc(%d, %d, %d) %*ph", le32_to_cpu(log_fmt->fmt_id),
+ para_int, log_fmt->argc, (int)sizeof(args), args);
+ else
+ snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE,
+ "fw_enc(%d, %d, %d, %s)", le32_to_cpu(log_fmt->fmt_id),
+ para_int, log_fmt->argc, log_fmt->u.raw);
+ } else {
+ snprintf(str_buf, RTW89_C2H_FW_LOG_STR_BUF_SIZE, (*fmts)[fmt_idx],
+ args[0x0], args[0x1], args[0x2], args[0x3], args[0x4],
+ args[0x5], args[0x6], args[0x7], args[0x8], args[0x9],
+ args[0xa], args[0xb], args[0xc], args[0xd], args[0xe],
+ args[0xf]);
+ }
+
+ rtw89_info(rtwdev, "C2H log: %s", str_buf);
+}
+
+void rtw89_fw_log_dump(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
+{
+ const struct rtw89_fw_c2h_log_fmt *log_fmt;
+ u8 para_int;
+ u32 fmt_idx;
+
+ if (len < RTW89_C2H_HEADER_LEN) {
+ rtw89_err(rtwdev, "c2h log length is wrong!\n");
+ return;
+ }
+
+ buf += RTW89_C2H_HEADER_LEN;
+ len -= RTW89_C2H_HEADER_LEN;
+ log_fmt = (const struct rtw89_fw_c2h_log_fmt *)buf;
+
+ if (len < RTW89_C2H_FW_FORMATTED_LOG_MIN_LEN)
+ goto plain_log;
+
+ if (log_fmt->signature != cpu_to_le16(RTW89_C2H_FW_LOG_SIGNATURE))
+ goto plain_log;
+
+ if (!rtwdev->fw.log.fmts)
+ return;
+
+ para_int = u8_get_bits(log_fmt->feature, RTW89_C2H_FW_LOG_FEATURE_PARA_INT);
+ fmt_idx = rtw89_fw_log_get_fmt_idx(rtwdev, le32_to_cpu(log_fmt->fmt_id));
+
+ if (!para_int && log_fmt->argc != 0 && fmt_idx != 0)
+ rtw89_info(rtwdev, "C2H log: %s%s",
+ (*rtwdev->fw.log.fmts)[fmt_idx], log_fmt->u.raw);
+ else if (fmt_idx != 0 && para_int)
+ rtw89_fw_log_dump_data(rtwdev, log_fmt, fmt_idx, para_int, false);
+ else
+ rtw89_fw_log_dump_data(rtwdev, log_fmt, fmt_idx, para_int, true);
+ return;
+
+plain_log:
+ rtw89_info(rtwdev, "C2H log: %.*s", len, buf);
+
}
#define H2C_CAM_LEN 60
@@ -922,7 +1381,7 @@ int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable)
}
skb_put(skb, H2C_LOG_CFG_LEN);
- SET_LOG_CFG_LEVEL(skb->data, RTW89_FW_LOG_LEVEL_SER);
+ SET_LOG_CFG_LEVEL(skb->data, RTW89_FW_LOG_LEVEL_LOUD);
SET_LOG_CFG_PATH(skb->data, BIT(RTW89_FW_LOG_LEVEL_C2H));
SET_LOG_CFG_COMP(skb->data, comp);
SET_LOG_CFG_COMP_EXT(skb->data, 0);
@@ -1300,7 +1759,8 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
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, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct sk_buff *skb;
u8 pads[RTW89_PPE_BW_NUM];
u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
@@ -1457,12 +1917,15 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct sk_buff *skb;
struct sk_buff *skb_beacon;
u16 tim_offset;
int bcn_total_len;
u16 beacon_rate;
+ void *noa_data;
+ u8 noa_len;
int ret;
if (vif->p2p)
@@ -1479,6 +1942,13 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
+ noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+ if (noa_len &&
+ (noa_len <= skb_tailroom(skb_beacon) ||
+ pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
+ skb_put_data(skb_beacon, noa_data, noa_len);
+ }
+
bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len);
if (!skb) {
@@ -1903,61 +2373,76 @@ fail:
return ret;
}
-#define H2C_RA_LEN 16
int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_h2c_ra_v1 *h2c_v1;
+ struct rtw89_h2c_ra *h2c;
+ u32 len = sizeof(*h2c);
+ bool format_v1 = false;
struct sk_buff *skb;
- u8 *cmd;
int ret;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_RA_LEN);
+ if (chip->chip_gen == RTW89_CHIP_BE) {
+ len = sizeof(*h2c_v1);
+ format_v1 = true;
+ }
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
}
- skb_put(skb, H2C_RA_LEN);
- cmd = skb->data;
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_ra *)skb->data;
rtw89_debug(rtwdev, RTW89_DBG_RA,
"ra cmd msk: %llx ", ra->ra_mask);
- RTW89_SET_FWCMD_RA_MODE(cmd, ra->mode_ctrl);
- RTW89_SET_FWCMD_RA_BW_CAP(cmd, ra->bw_cap);
- RTW89_SET_FWCMD_RA_MACID(cmd, ra->macid);
- RTW89_SET_FWCMD_RA_DCM(cmd, ra->dcm_cap);
- RTW89_SET_FWCMD_RA_ER(cmd, ra->er_cap);
- RTW89_SET_FWCMD_RA_INIT_RATE_LV(cmd, ra->init_rate_lv);
- RTW89_SET_FWCMD_RA_UPD_ALL(cmd, ra->upd_all);
- RTW89_SET_FWCMD_RA_SGI(cmd, ra->en_sgi);
- RTW89_SET_FWCMD_RA_LDPC(cmd, ra->ldpc_cap);
- RTW89_SET_FWCMD_RA_STBC(cmd, ra->stbc_cap);
- RTW89_SET_FWCMD_RA_SS_NUM(cmd, ra->ss_num);
- RTW89_SET_FWCMD_RA_GILTF(cmd, ra->giltf);
- RTW89_SET_FWCMD_RA_UPD_BW_NSS_MASK(cmd, ra->upd_bw_nss_mask);
- RTW89_SET_FWCMD_RA_UPD_MASK(cmd, ra->upd_mask);
- RTW89_SET_FWCMD_RA_MASK_0(cmd, FIELD_GET(MASKBYTE0, ra->ra_mask));
- RTW89_SET_FWCMD_RA_MASK_1(cmd, FIELD_GET(MASKBYTE1, ra->ra_mask));
- RTW89_SET_FWCMD_RA_MASK_2(cmd, FIELD_GET(MASKBYTE2, ra->ra_mask));
- RTW89_SET_FWCMD_RA_MASK_3(cmd, FIELD_GET(MASKBYTE3, ra->ra_mask));
- RTW89_SET_FWCMD_RA_MASK_4(cmd, FIELD_GET(MASKBYTE4, ra->ra_mask));
- RTW89_SET_FWCMD_RA_FIX_GILTF_EN(cmd, ra->fix_giltf_en);
- RTW89_SET_FWCMD_RA_FIX_GILTF(cmd, ra->fix_giltf);
-
- if (csi) {
- RTW89_SET_FWCMD_RA_BFEE_CSI_CTL(cmd, 1);
- RTW89_SET_FWCMD_RA_BAND_NUM(cmd, ra->band_num);
- RTW89_SET_FWCMD_RA_CR_TBL_SEL(cmd, ra->cr_tbl_sel);
- RTW89_SET_FWCMD_RA_FIXED_CSI_RATE_EN(cmd, ra->fixed_csi_rate_en);
- RTW89_SET_FWCMD_RA_RA_CSI_RATE_EN(cmd, ra->ra_csi_rate_en);
- RTW89_SET_FWCMD_RA_FIXED_CSI_MCS_SS_IDX(cmd, ra->csi_mcs_ss_idx);
- RTW89_SET_FWCMD_RA_FIXED_CSI_MODE(cmd, ra->csi_mode);
- RTW89_SET_FWCMD_RA_FIXED_CSI_GI_LTF(cmd, ra->csi_gi_ltf);
- RTW89_SET_FWCMD_RA_FIXED_CSI_BW(cmd, ra->csi_bw);
- }
-
+ h2c->w0 = le32_encode_bits(ra->mode_ctrl, RTW89_H2C_RA_W0_MODE) |
+ le32_encode_bits(ra->bw_cap, RTW89_H2C_RA_W0_BW_CAP) |
+ le32_encode_bits(ra->macid, RTW89_H2C_RA_W0_MACID) |
+ le32_encode_bits(ra->dcm_cap, RTW89_H2C_RA_W0_DCM) |
+ le32_encode_bits(ra->er_cap, RTW89_H2C_RA_W0_ER) |
+ le32_encode_bits(ra->init_rate_lv, RTW89_H2C_RA_W0_INIT_RATE_LV) |
+ le32_encode_bits(ra->upd_all, RTW89_H2C_RA_W0_UPD_ALL) |
+ le32_encode_bits(ra->en_sgi, RTW89_H2C_RA_W0_SGI) |
+ le32_encode_bits(ra->ldpc_cap, RTW89_H2C_RA_W0_LDPC) |
+ le32_encode_bits(ra->stbc_cap, RTW89_H2C_RA_W0_STBC) |
+ le32_encode_bits(ra->ss_num, RTW89_H2C_RA_W0_SS_NUM) |
+ le32_encode_bits(ra->giltf, RTW89_H2C_RA_W0_GILTF) |
+ le32_encode_bits(ra->upd_bw_nss_mask, RTW89_H2C_RA_W0_UPD_BW_NSS_MASK) |
+ le32_encode_bits(ra->upd_mask, RTW89_H2C_RA_W0_UPD_MASK);
+ h2c->w1 = le32_encode_bits(ra->ra_mask, RTW89_H2C_RA_W1_RAMASK_LO32);
+ h2c->w2 = le32_encode_bits(ra->ra_mask >> 32, RTW89_H2C_RA_W2_RAMASK_HI32);
+ h2c->w3 = le32_encode_bits(ra->fix_giltf_en, RTW89_H2C_RA_W3_FIX_GILTF_EN) |
+ le32_encode_bits(ra->fix_giltf, RTW89_H2C_RA_W3_FIX_GILTF);
+
+ if (!format_v1)
+ goto csi;
+
+ h2c_v1 = (struct rtw89_h2c_ra_v1 *)h2c;
+ h2c_v1->w4 = le32_encode_bits(ra->mode_ctrl, RTW89_H2C_RA_V1_W4_MODE_EHT) |
+ le32_encode_bits(ra->bw_cap, RTW89_H2C_RA_V1_W4_BW_EHT);
+
+csi:
+ if (!csi)
+ goto done;
+
+ h2c->w2 |= le32_encode_bits(1, RTW89_H2C_RA_W2_BFEE_CSI_CTL);
+ h2c->w3 |= le32_encode_bits(ra->band_num, RTW89_H2C_RA_W3_BAND_NUM) |
+ le32_encode_bits(ra->cr_tbl_sel, RTW89_H2C_RA_W3_CR_TBL_SEL) |
+ le32_encode_bits(ra->fixed_csi_rate_en, RTW89_H2C_RA_W3_FIXED_CSI_RATE_EN) |
+ le32_encode_bits(ra->ra_csi_rate_en, RTW89_H2C_RA_W3_RA_CSI_RATE_EN) |
+ le32_encode_bits(ra->csi_mcs_ss_idx, RTW89_H2C_RA_W3_FIXED_CSI_MCS_SS_IDX) |
+ le32_encode_bits(ra->csi_mode, RTW89_H2C_RA_W3_FIXED_CSI_MODE) |
+ le32_encode_bits(ra->csi_gi_ltf, RTW89_H2C_RA_W3_FIXED_CSI_GI_LTF) |
+ le32_encode_bits(ra->csi_bw, RTW89_H2C_RA_W3_FIXED_CSI_BW);
+
+done:
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RA,
H2C_FUNC_OUTSRC_RA_MACIDCFG, 0, 0,
- H2C_RA_LEN);
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
@@ -2815,12 +3300,13 @@ void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev)
static void rtw89_fw_c2h_parse_attr(struct sk_buff *c2h)
{
+ const struct rtw89_c2h_hdr *hdr = (const struct rtw89_c2h_hdr *)c2h->data;
struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h);
- attr->category = RTW89_GET_C2H_CATEGORY(c2h->data);
- attr->class = RTW89_GET_C2H_CLASS(c2h->data);
- attr->func = RTW89_GET_C2H_FUNC(c2h->data);
- attr->len = RTW89_GET_C2H_LEN(c2h->data);
+ attr->category = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_CATEGORY);
+ attr->class = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_CLASS);
+ attr->func = le32_get_bits(hdr->w0, RTW89_C2H_HDR_W0_FUNC);
+ attr->len = le32_get_bits(hdr->w1, RTW89_C2H_HDR_W1_LEN);
}
static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev,
@@ -3377,6 +3863,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
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;
u32 rx_fltr = rtwdev->hal.rx_fltr;
u8 mac_addr[ETH_ALEN];
@@ -3399,7 +3886,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
rx_fltr &= ~B_AX_A_BC;
rx_fltr &= ~B_AX_A_A1_MATCH;
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
rx_fltr);
}
@@ -3407,6 +3894,7 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
bool aborted)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct cfg80211_scan_info info = {
.aborted = aborted,
@@ -3417,7 +3905,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
return;
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
rtwdev->hal.rx_fltr);
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 45f927dc212e..775f4e8fbda4 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -291,160 +291,52 @@ struct rtw89_pktofld_info {
bool cancel;
};
-static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(0));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MODE(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(5, 1));
-}
-
-static inline void RTW89_SET_FWCMD_RA_BW_CAP(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(7, 6));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MACID(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(15, 8));
-}
-
-static inline void RTW89_SET_FWCMD_RA_DCM(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(16));
-}
-
-static inline void RTW89_SET_FWCMD_RA_ER(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(17));
-}
-
-static inline void RTW89_SET_FWCMD_RA_INIT_RATE_LV(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(19, 18));
-}
-
-static inline void RTW89_SET_FWCMD_RA_UPD_ALL(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(20));
-}
-
-static inline void RTW89_SET_FWCMD_RA_SGI(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(21));
-}
-
-static inline void RTW89_SET_FWCMD_RA_LDPC(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(22));
-}
-
-static inline void RTW89_SET_FWCMD_RA_STBC(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(23));
-}
-
-static inline void RTW89_SET_FWCMD_RA_SS_NUM(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(26, 24));
-}
-
-static inline void RTW89_SET_FWCMD_RA_GILTF(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, GENMASK(29, 27));
-}
-
-static inline void RTW89_SET_FWCMD_RA_UPD_BW_NSS_MASK(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(30));
-}
-
-static inline void RTW89_SET_FWCMD_RA_UPD_MASK(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x00, val, BIT(31));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MASK_0(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(7, 0));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MASK_1(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(15, 8));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MASK_2(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(23, 16));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MASK_3(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x01, val, GENMASK(31, 24));
-}
-
-static inline void RTW89_SET_FWCMD_RA_MASK_4(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x02, val, GENMASK(7, 0));
-}
-
-static inline void RTW89_SET_FWCMD_RA_BFEE_CSI_CTL(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x02, val, BIT(31));
-}
-
-static inline void RTW89_SET_FWCMD_RA_BAND_NUM(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(7, 0));
-}
-
-static inline void RTW89_SET_FWCMD_RA_RA_CSI_RATE_EN(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(8));
-}
-
-static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_RATE_EN(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(9));
-}
-
-static inline void RTW89_SET_FWCMD_RA_CR_TBL_SEL(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(10));
-}
-
-static inline void RTW89_SET_FWCMD_RA_FIX_GILTF_EN(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, BIT(11));
-}
-
-static inline void RTW89_SET_FWCMD_RA_FIX_GILTF(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(14, 12));
-}
-
-static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_MCS_SS_IDX(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(23, 16));
-}
-
-static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_MODE(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(25, 24));
-}
+struct rtw89_h2c_ra {
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+} __packed;
-static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_GI_LTF(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(28, 26));
-}
+#define RTW89_H2C_RA_W0_IS_DIS BIT(0)
+#define RTW89_H2C_RA_W0_MODE GENMASK(5, 1)
+#define RTW89_H2C_RA_W0_BW_CAP GENMASK(7, 6)
+#define RTW89_H2C_RA_W0_MACID GENMASK(15, 8)
+#define RTW89_H2C_RA_W0_DCM BIT(16)
+#define RTW89_H2C_RA_W0_ER BIT(17)
+#define RTW89_H2C_RA_W0_INIT_RATE_LV GENMASK(19, 18)
+#define RTW89_H2C_RA_W0_UPD_ALL BIT(20)
+#define RTW89_H2C_RA_W0_SGI BIT(21)
+#define RTW89_H2C_RA_W0_LDPC BIT(22)
+#define RTW89_H2C_RA_W0_STBC BIT(23)
+#define RTW89_H2C_RA_W0_SS_NUM GENMASK(26, 24)
+#define RTW89_H2C_RA_W0_GILTF GENMASK(29, 27)
+#define RTW89_H2C_RA_W0_UPD_BW_NSS_MASK BIT(30)
+#define RTW89_H2C_RA_W0_UPD_MASK BIT(31)
+#define RTW89_H2C_RA_W1_RAMASK_LO32 GENMASK(31, 0)
+#define RTW89_H2C_RA_W2_RAMASK_HI32 GENMASK(30, 0)
+#define RTW89_H2C_RA_W2_BFEE_CSI_CTL BIT(31)
+#define RTW89_H2C_RA_W3_BAND_NUM GENMASK(7, 0)
+#define RTW89_H2C_RA_W3_RA_CSI_RATE_EN BIT(8)
+#define RTW89_H2C_RA_W3_FIXED_CSI_RATE_EN BIT(9)
+#define RTW89_H2C_RA_W3_CR_TBL_SEL BIT(10)
+#define RTW89_H2C_RA_W3_FIX_GILTF_EN BIT(11)
+#define RTW89_H2C_RA_W3_FIX_GILTF GENMASK(14, 12)
+#define RTW89_H2C_RA_W3_FIXED_CSI_MCS_SS_IDX GENMASK(23, 16)
+#define RTW89_H2C_RA_W3_FIXED_CSI_MODE GENMASK(25, 24)
+#define RTW89_H2C_RA_W3_FIXED_CSI_GI_LTF GENMASK(28, 26)
+#define RTW89_H2C_RA_W3_FIXED_CSI_BW GENMASK(31, 29)
+
+struct rtw89_h2c_ra_v1 {
+ struct rtw89_h2c_ra v0;
+ __le32 w4;
+ __le32 w5;
+} __packed;
-static inline void RTW89_SET_FWCMD_RA_FIXED_CSI_BW(void *cmd, u32 val)
-{
- le32p_replace_bits((__le32 *)(cmd) + 0x03, val, GENMASK(31, 29));
-}
+#define RTW89_H2C_RA_V1_W4_MODE_EHT GENMASK(6, 0)
+#define RTW89_H2C_RA_V1_W4_BW_EHT GENMASK(10, 8)
+#define RTW89_H2C_RA_V1_W4_RAMASK_UHL16 GENMASK(31, 16)
+#define RTW89_H2C_RA_V1_W5_RAMASK_UHH16 GENMASK(15, 0)
static inline void RTW89_SET_FWCMD_SEC_IDX(void *cmd, u32 val)
{
@@ -571,7 +463,9 @@ struct rtw89_fw_hdr {
#define FW_HDR_W1_MINOR_VERSION GENMASK(15, 8)
#define FW_HDR_W1_SUBVERSION GENMASK(23, 16)
#define FW_HDR_W1_SUBINDEX GENMASK(31, 24)
+#define FW_HDR_W2_COMMITID GENMASK(31, 0)
#define FW_HDR_W3_LEN GENMASK(23, 16)
+#define FW_HDR_W3_HDR_VER GENMASK(31, 24)
#define FW_HDR_W4_MONTH GENMASK(7, 0)
#define FW_HDR_W4_DATE GENMASK(15, 8)
#define FW_HDR_W4_HOUR GENMASK(23, 16)
@@ -581,6 +475,54 @@ struct rtw89_fw_hdr {
#define FW_HDR_W7_DYN_HDR BIT(16)
#define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24)
+struct rtw89_fw_hdr_section_v1 {
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+} __packed;
+
+#define FWSECTION_HDR_V1_W0_DL_ADDR GENMASK(31, 0)
+#define FWSECTION_HDR_V1_W1_METADATA GENMASK(31, 24)
+#define FWSECTION_HDR_V1_W1_SECTIONTYPE GENMASK(27, 24)
+#define FWSECTION_HDR_V1_W1_SEC_SIZE GENMASK(23, 0)
+#define FWSECTION_HDR_V1_W1_CHECKSUM BIT(28)
+#define FWSECTION_HDR_V1_W1_REDL BIT(29)
+#define FWSECTION_HDR_V1_W2_MSSC GENMASK(7, 0)
+#define FWSECTION_HDR_V1_W2_BBMCU_IDX GENMASK(27, 24)
+
+struct rtw89_fw_hdr_v1 {
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+ __le32 w4;
+ __le32 w5;
+ __le32 w6;
+ __le32 w7;
+ __le32 w8;
+ __le32 w9;
+ __le32 w10;
+ __le32 w11;
+ struct rtw89_fw_hdr_section_v1 sections[];
+} __packed;
+
+#define FW_HDR_V1_W1_MAJOR_VERSION GENMASK(7, 0)
+#define FW_HDR_V1_W1_MINOR_VERSION GENMASK(15, 8)
+#define FW_HDR_V1_W1_SUBVERSION GENMASK(23, 16)
+#define FW_HDR_V1_W1_SUBINDEX GENMASK(31, 24)
+#define FW_HDR_V1_W2_COMMITID GENMASK(31, 0)
+#define FW_HDR_V1_W3_CMD_VERSERION GENMASK(23, 16)
+#define FW_HDR_V1_W3_HDR_VER GENMASK(31, 24)
+#define FW_HDR_V1_W4_MONTH GENMASK(7, 0)
+#define FW_HDR_V1_W4_DATE GENMASK(15, 8)
+#define FW_HDR_V1_W4_HOUR GENMASK(23, 16)
+#define FW_HDR_V1_W4_MIN GENMASK(31, 24)
+#define FW_HDR_V1_W5_YEAR GENMASK(15, 0)
+#define FW_HDR_V1_W5_HDR_SIZE GENMASK(31, 16)
+#define FW_HDR_V1_W6_SEC_NUM GENMASK(15, 8)
+#define FW_HDR_V1_W7_DYN_HDR BIT(16)
+
static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val)
{
le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0));
@@ -3209,14 +3151,15 @@ inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(void *cmd, u32 val)
#define RTW89_C2H_HEADER_LEN 8
-#define RTW89_GET_C2H_CATEGORY(c2h) \
- le32_get_bits(*((const __le32 *)c2h), GENMASK(1, 0))
-#define RTW89_GET_C2H_CLASS(c2h) \
- le32_get_bits(*((const __le32 *)c2h), GENMASK(7, 2))
-#define RTW89_GET_C2H_FUNC(c2h) \
- le32_get_bits(*((const __le32 *)c2h), GENMASK(15, 8))
-#define RTW89_GET_C2H_LEN(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(13, 0))
+struct rtw89_c2h_hdr {
+ __le32 w0;
+ __le32 w1;
+} __packed;
+
+#define RTW89_C2H_HDR_W0_CATEGORY GENMASK(1, 0)
+#define RTW89_C2H_HDR_W0_CLASS GENMASK(7, 2)
+#define RTW89_C2H_HDR_W0_FUNC GENMASK(15, 8)
+#define RTW89_C2H_HDR_W1_LEN GENMASK(13, 0)
struct rtw89_fw_c2h_attr {
u8 category;
@@ -3232,9 +3175,6 @@ static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb)
return (struct rtw89_fw_c2h_attr *)skb->cb;
}
-#define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2)
-#define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN)
-
struct rtw89_c2h_done_ack {
__le32 w0;
__le32 w1;
@@ -3256,6 +3196,26 @@ struct rtw89_c2h_done_ack {
#define RTW89_GET_MAC_C2H_REV_ACK_H2C_SEQ(c2h) \
le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16))
+struct rtw89_fw_c2h_log_fmt {
+ __le16 signature;
+ u8 feature;
+ u8 syntax;
+ __le32 fmt_id;
+ u8 file_num;
+ __le16 line_num;
+ u8 argc;
+ union {
+ DECLARE_FLEX_ARRAY(u8, raw);
+ DECLARE_FLEX_ARRAY(__le32, argv);
+ } __packed u;
+} __packed;
+
+#define RTW89_C2H_FW_FORMATTED_LOG_MIN_LEN 11
+#define RTW89_C2H_FW_LOG_FEATURE_PARA_INT BIT(2)
+#define RTW89_C2H_FW_LOG_MAX_PARA_NUM 16
+#define RTW89_C2H_FW_LOG_SIGNATURE 0xA5A5
+#define RTW89_C2H_FW_LOG_STR_BUF_SIZE 512
+
struct rtw89_c2h_mac_bcnfltr_rpt {
__le32 w0;
__le32 w1;
@@ -3267,24 +3227,32 @@ struct rtw89_c2h_mac_bcnfltr_rpt {
#define RTW89_C2H_MAC_BCNFLTR_RPT_W2_EVENT GENMASK(11, 10)
#define RTW89_C2H_MAC_BCNFLTR_RPT_W2_MA GENMASK(23, 16)
-#define RTW89_GET_PHY_C2H_RA_RPT_MACID(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 0))
-#define RTW89_GET_PHY_C2H_RA_RPT_RETRY_RATIO(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16))
-#define RTW89_GET_PHY_C2H_RA_RPT_MCSNSS(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(6, 0))
-#define RTW89_GET_PHY_C2H_RA_RPT_MD_SEL(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(9, 8))
-#define RTW89_GET_PHY_C2H_RA_RPT_GILTF(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(12, 10))
-#define RTW89_GET_PHY_C2H_RA_RPT_BW(c2h) \
- le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(14, 13))
-
-/* VHT, HE, HT-old: [6:4]: NSS, [3:0]: MCS
- * HT-new: [6:5]: NA, [4:0]: MCS
+struct rtw89_c2h_ra_rpt {
+ struct rtw89_c2h_hdr hdr;
+ __le32 w2;
+ __le32 w3;
+} __packed;
+
+#define RTW89_C2H_RA_RPT_W2_MACID GENMASK(15, 0)
+#define RTW89_C2H_RA_RPT_W2_RETRY_RATIO GENMASK(23, 16)
+#define RTW89_C2H_RA_RPT_W2_MCSNSS_B7 BIT(31)
+#define RTW89_C2H_RA_RPT_W3_MCSNSS GENMASK(6, 0)
+#define RTW89_C2H_RA_RPT_W3_MD_SEL GENMASK(9, 8)
+#define RTW89_C2H_RA_RPT_W3_GILTF GENMASK(12, 10)
+#define RTW89_C2H_RA_RPT_W3_BW GENMASK(14, 13)
+#define RTW89_C2H_RA_RPT_W3_MD_SEL_B2 BIT(15)
+#define RTW89_C2H_RA_RPT_W3_BW_B2 BIT(16)
+
+/* For WiFi 6 chips:
+ * VHT, HE, HT-old: [6:4]: NSS, [3:0]: MCS
+ * HT-new: [6:5]: NA, [4:0]: MCS
+ * For WiFi 7 chips (V1):
+ * HT, VHT, HE, EHT: [7:5]: NSS, [4:0]: MCS
*/
#define RTW89_RA_RATE_MASK_NSS GENMASK(6, 4)
#define RTW89_RA_RATE_MASK_MCS GENMASK(3, 0)
+#define RTW89_RA_RATE_MASK_NSS_V1 GENMASK(7, 5)
+#define RTW89_RA_RATE_MASK_MCS_V1 GENMASK(4, 0)
#define RTW89_RA_RATE_MASK_HT_MCS GENMASK(4, 0)
#define RTW89_MK_HT_RATE(nss, mcs) (FIELD_PREP(GENMASK(4, 3), nss) | \
FIELD_PREP(GENMASK(2, 0), mcs))
@@ -3426,6 +3394,51 @@ struct rtw89_mfw_hdr {
struct rtw89_mfw_info info[];
} __packed;
+struct rtw89_fw_logsuit_hdr {
+ __le32 rsvd;
+ __le32 count;
+ __le32 ids[];
+} __packed;
+
+#define RTW89_FW_ELEMENT_ALIGN 16
+
+enum rtw89_fw_element_id {
+ RTW89_FW_ELEMENT_ID_BBMCU0 = 0,
+ RTW89_FW_ELEMENT_ID_BBMCU1 = 1,
+ RTW89_FW_ELEMENT_ID_BB_REG = 2,
+ RTW89_FW_ELEMENT_ID_BB_GAIN = 3,
+ RTW89_FW_ELEMENT_ID_RADIO_A = 4,
+ RTW89_FW_ELEMENT_ID_RADIO_B = 5,
+ RTW89_FW_ELEMENT_ID_RADIO_C = 6,
+ RTW89_FW_ELEMENT_ID_RADIO_D = 7,
+ RTW89_FW_ELEMENT_ID_RF_NCTL = 8,
+
+ RTW89_FW_ELEMENT_ID_NUM,
+};
+
+struct rtw89_fw_element_hdr {
+ __le32 id; /* enum rtw89_fw_element_id */
+ __le32 size; /* exclude header size */
+ u8 ver[4];
+ __le32 rsvd0;
+ __le32 rsvd1;
+ __le32 rsvd2;
+ union {
+ struct {
+ u8 priv[8];
+ u8 contents[];
+ } __packed common;
+ struct {
+ u8 idx;
+ u8 rsvd[7];
+ struct {
+ __le32 addr;
+ __le32 data;
+ } __packed regs[];
+ } __packed reg2;
+ } __packed u;
+} __packed;
+
struct fwcmd_hdr {
__le32 hdr0;
__le32 hdr1;
@@ -3607,6 +3620,7 @@ struct rtw89_fw_h2c_rf_get_mccch {
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
+int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev);
const struct firmware *
rtw89_early_fw_feature_recognize(struct device *device,
const struct rtw89_chip_info *chip,
@@ -3616,6 +3630,8 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
void rtw89_load_firmware_work(struct work_struct *work);
void rtw89_unload_firmware(struct rtw89_dev *rtwdev);
int rtw89_wait_firmware_completion(struct rtw89_dev *rtwdev);
+int rtw89_fw_log_prepare(struct rtw89_dev *rtwdev);
+void rtw89_fw_log_dump(struct rtw89_dev *rtwdev, u8 *buf, u32 len);
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);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index c93e6250cb8b..fab9f5004a75 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -12,7 +12,7 @@
#include "reg.h"
#include "util.h"
-const u32 rtw89_mac_mem_base_addrs[RTW89_MAC_MEM_NUM] = {
+static const u32 rtw89_mac_mem_base_addrs_ax[RTW89_MAC_MEM_NUM] = {
[RTW89_MAC_MEM_AXIDMA] = AXIDMA_BASE_ADDR,
[RTW89_MAC_MEM_SHARED_BUF] = SHARED_BUF_BASE_ADDR,
[RTW89_MAC_MEM_DMAC_TBL] = DMAC_TBL_BASE_ADDR,
@@ -39,19 +39,21 @@ const u32 rtw89_mac_mem_base_addrs[RTW89_MAC_MEM_NUM] = {
static void rtw89_mac_mem_write(struct rtw89_dev *rtwdev, u32 offset,
u32 val, enum rtw89_mac_mem_sel sel)
{
- u32 addr = rtw89_mac_mem_base_addrs[sel] + offset;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 addr = mac->mem_base_addrs[sel] + offset;
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, addr);
- rtw89_write32(rtwdev, R_AX_INDIR_ACCESS_ENTRY, val);
+ rtw89_write32(rtwdev, mac->filter_model_addr, addr);
+ rtw89_write32(rtwdev, mac->indir_access_addr, val);
}
static u32 rtw89_mac_mem_read(struct rtw89_dev *rtwdev, u32 offset,
enum rtw89_mac_mem_sel sel)
{
- u32 addr = rtw89_mac_mem_base_addrs[sel] + offset;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 addr = mac->mem_base_addrs[sel] + offset;
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, addr);
- return rtw89_read32(rtwdev, R_AX_INDIR_ACCESS_ENTRY);
+ rtw89_write32(rtwdev, mac->filter_model_addr, addr);
+ return rtw89_read32(rtwdev, mac->indir_access_addr);
}
int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 mac_idx,
@@ -2082,7 +2084,7 @@ static int addr_cam_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_ADDR_CAM_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_ADDR_CAM_CTRL, mac_idx);
val = rtw89_read32(rtwdev, reg);
val |= u32_encode_bits(0x7f, B_AX_ADDR_CAM_RANGE_MASK) |
@@ -2109,7 +2111,7 @@ static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_PREBKF_CFG_1, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PREBKF_CFG_1, mac_idx);
if (rtwdev->chip->chip_id == RTL8852C)
rtw89_write32_mask(rtwdev, reg, B_AX_SIFS_MACTXEN_T1_MASK,
SIFS_MACTXEN_T1_V1);
@@ -2118,14 +2120,14 @@ static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx)
SIFS_MACTXEN_T1);
if (rtwdev->chip->chip_id == RTL8852B || rtwdev->chip->chip_id == RTL8851B) {
- reg = rtw89_mac_reg_by_idx(R_AX_SCH_EXT_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_SCH_EXT_CTRL, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_PORT_RST_TSF_ADV);
}
- reg = rtw89_mac_reg_by_idx(R_AX_CCA_CFG_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CCA_CFG_0, mac_idx);
rtw89_write32_clr(rtwdev, reg, B_AX_BTCCA_EN);
- reg = rtw89_mac_reg_by_idx(R_AX_PREBKF_CFG_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PREBKF_CFG_0, mac_idx);
if (rtwdev->chip->chip_id == RTL8852C) {
val = rtw89_read32_mask(rtwdev, R_AX_SEC_ENG_CTRL,
B_AX_TX_PARTIAL_MODE);
@@ -2165,13 +2167,13 @@ int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev,
switch (type) {
case RTW89_MGNT:
- reg = rtw89_mac_reg_by_idx(R_AX_MGNT_FLTR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_MGNT_FLTR, mac_idx);
break;
case RTW89_CTRL:
- reg = rtw89_mac_reg_by_idx(R_AX_CTRL_FLTR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CTRL_FLTR, mac_idx);
break;
case RTW89_DATA:
- reg = rtw89_mac_reg_by_idx(R_AX_DATA_FLTR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_DATA_FLTR, mac_idx);
break;
default:
rtw89_err(rtwdev, "[ERR]set rx filter type err\n");
@@ -2202,9 +2204,9 @@ static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx)
B_AX_LSIG_PARITY_CHK_EN | B_AX_SIGA_CRC_CHK |
B_AX_VHT_SU_SIGB_CRC_CHK | B_AX_VHT_MU_SIGB_CRC_CHK |
B_AX_HE_SIGB_CRC_CHK;
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, mac_idx),
+ rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_RX_FLTR_OPT, mac_idx),
mac_ftlr);
- rtw89_write16(rtwdev, rtw89_mac_reg_by_idx(R_AX_PLCP_HDR_FLTR, mac_idx),
+ rtw89_write16(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_PLCP_HDR_FLTR, mac_idx),
plcp_ftlr);
return 0;
@@ -2224,20 +2226,20 @@ static void _patch_dis_resp_chk(struct rtw89_dev *rtwdev, u8 mac_idx)
switch (rtwdev->chip->chip_id) {
case RTL8852A:
case RTL8852B:
- reg = rtw89_mac_reg_by_idx(R_AX_RSP_CHK_SIG, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RSP_CHK_SIG, mac_idx);
val32 = rtw89_read32(rtwdev, reg) & ~b_rsp_chk_nav;
rtw89_write32(rtwdev, reg, val32);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_0, mac_idx);
val32 = rtw89_read32(rtwdev, reg) & ~b_rsp_chk_cca;
rtw89_write32(rtwdev, reg, val32);
break;
default:
- reg = rtw89_mac_reg_by_idx(R_AX_RSP_CHK_SIG, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RSP_CHK_SIG, mac_idx);
val32 = rtw89_read32(rtwdev, reg) | b_rsp_chk_nav;
rtw89_write32(rtwdev, reg, val32);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_0, mac_idx);
val32 = rtw89_read32(rtwdev, reg) | b_rsp_chk_cca;
rtw89_write32(rtwdev, reg, val32);
break;
@@ -2253,7 +2255,7 @@ static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_CCA_CONTROL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CCA_CONTROL, mac_idx);
val = rtw89_read32(rtwdev, reg);
val |= (B_AX_TB_CHK_BASIC_NAV | B_AX_TB_CHK_BTCCA |
B_AX_TB_CHK_EDCCA | B_AX_TB_CHK_CCA_P20 |
@@ -2294,7 +2296,7 @@ static int spatial_reuse_init(struct rtw89_dev *rtwdev, u8 mac_idx)
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_RX_SR_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RX_SR_CTRL, mac_idx);
rtw89_write8_clr(rtwdev, reg, B_AX_SR_EN);
return 0;
@@ -2309,13 +2311,13 @@ static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_MAC_LOOPBACK, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_MAC_LOOPBACK, mac_idx);
rtw89_write32_clr(rtwdev, reg, B_AX_MACLBK_EN);
- reg = rtw89_mac_reg_by_idx(R_AX_TCR0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TCR0, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_TCR_UDF_THSD_MASK, TCR_UDF_THSD);
- reg = rtw89_mac_reg_by_idx(R_AX_TXD_FIFO_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXD_FIFO_CTRL, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_TXDFIFO_HIGH_MCS_THRE_MASK, TXDFIFO_HIGH_MCS_THRE);
rtw89_write32_mask(rtwdev, reg, B_AX_TXDFIFO_LOW_MCS_THRE_MASK, TXDFIFO_LOW_MCS_THRE);
@@ -2333,7 +2335,7 @@ static int trxptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_0, mac_idx);
val = rtw89_read32(rtwdev, reg);
val &= ~B_AX_WMAC_SPEC_SIFS_CCK_MASK;
val |= FIELD_PREP(B_AX_WMAC_SPEC_SIFS_CCK_MASK, WMAC_SPEC_SIFS_CCK);
@@ -2353,12 +2355,12 @@ static int trxptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
val |= FIELD_PREP(B_AX_WMAC_SPEC_SIFS_OFDM_MASK, sifs);
rtw89_write32(rtwdev, reg, val);
- reg = rtw89_mac_reg_by_idx(R_AX_RXTRIG_TEST_USER_2, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RXTRIG_TEST_USER_2, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_RXTRIG_FCSCHK_EN);
- reg = rtw89_mac_reg_by_idx(rrsr->ref_rate.addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, rrsr->ref_rate.addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, rrsr->ref_rate.mask, rrsr->ref_rate.data);
- reg = rtw89_mac_reg_by_idx(rrsr->rsc.addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, rrsr->rsc.addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, rrsr->rsc.mask, rrsr->rsc.data);
return 0;
@@ -2397,10 +2399,10 @@ static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (mac_idx == RTW89_MAC_0)
rst_bacam(rtwdev);
- reg = rtw89_mac_reg_by_idx(R_AX_RESPBA_CAM_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RESPBA_CAM_CTRL, mac_idx);
rtw89_write8_set(rtwdev, reg, B_AX_SSN_SEL);
- reg = rtw89_mac_reg_by_idx(R_AX_DLK_PROTECT_CTL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_DLK_PROTECT_CTL, mac_idx);
val = rtw89_read16(rtwdev, reg);
val = u16_replace_bits(val, TRXCFG_RMAC_DATA_TO,
B_AX_RX_DLK_DATA_TIME_MASK);
@@ -2408,10 +2410,10 @@ static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
B_AX_RX_DLK_CCA_TIME_MASK);
rtw89_write16(rtwdev, reg, val);
- reg = rtw89_mac_reg_by_idx(R_AX_RCR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RCR, mac_idx);
rtw89_write8_mask(rtwdev, reg, B_AX_CH_EN_MASK, 0x1);
- reg = rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RX_FLTR_OPT, mac_idx);
if (mac_idx == RTW89_MAC_0)
rx_qta = rtwdev->mac.dle_info.c0_rx_qta;
else
@@ -2425,13 +2427,13 @@ static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (rtwdev->chip->chip_id == RTL8852A &&
rtwdev->hal.cv == CHIP_CBV) {
rtw89_write16_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_DLK_PROTECT_CTL, mac_idx),
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_DLK_PROTECT_CTL, mac_idx),
B_AX_RX_DLK_CCA_TIME_MASK, 0);
- rtw89_write16_set(rtwdev, rtw89_mac_reg_by_idx(R_AX_RCR, mac_idx),
+ rtw89_write16_set(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_RCR, mac_idx),
BIT(12));
}
- reg = rtw89_mac_reg_by_idx(R_AX_PLCP_HDR_FLTR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PLCP_HDR_FLTR, mac_idx);
rtw89_write8_clr(rtwdev, reg, B_AX_VHT_SU_SIGB_CRC_CHK);
return ret;
@@ -2447,7 +2449,7 @@ static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
val = rtw89_read32(rtwdev, reg);
val = u32_replace_bits(val, 0, B_AX_TXSC_20M_MASK);
val = u32_replace_bits(val, 0, B_AX_TXSC_40M_MASK);
@@ -2455,7 +2457,7 @@ static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx)
rtw89_write32(rtwdev, reg, val);
if (chip_id == RTL8852A || chip_id == RTL8852B) {
- reg = rtw89_mac_reg_by_idx(R_AX_PTCL_RRSR1, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_RRSR1, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_RRSR_RATE_EN_MASK, RRSR_OFDM_CCK_EN);
}
@@ -2485,7 +2487,7 @@ static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return ret;
if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) {
- reg = rtw89_mac_reg_by_idx(R_AX_SIFS_SETTING, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_SIFS_SETTING, mac_idx);
val = rtw89_read32(rtwdev, reg);
val = u32_replace_bits(val, S_AX_CTS2S_TH_1K,
B_AX_HW_CTS2SELF_PKT_LEN_TH_MASK);
@@ -2494,7 +2496,7 @@ static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
val |= B_AX_HW_CTS2SELF_EN;
rtw89_write32(rtwdev, reg, val);
- reg = rtw89_mac_reg_by_idx(R_AX_PTCL_FSM_MON, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_FSM_MON, mac_idx);
val = rtw89_read32(rtwdev, reg);
val = u32_replace_bits(val, S_AX_PTCL_TO_2MS, B_AX_PTCL_TX_ARB_TO_THR_MASK);
val &= ~B_AX_PTCL_TX_ARB_TO_MODE;
@@ -2531,7 +2533,7 @@ static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_RXDMA_CTRL_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RXDMA_CTRL_0, mac_idx);
rtw89_write8_clr(rtwdev, reg, RX_FULL_MODE);
return 0;
@@ -2725,7 +2727,7 @@ static int rtw89_hw_sch_tx_en_h2c(struct rtw89_dev *rtwdev, u8 band,
static int rtw89_set_hw_sch_tx_en(struct rtw89_dev *rtwdev, u8 mac_idx,
u16 tx_en, u16 tx_en_mask)
{
- u32 reg = rtw89_mac_reg_by_idx(R_AX_CTN_TXEN, mac_idx);
+ u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CTN_TXEN, mac_idx);
u16 val;
int ret;
@@ -2747,7 +2749,7 @@ static int rtw89_set_hw_sch_tx_en(struct rtw89_dev *rtwdev, u8 mac_idx,
static int rtw89_set_hw_sch_tx_en_v1(struct rtw89_dev *rtwdev, u8 mac_idx,
u32 tx_en, u32 tx_en_mask)
{
- u32 reg = rtw89_mac_reg_by_idx(R_AX_CTN_DRV_TXEN, mac_idx);
+ u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CTN_DRV_TXEN, mac_idx);
u32 val;
int ret;
@@ -2768,7 +2770,7 @@ int rtw89_mac_stop_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx,
int ret;
*tx_en = rtw89_read16(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_CTN_TXEN, mac_idx));
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_CTN_TXEN, mac_idx));
switch (sel) {
case RTW89_SCH_TX_SEL_ALL:
@@ -2809,7 +2811,7 @@ int rtw89_mac_stop_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx,
int ret;
*tx_en = rtw89_read32(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_CTN_DRV_TXEN, mac_idx));
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_CTN_DRV_TXEN, mac_idx));
switch (sel) {
case RTW89_SCH_TX_SEL_ALL:
@@ -3016,7 +3018,7 @@ static int band_idle_ck_b(struct rtw89_dev *rtwdev, u8 mac_idx)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_PTCL_TX_CTN_SEL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_TX_CTN_SEL, mac_idx);
ret = read_poll_timeout(rtw89_read8, val,
(val & B_AX_PTCL_TX_ON_STAT) == 0,
@@ -3224,7 +3226,7 @@ static void rtw89_scheduler_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 reg;
- reg = rtw89_mac_reg_by_idx(R_AX_SCHEDULE_ERR_IMR, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_SCHEDULE_ERR_IMR, mac_idx);
rtw89_write32_clr(rtwdev, reg, B_AX_SORT_NON_IDLE_ERR_INT_EN |
B_AX_FSM_TIMEOUT_ERR_INT_EN);
rtw89_write32_set(rtwdev, reg, B_AX_FSM_TIMEOUT_ERR_INT_EN);
@@ -3235,7 +3237,7 @@ static void rtw89_ptcl_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
const struct rtw89_imr_info *imr = rtwdev->chip->imr_info;
u32 reg;
- reg = rtw89_mac_reg_by_idx(R_AX_PTCL_IMR0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_IMR0, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->ptcl_imr_clr);
rtw89_write32_set(rtwdev, reg, imr->ptcl_imr_set);
}
@@ -3246,12 +3248,12 @@ static void rtw89_cdma_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 reg;
- reg = rtw89_mac_reg_by_idx(imr->cdma_imr_0_reg, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, imr->cdma_imr_0_reg, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->cdma_imr_0_clr);
rtw89_write32_set(rtwdev, reg, imr->cdma_imr_0_set);
if (chip_id == RTL8852C) {
- reg = rtw89_mac_reg_by_idx(imr->cdma_imr_1_reg, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, imr->cdma_imr_1_reg, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->cdma_imr_1_clr);
rtw89_write32_set(rtwdev, reg, imr->cdma_imr_1_set);
}
@@ -3262,7 +3264,7 @@ static void rtw89_phy_intf_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
const struct rtw89_imr_info *imr = rtwdev->chip->imr_info;
u32 reg;
- reg = rtw89_mac_reg_by_idx(imr->phy_intf_imr_reg, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, imr->phy_intf_imr_reg, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->phy_intf_imr_clr);
rtw89_write32_set(rtwdev, reg, imr->phy_intf_imr_set);
}
@@ -3272,7 +3274,7 @@ static void rtw89_rmac_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
const struct rtw89_imr_info *imr = rtwdev->chip->imr_info;
u32 reg;
- reg = rtw89_mac_reg_by_idx(imr->rmac_imr_reg, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, imr->rmac_imr_reg, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->rmac_imr_clr);
rtw89_write32_set(rtwdev, reg, imr->rmac_imr_set);
}
@@ -3282,7 +3284,7 @@ static void rtw89_tmac_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
const struct rtw89_imr_info *imr = rtwdev->chip->imr_info;
u32 reg;
- reg = rtw89_mac_reg_by_idx(imr->tmac_imr_reg, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, imr->tmac_imr_reg, mac_idx);
rtw89_write32_clr(rtwdev, reg, imr->tmac_imr_clr);
rtw89_write32_set(rtwdev, reg, imr->tmac_imr_set);
}
@@ -3661,6 +3663,9 @@ static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid)
{
u8 i;
+ if (rtwdev->chip->chip_gen != RTW89_CHIP_AX)
+ return;
+
for (i = 0; i < 4; i++) {
rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR,
DMAC_TBL_BASE_ADDR + (macid << 4) + (i << 2));
@@ -3670,6 +3675,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)
+ return;
+
rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR,
CMAC_TBL_BASE_ADDR + macid * CCTL_INFO_SIZE);
rtw89_write32(rtwdev, R_AX_INDIR_ACCESS_ENTRY, 0x4);
@@ -3860,7 +3868,7 @@ static void rtw89_mac_port_cfg_hiq_win(struct rtw89_dev *rtwdev,
u8 port = rtwvif->port;
u32 reg;
- reg = rtw89_mac_reg_by_idx(hiq_win_addr[port], rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, hiq_win_addr[port], rtwvif->mac_idx);
rtw89_write8(rtwdev, reg, win);
}
@@ -3871,7 +3879,7 @@ static void rtw89_mac_port_cfg_hiq_dtim(struct rtw89_dev *rtwdev,
const struct rtw89_port_reg *p = &rtw_port_base;
u32 addr;
- addr = rtw89_mac_reg_by_idx(R_AX_MD_TSFT_STMP_CTL, rtwvif->mac_idx);
+ addr = rtw89_mac_reg_by_idx(rtwdev, R_AX_MD_TSFT_STMP_CTL, rtwvif->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,
@@ -3930,7 +3938,7 @@ static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev,
bss_color = vif->bss_conf.he_bss_color.color;
reg_base = port >= 4 ? R_AX_PTCL_BSS_COLOR_1 : R_AX_PTCL_BSS_COLOR_0;
- reg = rtw89_mac_reg_by_idx(reg_base, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif->mac_idx);
rtw89_write32_mask(rtwdev, reg, masks[port], bss_color);
}
@@ -3944,7 +3952,7 @@ static void rtw89_mac_port_cfg_mbssid(struct rtw89_dev *rtwdev,
return;
if (port == 0) {
- reg = rtw89_mac_reg_by_idx(R_AX_MBSSID_CTRL, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_MBSSID_CTRL, rtwvif->mac_idx);
rtw89_write32_clr(rtwdev, reg, B_AX_P0MB_ALL_MASK);
}
}
@@ -3956,7 +3964,7 @@ static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev,
u32 reg;
u32 val;
- reg = rtw89_mac_reg_by_idx(R_AX_MBSSID_DROP_0, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_MBSSID_DROP_0, rtwvif->mac_idx);
val = rtw89_read32(rtwdev, reg);
val &= ~FIELD_PREP(B_AX_PORT_DROP_4_0_MASK, BIT(port));
if (port == 0)
@@ -4014,7 +4022,7 @@ 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(R_AX_PORT0_TSF_SYNC + rtwvif->port * 4,
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PORT0_TSF_SYNC + rtwvif->port * 4,
rtwvif->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port);
@@ -4204,7 +4212,7 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
rtw89_mac_check_he_obss_narrow_bw_ru_iter,
&tolerated);
- reg = rtw89_mac_reg_by_idx(R_AX_RXTRIG_TEST_USER_2, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_RXTRIG_TEST_USER_2, rtwvif->mac_idx);
if (tolerated)
rtw89_write32_clr(rtwdev, reg, B_AX_RXTRIG_RU26_DIS);
else
@@ -4437,8 +4445,7 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le
static void
rtw89_mac_c2h_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
- rtw89_info(rtwdev, "%*s", RTW89_GET_C2H_LOG_LEN(len),
- RTW89_GET_C2H_LOG_SRT_PRT(c2h->data));
+ rtw89_fw_log_dump(rtwdev, c2h->data, len);
}
static void
@@ -4732,7 +4739,7 @@ bool rtw89_mac_get_txpwr_cr(struct rtw89_dev *rtwdev,
{
const struct rtw89_dle_mem *dle_mem = rtwdev->chip->dle_mem;
enum rtw89_qta_mode mode = dle_mem->mode;
- u32 addr = rtw89_mac_reg_by_idx(reg_base, phy_idx);
+ u32 addr = rtw89_mac_reg_by_idx(rtwdev, reg_base, phy_idx);
if (addr < R_AX_PWR_RATE_CTRL || addr > CMAC1_END_ADDR) {
rtw89_err(rtwdev, "[TXPWR] addr=0x%x exceed txpwr cr\n",
@@ -4761,7 +4768,7 @@ EXPORT_SYMBOL(rtw89_mac_get_txpwr_cr);
int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable)
{
- u32 reg = rtw89_mac_reg_by_idx(R_AX_PPDU_STAT, mac_idx);
+ u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PPDU_STAT, mac_idx);
int ret;
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
@@ -4808,7 +4815,7 @@ void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx)
time_th = min_t(u32, time_th >> MAC_AX_TIME_TH_SH, MAC_AX_TIME_TH_MAX);
len_th = min_t(u32, len_th >> MAC_AX_LEN_TH_SH, MAC_AX_LEN_TH_MAX);
- reg = rtw89_mac_reg_by_idx(R_AX_AGG_LEN_HT_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_AGG_LEN_HT_0, mac_idx);
rtw89_write16_mask(rtwdev, reg, B_AX_RTS_TXTIME_TH_MASK, time_th);
rtw89_write16_mask(rtwdev, reg, B_AX_RTS_LEN_TH_MASK, len_th);
}
@@ -5044,7 +5051,7 @@ int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt)
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_BT_PLT, plt->band);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BT_PLT, plt->band);
val = (plt->tx & RTW89_MAC_AX_PLT_LTE_RX ? B_AX_TX_PLT_GNT_LTE_RX : 0) |
(plt->tx & RTW89_MAC_AX_PLT_GNT_BT_TX ? B_AX_TX_PLT_GNT_BT_TX : 0) |
(plt->tx & RTW89_MAC_AX_PLT_GNT_BT_RX ? B_AX_TX_PLT_GNT_BT_RX : 0) |
@@ -5134,7 +5141,7 @@ u16 rtw89_mac_get_plt_cnt(struct rtw89_dev *rtwdev, u8 band)
u32 reg;
u16 cnt;
- reg = rtw89_mac_reg_by_idx(R_AX_BT_PLT, band);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BT_PLT, band);
cnt = rtw89_read32_mask(rtwdev, reg, B_AX_BT_PLT_PKT_CNT_MASK);
rtw89_write16_set(rtwdev, reg, B_AX_BT_PLT_RST);
@@ -5147,7 +5154,7 @@ static void rtw89_mac_bfee_standby_timer(struct rtw89_dev *rtwdev, u8 mac_idx,
u32 reg;
rtw89_debug(rtwdev, RTW89_DBG_BF, "set bfee standby_timer to %d\n", keep);
- reg = rtw89_mac_reg_by_idx(R_AX_BFMEE_RESP_OPTION, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BFMEE_RESP_OPTION, mac_idx);
if (keep) {
set_bit(RTW89_FLAG_BFEE_TIMER_KEEP, rtwdev->flags);
rtw89_write32_mask(rtwdev, reg, B_AX_BFMEE_BFRP_RX_STANDBY_TIMER_MASK,
@@ -5166,7 +5173,7 @@ static void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en)
B_AX_BFMEE_HE_NDPA_EN;
rtw89_debug(rtwdev, RTW89_DBG_BF, "set bfee ndpa_en to %d\n", en);
- reg = rtw89_mac_reg_by_idx(R_AX_BFMEE_RESP_OPTION, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BFMEE_RESP_OPTION, mac_idx);
if (en) {
set_bit(RTW89_FLAG_BFEE_EN, rtwdev->flags);
rtw89_write32_set(rtwdev, reg, mask);
@@ -5188,30 +5195,30 @@ static int rtw89_mac_init_bfee(struct rtw89_dev *rtwdev, u8 mac_idx)
/* AP mode set tx gid to 63 */
/* STA mode set tx gid to 0(default) */
- reg = rtw89_mac_reg_by_idx(R_AX_BFMER_CTRL_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BFMER_CTRL_0, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_BFMER_NDP_BFEN);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_RRSC, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_RRSC, mac_idx);
rtw89_write32(rtwdev, reg, CSI_RRSC_BMAP);
- reg = rtw89_mac_reg_by_idx(R_AX_BFMEE_RESP_OPTION, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BFMEE_RESP_OPTION, mac_idx);
val32 = FIELD_PREP(B_AX_BFMEE_NDP_RX_STANDBY_TIMER_MASK, NDP_RX_STANDBY_TIMER);
rtw89_write32(rtwdev, reg, val32);
rtw89_mac_bfee_standby_timer(rtwdev, mac_idx, true);
rtw89_mac_bfee_ctrl(rtwdev, mac_idx, true);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
+ 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 |
B_AX_BFMEE_USE_NSTS |
B_AX_BFMEE_CSI_GID_SEL |
B_AX_BFMEE_CSI_FORCE_RETE_EN);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_RATE, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_RATE, mac_idx);
rtw89_write32(rtwdev, reg,
u32_encode_bits(CSI_INIT_RATE_HT, B_AX_BFMEE_HT_CSI_RATE_MASK) |
u32_encode_bits(CSI_INIT_RATE_VHT, B_AX_BFMEE_VHT_CSI_RATE_MASK) |
u32_encode_bits(CSI_INIT_RATE_HE, B_AX_BFMEE_HE_CSI_RATE_MASK));
- reg = rtw89_mac_reg_by_idx(R_AX_CSIRPT_OPTION, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_CSIRPT_OPTION, mac_idx);
rtw89_write32_set(rtwdev, reg,
B_AX_CSIPRT_VHTSU_AID_EN | B_AX_CSIPRT_HESU_AID_EN);
@@ -5255,7 +5262,7 @@ static int rtw89_mac_set_csi_para_reg(struct rtw89_dev *rtwdev,
nc = min(nc, sound_dim);
nr = min(nr, sound_dim);
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
+ 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);
val = FIELD_PREP(B_AX_BFMEE_CSIINFO0_NC_MASK, nc) |
@@ -5267,9 +5274,9 @@ static int rtw89_mac_set_csi_para_reg(struct rtw89_dev *rtwdev,
FIELD_PREP(B_AX_BFMEE_CSIINFO0_STBC_EN, stbc_en);
if (port_sel == 0)
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
else
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_1, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_1, mac_idx);
rtw89_write16(rtwdev, reg, val);
@@ -5305,11 +5312,11 @@ static int rtw89_mac_csi_rrsc(struct rtw89_dev *rtwdev,
BIT(RTW89_MAC_BF_RRSC_HT_MSC3) |
BIT(RTW89_MAC_BF_RRSC_HT_MSC5));
}
- reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
+ 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);
rtw89_write32(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_RRSC, mac_idx),
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_RRSC, mac_idx),
rrsc);
return 0;
@@ -5347,19 +5354,21 @@ void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *
rtw89_debug(rtwdev, RTW89_DBG_BF, "update bf GID table\n");
p = (__le32 *)conf->mu_group.membership;
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION_EN0, mac_idx),
+ rtw89_write32(rtwdev,
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION_EN0, mac_idx),
le32_to_cpu(p[0]));
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION_EN1, mac_idx),
+ rtw89_write32(rtwdev,
+ rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION_EN1, mac_idx),
le32_to_cpu(p[1]));
p = (__le32 *)conf->mu_group.position;
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION0, mac_idx),
+ rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION0, mac_idx),
le32_to_cpu(p[0]));
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION1, mac_idx),
+ rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION1, mac_idx),
le32_to_cpu(p[1]));
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION2, mac_idx),
+ rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION2, mac_idx),
le32_to_cpu(p[2]));
- rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_GID_POSITION3, mac_idx),
+ rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(rtwdev, R_AX_GID_POSITION3, mac_idx),
le32_to_cpu(p[3]));
}
@@ -5450,7 +5459,7 @@ __rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
return ret;
}
- reg = rtw89_mac_reg_by_idx(R_AX_AMPDU_AGG_LIMIT, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_AMPDU_AGG_LIMIT, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_AMPDU_MAX_TIME_MASK,
max_tx_time >> 5);
}
@@ -5490,7 +5499,7 @@ int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
return ret;
}
- reg = rtw89_mac_reg_by_idx(R_AX_AMPDU_AGG_LIMIT, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_AMPDU_AGG_LIMIT, mac_idx);
*tx_time = rtw89_read32_mask(rtwdev, reg, B_AX_AMPDU_MAX_TIME_MASK) << 5;
}
@@ -5532,7 +5541,7 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
return ret;
}
- reg = rtw89_mac_reg_by_idx(R_AX_TXCNT, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXCNT, mac_idx);
*tx_retry = rtw89_read32_mask(rtwdev, reg, B_AX_L_TXCNT_LMT_MASK);
}
@@ -5551,7 +5560,7 @@ int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev,
if (ret)
return ret;
- reg = rtw89_mac_reg_by_idx(R_AX_MUEDCA_EN, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_MUEDCA_EN, mac_idx);
if (en)
rtw89_write16_set(rtwdev, reg, set);
else
@@ -5674,3 +5683,12 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
}
return ret;
}
+
+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,
+ .indir_access_addr = R_AX_INDIR_ACCESS_ENTRY,
+ .mem_base_addrs = rtw89_mac_mem_base_addrs_ax,
+ .rx_fltr = R_AX_RX_FLTR_OPT,
+};
+EXPORT_SYMBOL(rtw89_mac_gen_ax);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 0e1570451c2c..7cf34137c0bc 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -275,6 +275,7 @@ enum rtw89_mac_dbg_port_sel {
/* SRAM mem dump */
#define R_AX_INDIR_ACCESS_ENTRY 0x40000
+#define R_BE_INDIR_ACCESS_ENTRY 0x80000
#define AXIDMA_BASE_ADDR 0x18006000
#define STA_SCHED_BASE_ADDR 0x18808000
@@ -298,6 +299,31 @@ enum rtw89_mac_dbg_port_sel {
#define TXDATA_FIFO_1_BASE_ADDR 0x188A1000
#define CPU_LOCAL_BASE_ADDR 0x18003000
+#define WD_PAGE_BASE_ADDR_BE 0x0
+#define CPU_LOCAL_BASE_ADDR_BE 0x18003000
+#define AXIDMA_BASE_ADDR_BE 0x18006000
+#define SHARED_BUF_BASE_ADDR_BE 0x18700000
+#define DMAC_TBL_BASE_ADDR_BE 0x18800000
+#define SHCUT_MACHDR_BASE_ADDR_BE 0x18800800
+#define STA_SCHED_BASE_ADDR_BE 0x18818000
+#define NAT25_CAM_BASE_ADDR_BE 0x18820000
+#define RXPLD_FLTR_CAM_BASE_ADDR_BE 0x18823000
+#define SEC_CAM_BASE_ADDR_BE 0x18824000
+#define WOW_CAM_BASE_ADDR_BE 0x18828000
+#define MLD_TBL_BASE_ADDR_BE 0x18829000
+#define RX_CLSF_CAM_BASE_ADDR_BE 0x1882A000
+#define CMAC_TBL_BASE_ADDR_BE 0x18840000
+#define ADDR_CAM_BASE_ADDR_BE 0x18850000
+#define BSSID_CAM_BASE_ADDR_BE 0x18858000
+#define BA_CAM_BASE_ADDR_BE 0x18859000
+#define BCN_IE_CAM0_BASE_ADDR_BE 0x18860000
+#define TXDATA_FIFO_0_BASE_ADDR_BE 0x18861000
+#define TXD_FIFO_0_BASE_ADDR_BE 0x18862000
+#define BCN_IE_CAM1_BASE_ADDR_BE 0x18880000
+#define TXDATA_FIFO_1_BASE_ADDR_BE 0x18881000
+#define TXD_FIFO_1_BASE_ADDR_BE 0x18881800
+#define DCPU_LOCAL_BASE_ADDR_BE 0x19C02000
+
#define CCTL_INFO_SIZE 32
enum rtw89_mac_mem_sel {
@@ -322,13 +348,12 @@ enum rtw89_mac_mem_sel {
RTW89_MAC_MEM_BSSID_CAM,
RTW89_MAC_MEM_TXD_FIFO_0_V1,
RTW89_MAC_MEM_TXD_FIFO_1_V1,
+ RTW89_MAC_MEM_WD_PAGE,
/* keep last */
RTW89_MAC_MEM_NUM,
};
-extern const u32 rtw89_mac_mem_base_addrs[];
-
enum rtw89_rpwm_req_pwr_state {
RTW89_MAC_RPWM_REQ_PWR_STATE_ACTIVE = 0,
RTW89_MAC_RPWM_REQ_PWR_STATE_BAND0_RFON = 1,
@@ -478,6 +503,7 @@ enum rtw89_mac_bf_rrsc_rate {
({typeof(_addr) __addr = (_addr); \
__addr >= R_AX_CMAC_REG_START && __addr <= R_AX_CMAC_REG_END; })
#define RTW89_MAC_AX_BAND_REG_OFFSET 0x2000
+#define RTW89_MAC_BE_BAND_REG_OFFSET 0x4000
#define PTCL_IDLE_POLL_CNT 10000
#define SW_CVR_DUR_US 8
@@ -826,14 +852,29 @@ struct rtw89_mac_size_set {
extern const struct rtw89_mac_size_set rtw89_mac_size;
-static inline u32 rtw89_mac_reg_by_idx(u32 reg_base, u8 band)
+struct rtw89_mac_gen_def {
+ u32 band1_offset;
+ u32 filter_model_addr;
+ u32 indir_access_addr;
+ const u32 *mem_base_addrs;
+ u32 rx_fltr;
+};
+
+extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax;
+extern const struct rtw89_mac_gen_def rtw89_mac_gen_be;
+
+static inline
+u32 rtw89_mac_reg_by_idx(struct rtw89_dev *rtwdev, u32 reg_base, u8 band)
{
- return band == 0 ? reg_base : (reg_base + 0x2000);
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ return band == 0 ? reg_base : (reg_base + mac->band1_offset);
}
-static inline u32 rtw89_mac_reg_by_port(u32 base, u8 port, u8 mac_idx)
+static inline
+u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_idx)
{
- return rtw89_mac_reg_by_idx(base + port * 0x40, mac_idx);
+ return rtw89_mac_reg_by_idx(rtwdev, base + port * 0x40, mac_idx);
}
static inline u32
@@ -841,7 +882,7 @@ rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
return rtw89_read32(rtwdev, reg);
}
@@ -851,7 +892,7 @@ rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
return rtw89_read32_mask(rtwdev, reg, mask);
}
@@ -861,7 +902,7 @@ rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write32(rtwdev, reg, data);
}
@@ -871,7 +912,7 @@ rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write32_mask(rtwdev, reg, mask, data);
}
@@ -881,7 +922,7 @@ rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write16_mask(rtwdev, reg, mask, data);
}
@@ -891,7 +932,7 @@ rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write32_clr(rtwdev, reg, bit);
}
@@ -901,7 +942,7 @@ rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write16_clr(rtwdev, reg, bit);
}
@@ -911,7 +952,7 @@ rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
{
u32 reg;
- reg = rtw89_mac_reg_by_port(base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
rtw89_write32_set(rtwdev, reg, bit);
}
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index a66503eb35b8..5e48618706d9 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -224,6 +224,7 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
u64 multicast)
{
struct rtw89_dev *rtwdev = hw->priv;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
@@ -271,13 +272,13 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
}
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
rtwdev->hal.rx_fltr);
if (!rtwdev->dbcc_en)
goto out;
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_1),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1),
B_AX_RX_FLTR_CFG_MASK,
rtwdev->hal.rx_fltr);
@@ -296,7 +297,8 @@ static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif, u8 aifsn)
{
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
u8 slot_time;
u8 sifs;
@@ -353,7 +355,7 @@ static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev,
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(ac_to_mu_edca_param[ac], rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac], rtwvif->mac_idx);
rtw89_write32(rtwdev, reg, val);
rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true);
@@ -413,6 +415,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
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_queue_chanctx_work(rtwdev);
} else {
/* Abort ongoing scan if cancel_scan isn't issued
* when disconnected by peer
@@ -476,6 +480,8 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
rtw89_chip_rfk_channel(rtwdev);
+
+ rtw89_queue_chanctx_work(rtwdev);
mutex_unlock(&rtwdev->mutex);
return 0;
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
new file mode 100644
index 000000000000..9a63fb35e867
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#include "mac.h"
+#include "reg.h"
+
+static const u32 rtw89_mac_mem_base_addrs_be[RTW89_MAC_MEM_NUM] = {
+ [RTW89_MAC_MEM_AXIDMA] = AXIDMA_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_SHARED_BUF] = SHARED_BUF_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_DMAC_TBL] = DMAC_TBL_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_SHCUT_MACHDR] = SHCUT_MACHDR_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_STA_SCHED] = STA_SCHED_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_RXPLD_FLTR_CAM] = RXPLD_FLTR_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_SECURITY_CAM] = SEC_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_WOW_CAM] = WOW_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_CMAC_TBL] = CMAC_TBL_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_ADDR_CAM] = ADDR_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_BA_CAM] = BA_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_BCN_IE_CAM0] = BCN_IE_CAM0_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_BCN_IE_CAM1] = BCN_IE_CAM1_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_TXD_FIFO_0] = TXD_FIFO_0_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_TXD_FIFO_1] = TXD_FIFO_1_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_TXDATA_FIFO_0] = TXDATA_FIFO_0_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_TXDATA_FIFO_1] = TXDATA_FIFO_1_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_CPU_LOCAL] = CPU_LOCAL_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_BSSID_CAM] = BSSID_CAM_BASE_ADDR_BE,
+ [RTW89_MAC_MEM_WD_PAGE] = WD_PAGE_BASE_ADDR_BE,
+};
+
+const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
+ .band1_offset = RTW89_MAC_BE_BAND_REG_OFFSET,
+ .filter_model_addr = R_BE_FILTER_MODEL_ADDR,
+ .indir_access_addr = R_BE_INDIR_ACCESS_ENTRY,
+ .mem_base_addrs = rtw89_mac_mem_base_addrs_be,
+ .rx_fltr = R_BE_RX_FLTR_OPT,
+};
+EXPORT_SYMBOL(rtw89_mac_gen_be);
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 9402f1a0caea..3a4bfc44142b 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -3939,5 +3939,5 @@ void rtw89_pci_remove(struct pci_dev *pdev)
EXPORT_SYMBOL(rtw89_pci_remove);
MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ax wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ax wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index fb15c852fdd4..7139146cb3fa 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -133,10 +133,10 @@ 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 *rtwsta,
+ const struct rtw89_chan *chan)
{
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
enum nl80211_band band;
u64 cfg_mask;
@@ -197,9 +197,9 @@ rtw89_ra_mask_he_rates[4] = {RA_MASK_HE_1SS_RATES, RA_MASK_HE_2SS_RATES,
static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
struct rtw89_sta *rtwsta,
+ const struct rtw89_chan *chan,
bool *fix_giltf_en, u8 *fix_giltf)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
u8 band = chan->band_type;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
@@ -236,7 +236,8 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
struct rtw89_ra_info *ra = &rtwsta->ra;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif);
const u64 *high_rate_masks = rtw89_ra_mask_ht_rates;
u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi);
@@ -265,7 +266,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
if (sta->deflink.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, &fix_giltf_en, &fix_giltf);
+ 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);
@@ -332,7 +333,7 @@ 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);
+ ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan);
switch (sta->deflink.bandwidth) {
case IEEE80211_STA_RX_BW_160:
@@ -362,7 +363,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
ra->dcm_cap = 1;
if (rate_pattern->enable && !vif->p2p) {
- ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta);
+ ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan);
ra_mask &= rate_pattern->ra_mask;
mode = rate_pattern->ra_mode;
}
@@ -444,6 +445,12 @@ static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
return true;
}
+#define RTW89_HW_RATE_BY_CHIP_GEN(rate) \
+ { \
+ [RTW89_CHIP_AX] = RTW89_HW_RATE_ ## rate, \
+ [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)
@@ -451,40 +458,48 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
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, RTW89_SUB_ENTITY_0);
- static const u16 hw_rate_he[] = {RTW89_HW_RATE_HE_NSS1_MCS0,
- RTW89_HW_RATE_HE_NSS2_MCS0,
- RTW89_HW_RATE_HE_NSS3_MCS0,
- RTW89_HW_RATE_HE_NSS4_MCS0};
- static const u16 hw_rate_vht[] = {RTW89_HW_RATE_VHT_NSS1_MCS0,
- RTW89_HW_RATE_VHT_NSS2_MCS0,
- RTW89_HW_RATE_VHT_NSS3_MCS0,
- RTW89_HW_RATE_VHT_NSS4_MCS0};
- static const u16 hw_rate_ht[] = {RTW89_HW_RATE_MCS0,
- RTW89_HW_RATE_MCS8,
- RTW89_HW_RATE_MCS16,
- RTW89_HW_RATE_MCS24};
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_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),
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS3_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS4_MCS0),
+ };
+ static const u16 hw_rate_vht[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS1_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS2_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS3_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS4_MCS0),
+ };
+ static const u16 hw_rate_ht[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS8),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS16),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS24),
+ };
u8 band = chan->band_type;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
u8 tx_nss = rtwdev->hal.tx_nss;
u8 i;
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_he[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_he[i][chip_gen],
RA_MASK_HE_RATES, RTW89_RA_MODE_HE,
mask->control[nl_band].he_mcs[i],
0, true))
goto out;
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_vht[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_vht[i][chip_gen],
RA_MASK_VHT_RATES, RTW89_RA_MODE_VHT,
mask->control[nl_band].vht_mcs[i],
0, true))
goto out;
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_ht[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_ht[i][chip_gen],
RA_MASK_HT_RATES, RTW89_RA_MODE_HT,
mask->control[nl_band].ht_mcs[i],
0, true))
@@ -1342,12 +1357,16 @@ static void rtw89_phy_init_reg(struct rtw89_dev *rtwdev,
void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_phy_table *bb_table = chip->bb_table;
- const struct rtw89_phy_table *bb_gain_table = chip->bb_gain_table;
+ const struct rtw89_phy_table *bb_table;
+ const struct rtw89_phy_table *bb_gain_table;
+ bb_table = elm_info->bb_tbl ? elm_info->bb_tbl : chip->bb_table;
rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL);
rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
+
+ 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,
rtw89_phy_config_bb_gain, NULL);
@@ -1365,6 +1384,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
{
void (*config)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path, void *data);
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_phy_table *rf_table;
struct rtw89_fw_h2c_rf_reg_info *rf_reg_info;
@@ -1375,7 +1395,8 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
return;
for (path = RF_PATH_A; path < chip->rf_path_num; path++) {
- rf_table = chip->rf_table[path];
+ rf_table = elm_info->rf_radio[path] ?
+ elm_info->rf_radio[path] : chip->rf_table[path];
rf_reg_info->rf_path = rf_table->rf_path;
if (noio)
config = rtw89_phy_config_rf_reg_noio;
@@ -1392,6 +1413,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_phy_table *nctl_table;
u32 val;
@@ -1414,7 +1436,7 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
if (ret)
rtw89_err(rtwdev, "failed to poll nctl block\n");
- nctl_table = chip->nctl_table;
+ nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table;
rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL);
if (chip->nctl_post_table)
@@ -1426,6 +1448,9 @@ static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr)
u32 phy_page = addr >> 8;
u32 ofst = 0;
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return addr < 0x10000 ? 0x20000 : 0;
+
switch (phy_page) {
case 0x6:
case 0x7:
@@ -1627,6 +1652,8 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
u8 regd = rtw89_regd_get(rtwdev, band);
u8 reg6 = regulatory->reg_6ghz_power;
@@ -1662,7 +1689,7 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
}
lmt = _phy_txpwr_rf_to_mac(rtwdev, lmt);
- sar = rtw89_query_sar(rtwdev);
+ sar = rtw89_query_sar(rtwdev, freq);
return min(lmt, sar);
}
@@ -1882,6 +1909,8 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
u8 regd = rtw89_regd_get(rtwdev, band);
u8 reg6 = regulatory->reg_6ghz_power;
@@ -1917,7 +1946,7 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
}
lmt_ru = _phy_txpwr_rf_to_mac(rtwdev, lmt_ru);
- sar = rtw89_query_sar(rtwdev);
+ sar = rtw89_query_sar(rtwdev, freq);
return min(lmt_ru, sar);
}
@@ -2231,21 +2260,34 @@ 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_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 sk_buff *c2h = ra_data->c2h;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
u8 mode, rate, bw, giltf, mac_id;
u16 legacy_bitrate;
bool valid;
u8 mcs = 0;
+ u8 t;
- mac_id = RTW89_GET_PHY_C2H_RA_RPT_MACID(c2h->data);
+ mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID);
if (mac_id != rtwsta->mac_id)
return;
- rate = RTW89_GET_PHY_C2H_RA_RPT_MCSNSS(c2h->data);
- bw = RTW89_GET_PHY_C2H_RA_RPT_BW(c2h->data);
- giltf = RTW89_GET_PHY_C2H_RA_RPT_GILTF(c2h->data);
- mode = RTW89_GET_PHY_C2H_RA_RPT_MD_SEL(c2h->data);
+ rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS);
+ bw = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW);
+ giltf = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_GILTF);
+ mode = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL);
+
+ if (format_v1) {
+ t = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MCSNSS_B7);
+ rate |= u8_encode_bits(t, BIT(7));
+ t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW_B2);
+ bw |= u8_encode_bits(t, BIT(2));
+ t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL_B2);
+ mode |= u8_encode_bits(t, BIT(2));
+ }
if (mode == RTW89_RA_RPT_MODE_LEGACY) {
valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate);
@@ -2273,16 +2315,24 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
break;
case RTW89_RA_RPT_MODE_VHT:
ra_report->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
- ra_report->txrate.mcs = FIELD_GET(RTW89_RA_RATE_MASK_MCS, rate);
- ra_report->txrate.nss = FIELD_GET(RTW89_RA_RATE_MASK_NSS, rate) + 1;
+ ra_report->txrate.mcs = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
+ ra_report->txrate.nss = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
if (giltf)
ra_report->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
mcs = ra_report->txrate.mcs;
break;
case RTW89_RA_RPT_MODE_HE:
ra_report->txrate.flags |= RATE_INFO_FLAGS_HE_MCS;
- ra_report->txrate.mcs = FIELD_GET(RTW89_RA_RATE_MASK_MCS, rate);
- ra_report->txrate.nss = FIELD_GET(RTW89_RA_RATE_MASK_NSS, rate) + 1;
+ ra_report->txrate.mcs = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
+ ra_report->txrate.nss = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
if (giltf == RTW89_GILTF_2XHE08 || giltf == RTW89_GILTF_1XHE08)
ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_0_8;
else if (giltf == RTW89_GILTF_2XHE16 || giltf == RTW89_GILTF_1XHE16)
@@ -2295,8 +2345,11 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
ra_report->txrate.bw = rtw89_hw_to_rate_info_bw(bw);
ra_report->bit_rate = cfg80211_calculate_bitrate(&ra_report->txrate);
- ra_report->hw_rate = FIELD_PREP(RTW89_HW_RATE_MASK_MOD, mode) |
- FIELD_PREP(RTW89_HW_RATE_MASK_VAL, rate);
+ ra_report->hw_rate = format_v1 ?
+ u16_encode_bits(mode, RTW89_HW_RATE_V1_MASK_MOD) |
+ u16_encode_bits(rate, RTW89_HW_RATE_V1_MASK_VAL) :
+ 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;
@@ -2841,7 +2894,8 @@ void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val,
void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
if (!chip->support_ul_tb_ctrl)
@@ -2977,7 +3031,7 @@ static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu,
struct rtw89_antdiv_stats *stats)
{
- if (GET_DATA_RATE_MODE(phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) {
+ if (rtw89_get_data_rate_mode(rtwdev, phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) {
if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) {
ewma_rssi_add(&stats->cck_rssi_avg, phy_ppdu->rssi_avg);
stats->pkt_cnt_cck++;
@@ -3183,7 +3237,9 @@ static u32 rtw89_phy_ccx_idx_to_us(struct rtw89_dev *rtwdev, u16 idx)
static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
env->ccx_manual_ctrl = false;
env->ccx_ongoing = false;
@@ -3191,10 +3247,10 @@ static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev)
env->ccx_period = 0;
env->ccx_unit_idx = RTW89_CCX_32_US;
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EN_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_TRIG_OPT_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EDCCA_OPT_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->en_mask, 1);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->trig_opt_mask, 1);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->edcca_opt_mask,
RTW89_CCX_EDCCA_BW20_0);
}
@@ -3309,25 +3365,27 @@ ifs_update_finished:
static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u8 i = 0;
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_LOW_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_th_l_mask,
env->ifs_clm_th_l[0]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_LOW_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_th_l_mask,
env->ifs_clm_th_l[1]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_LOW_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_th_l_mask,
env->ifs_clm_th_l[2]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_LOW_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_th_l_mask,
env->ifs_clm_th_l[3]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_HIGH_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_th_h_mask,
env->ifs_clm_th_h[0]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_HIGH_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_th_h_mask,
env->ifs_clm_th_h[1]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_HIGH_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_th_h_mask,
env->ifs_clm_th_h[2]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_HIGH_MSK,
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_th_h_mask,
env->ifs_clm_th_h[3]);
for (i = 0; i < RTW89_IFS_CLM_NUM; i++)
@@ -3338,7 +3396,9 @@ static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev)
static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
struct rtw89_ccx_para_info para = {0};
env->ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
@@ -3348,12 +3408,11 @@ static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev)
if (rtw89_phy_ifs_clm_th_update_check(rtwdev, &para))
rtw89_phy_ifs_clm_set_th_reg(rtwdev);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COLLECT_EN,
- true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_EN_MSK, true);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_collect_en_mask, true);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_en_mask, true);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_en_mask, true);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_en_mask, true);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_en_mask, true);
}
static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
@@ -3390,12 +3449,14 @@ static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 0);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 0);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 0);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 0);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 1);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1);
env->ccx_ongoing = true;
}
@@ -3467,63 +3528,79 @@ static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev)
static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u8 i = 0;
- if (rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_DONE_MSK) == 0) {
+ if (rtw89_phy_read32_mask(rtwdev, ccx->ifs_total_addr,
+ ccx->ifs_cnt_done_mask) == 0) {
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"Get IFS_CLM report Fail\n");
return false;
}
env->ifs_clm_tx =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
- B_IFS_CLM_TX_CNT_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_tx_cnt_addr,
+ ccx->ifs_clm_tx_cnt_msk);
env->ifs_clm_edcca_excl_cca =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
- B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_tx_cnt_addr,
+ ccx->ifs_clm_edcca_excl_cca_fa_mask);
env->ifs_clm_cckcca_excl_fa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
- B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_cca_addr,
+ ccx->ifs_clm_cckcca_excl_fa_mask);
env->ifs_clm_ofdmcca_excl_fa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
- B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_cca_addr,
+ ccx->ifs_clm_ofdmcca_excl_fa_mask);
env->ifs_clm_cckfa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
- B_IFS_CLM_CCK_FA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_fa_addr,
+ ccx->ifs_clm_cck_fa_mask);
env->ifs_clm_ofdmfa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
- B_IFS_CLM_OFDM_FA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_clm_fa_addr,
+ ccx->ifs_clm_ofdm_fa_mask);
env->ifs_clm_his[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T1_HIS_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t1_his_mask);
env->ifs_clm_his[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T2_HIS_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t2_his_mask);
env->ifs_clm_his[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T3_HIS_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t3_his_mask);
env->ifs_clm_his[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T4_HIS_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t4_his_mask);
env->ifs_clm_avg[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T1_AVG_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_avg_l_addr,
+ ccx->ifs_t1_avg_mask);
env->ifs_clm_avg[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T2_AVG_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_avg_l_addr,
+ ccx->ifs_t2_avg_mask);
env->ifs_clm_avg[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T3_AVG_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_avg_h_addr,
+ ccx->ifs_t3_avg_mask);
env->ifs_clm_avg[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T4_AVG_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_avg_h_addr,
+ ccx->ifs_t4_avg_mask);
env->ifs_clm_cca[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T1_CCA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_cca_l_addr,
+ ccx->ifs_t1_cca_mask);
env->ifs_clm_cca[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T2_CCA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_cca_l_addr,
+ ccx->ifs_t2_cca_mask);
env->ifs_clm_cca[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T3_CCA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_cca_h_addr,
+ ccx->ifs_t3_cca_mask);
env->ifs_clm_cca[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T4_CCA_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_cca_h_addr,
+ ccx->ifs_t4_cca_mask);
env->ifs_clm_total_ifs =
- rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_TOTAL_CNT_MSK);
+ rtw89_phy_read32_mask(rtwdev, ccx->ifs_total_addr,
+ ccx->ifs_total_mask);
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "IFS-CLM total_ifs = %d\n",
env->ifs_clm_total_ifs);
@@ -3551,7 +3628,9 @@ static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev)
static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
struct rtw89_ccx_para_info *para)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u32 period = 0;
u32 unit_idx = 0;
@@ -3567,10 +3646,11 @@ static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
if (para->mntr_time != env->ifs_clm_mntr_time) {
rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time,
&period, &unit_idx);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
- B_IFS_CLM_PERIOD_MSK, period);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
- B_IFS_CLM_COUNTER_UNIT_MSK, unit_idx);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_cnt_addr,
+ ccx->ifs_clm_period_mask, period);
+ rtw89_phy_set_phy_regs(rtwdev, ccx->ifs_cnt_addr,
+ ccx->ifs_clm_cnt_unit_mask,
+ unit_idx);
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"Update IFS-CLM time ((%d)) -> ((%d))\n",
@@ -3688,16 +3768,19 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev,
bool enable,
enum rtw89_phy_idx phy_idx)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ const struct rtw89_physts_regs *physts = phy->physts;
+
if (enable) {
- rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_FAIL);
- rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_BRK);
+ 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);
} else {
- rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_FAIL);
- rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_BRK);
+ 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);
}
}
@@ -4125,10 +4208,10 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
"igi=%d, cck_ccaTH=%d, backoff=%d, cck_PD_low=((%d))dB\n",
final_rssi, cck_cca_th, under_region, pd_val);
- rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_EN_V1,
- B_BMODE_PDTH_LIMIT_EN_MSK_V1, enable);
- rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_V1,
- B_BMODE_PDTH_LOWER_BOUND_MSK_V1, pd_val);
+ rtw89_phy_write32_mask(rtwdev, dig_regs->bmode_pd_reg,
+ dig_regs->bmode_cca_rssi_limit_en, enable);
+ rtw89_phy_write32_mask(rtwdev, dig_regs->bmode_pd_lower_bound_reg,
+ dig_regs->bmode_rssi_nocca_low_th_mask, pd_val);
}
void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev)
@@ -4517,7 +4600,7 @@ void rtw89_phy_tssi_ctrl_set_fast_mode_cfg(struct rtw89_dev *rtwdev,
regs = rtw89_tssi_fastmode_regs_level;
for (i = 0; i < RTW89_TSSI_FAST_MODE_NUM; i++) {
- reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, regs[i].addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, regs[i].mask, val);
}
}
@@ -4579,11 +4662,11 @@ void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
data = chip->tssi_dbw_table->data[bandedge_cfg];
for (i = 0; i < RTW89_TSSI_SBW_NUM; i++) {
- reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, regs[i].addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, regs[i].mask, data[i]);
}
- reg = rtw89_mac_reg_by_idx(R_AX_BANDEDGE_CFG, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BANDEDGE_CFG, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_BANDEDGE_CFG_IDX_MASK, bandedge_cfg);
rtw89_phy_tssi_ctrl_set_fast_mode_cfg(rtwdev, mac_idx, bandedge_cfg,
@@ -4681,3 +4764,74 @@ void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan)
rtw89_phy_write32(rtwdev, reg, hal->edcca_bak);
}
}
+
+static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
+ .setting_addr = R_CCX,
+ .edcca_opt_mask = B_CCX_EDCCA_OPT_MSK,
+ .measurement_trig_mask = B_MEASUREMENT_TRIG_MSK,
+ .trig_opt_mask = B_CCX_TRIG_OPT_MSK,
+ .en_mask = B_CCX_EN_MSK,
+ .ifs_cnt_addr = R_IFS_COUNTER,
+ .ifs_clm_period_mask = B_IFS_CLM_PERIOD_MSK,
+ .ifs_clm_cnt_unit_mask = B_IFS_CLM_COUNTER_UNIT_MSK,
+ .ifs_clm_cnt_clear_mask = B_IFS_COUNTER_CLR_MSK,
+ .ifs_collect_en_mask = B_IFS_COLLECT_EN,
+ .ifs_t1_addr = R_IFS_T1,
+ .ifs_t1_th_h_mask = B_IFS_T1_TH_HIGH_MSK,
+ .ifs_t1_en_mask = B_IFS_T1_EN_MSK,
+ .ifs_t1_th_l_mask = B_IFS_T1_TH_LOW_MSK,
+ .ifs_t2_addr = R_IFS_T2,
+ .ifs_t2_th_h_mask = B_IFS_T2_TH_HIGH_MSK,
+ .ifs_t2_en_mask = B_IFS_T2_EN_MSK,
+ .ifs_t2_th_l_mask = B_IFS_T2_TH_LOW_MSK,
+ .ifs_t3_addr = R_IFS_T3,
+ .ifs_t3_th_h_mask = B_IFS_T3_TH_HIGH_MSK,
+ .ifs_t3_en_mask = B_IFS_T3_EN_MSK,
+ .ifs_t3_th_l_mask = B_IFS_T3_TH_LOW_MSK,
+ .ifs_t4_addr = R_IFS_T4,
+ .ifs_t4_th_h_mask = B_IFS_T4_TH_HIGH_MSK,
+ .ifs_t4_en_mask = B_IFS_T4_EN_MSK,
+ .ifs_t4_th_l_mask = B_IFS_T4_TH_LOW_MSK,
+ .ifs_clm_tx_cnt_addr = R_IFS_CLM_TX_CNT,
+ .ifs_clm_edcca_excl_cca_fa_mask = B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK,
+ .ifs_clm_tx_cnt_msk = B_IFS_CLM_TX_CNT_MSK,
+ .ifs_clm_cca_addr = R_IFS_CLM_CCA,
+ .ifs_clm_ofdmcca_excl_fa_mask = B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_cckcca_excl_fa_mask = B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_fa_addr = R_IFS_CLM_FA,
+ .ifs_clm_ofdm_fa_mask = B_IFS_CLM_OFDM_FA_MSK,
+ .ifs_clm_cck_fa_mask = B_IFS_CLM_CCK_FA_MSK,
+ .ifs_his_addr = R_IFS_HIS,
+ .ifs_t4_his_mask = B_IFS_T4_HIS_MSK,
+ .ifs_t3_his_mask = B_IFS_T3_HIS_MSK,
+ .ifs_t2_his_mask = B_IFS_T2_HIS_MSK,
+ .ifs_t1_his_mask = B_IFS_T1_HIS_MSK,
+ .ifs_avg_l_addr = R_IFS_AVG_L,
+ .ifs_t2_avg_mask = B_IFS_T2_AVG_MSK,
+ .ifs_t1_avg_mask = B_IFS_T1_AVG_MSK,
+ .ifs_avg_h_addr = R_IFS_AVG_H,
+ .ifs_t4_avg_mask = B_IFS_T4_AVG_MSK,
+ .ifs_t3_avg_mask = B_IFS_T3_AVG_MSK,
+ .ifs_cca_l_addr = R_IFS_CCA_L,
+ .ifs_t2_cca_mask = B_IFS_T2_CCA_MSK,
+ .ifs_t1_cca_mask = B_IFS_T1_CCA_MSK,
+ .ifs_cca_h_addr = R_IFS_CCA_H,
+ .ifs_t4_cca_mask = B_IFS_T4_CCA_MSK,
+ .ifs_t3_cca_mask = B_IFS_T3_CCA_MSK,
+ .ifs_total_addr = R_IFSCNT,
+ .ifs_cnt_done_mask = B_IFSCNT_DONE_MSK,
+ .ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK,
+};
+
+static const struct rtw89_physts_regs rtw89_physts_regs_ax = {
+ .setting_addr = R_PLCP_HISTOGRAM,
+ .dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
+ .dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+};
+
+const struct rtw89_phy_gen_def rtw89_phy_gen_ax = {
+ .cr_base = 0x10000,
+ .ccx = &rtw89_ccx_regs_ax,
+ .physts = &rtw89_physts_regs_ax,
+};
+EXPORT_SYMBOL(rtw89_phy_gen_ax);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index ab174a0ba488..d6dc0cbbae43 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -7,7 +7,6 @@
#include "core.h"
-#define RTW89_PHY_ADDR_OFFSET 0x10000
#define RTW89_RF_ADDR_ADSEL_MASK BIT(16)
#define get_phy_headline(addr) FIELD_GET(GENMASK(31, 28), addr)
@@ -337,61 +336,154 @@ struct rtw89_nbi_reg_def {
struct rtw89_reg_def notch2_en;
};
+struct rtw89_ccx_regs {
+ u32 setting_addr;
+ u32 edcca_opt_mask;
+ u32 measurement_trig_mask;
+ u32 trig_opt_mask;
+ u32 en_mask;
+ u32 ifs_cnt_addr;
+ u32 ifs_clm_period_mask;
+ u32 ifs_clm_cnt_unit_mask;
+ u32 ifs_clm_cnt_clear_mask;
+ u32 ifs_collect_en_mask;
+ u32 ifs_t1_addr;
+ u32 ifs_t1_th_h_mask;
+ u32 ifs_t1_en_mask;
+ u32 ifs_t1_th_l_mask;
+ u32 ifs_t2_addr;
+ u32 ifs_t2_th_h_mask;
+ u32 ifs_t2_en_mask;
+ u32 ifs_t2_th_l_mask;
+ u32 ifs_t3_addr;
+ u32 ifs_t3_th_h_mask;
+ u32 ifs_t3_en_mask;
+ u32 ifs_t3_th_l_mask;
+ u32 ifs_t4_addr;
+ u32 ifs_t4_th_h_mask;
+ u32 ifs_t4_en_mask;
+ u32 ifs_t4_th_l_mask;
+ u32 ifs_clm_tx_cnt_addr;
+ u32 ifs_clm_edcca_excl_cca_fa_mask;
+ u32 ifs_clm_tx_cnt_msk;
+ u32 ifs_clm_cca_addr;
+ u32 ifs_clm_ofdmcca_excl_fa_mask;
+ u32 ifs_clm_cckcca_excl_fa_mask;
+ u32 ifs_clm_fa_addr;
+ u32 ifs_clm_ofdm_fa_mask;
+ u32 ifs_clm_cck_fa_mask;
+ u32 ifs_his_addr;
+ u32 ifs_t4_his_mask;
+ u32 ifs_t3_his_mask;
+ u32 ifs_t2_his_mask;
+ u32 ifs_t1_his_mask;
+ u32 ifs_avg_l_addr;
+ u32 ifs_t2_avg_mask;
+ u32 ifs_t1_avg_mask;
+ u32 ifs_avg_h_addr;
+ u32 ifs_t4_avg_mask;
+ u32 ifs_t3_avg_mask;
+ u32 ifs_cca_l_addr;
+ u32 ifs_t2_cca_mask;
+ u32 ifs_t1_cca_mask;
+ u32 ifs_cca_h_addr;
+ u32 ifs_t4_cca_mask;
+ u32 ifs_t3_cca_mask;
+ u32 ifs_total_addr;
+ u32 ifs_cnt_done_mask;
+ u32 ifs_total_mask;
+};
+
+struct rtw89_physts_regs {
+ u32 setting_addr;
+ u32 dis_trigger_fail_mask;
+ u32 dis_trigger_brk_mask;
+};
+
+struct rtw89_phy_gen_def {
+ u32 cr_base;
+ const struct rtw89_ccx_regs *ccx;
+ const struct rtw89_physts_regs *physts;
+};
+
+extern const struct rtw89_phy_gen_def rtw89_phy_gen_ax;
+extern const struct rtw89_phy_gen_def rtw89_phy_gen_be;
+
static inline void rtw89_phy_write8(struct rtw89_dev *rtwdev,
u32 addr, u8 data)
{
- rtw89_write8(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, data);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write8(rtwdev, addr + phy->cr_base, data);
}
static inline void rtw89_phy_write16(struct rtw89_dev *rtwdev,
u32 addr, u16 data)
{
- rtw89_write16(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, data);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write16(rtwdev, addr + phy->cr_base, data);
}
static inline void rtw89_phy_write32(struct rtw89_dev *rtwdev,
u32 addr, u32 data)
{
- rtw89_write32(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, data);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write32(rtwdev, addr + phy->cr_base, data);
}
static inline void rtw89_phy_write32_set(struct rtw89_dev *rtwdev,
u32 addr, u32 bits)
{
- rtw89_write32_set(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, bits);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write32_set(rtwdev, addr + phy->cr_base, bits);
}
static inline void rtw89_phy_write32_clr(struct rtw89_dev *rtwdev,
u32 addr, u32 bits)
{
- rtw89_write32_clr(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, bits);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write32_clr(rtwdev, addr + phy->cr_base, bits);
}
static inline void rtw89_phy_write32_mask(struct rtw89_dev *rtwdev,
u32 addr, u32 mask, u32 data)
{
- rtw89_write32_mask(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, mask, data);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ rtw89_write32_mask(rtwdev, addr + phy->cr_base, mask, data);
}
static inline u8 rtw89_phy_read8(struct rtw89_dev *rtwdev, u32 addr)
{
- return rtw89_read8(rtwdev, addr | RTW89_PHY_ADDR_OFFSET);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ return rtw89_read8(rtwdev, addr + phy->cr_base);
}
static inline u16 rtw89_phy_read16(struct rtw89_dev *rtwdev, u32 addr)
{
- return rtw89_read16(rtwdev, addr | RTW89_PHY_ADDR_OFFSET);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ return rtw89_read16(rtwdev, addr + phy->cr_base);
}
static inline u32 rtw89_phy_read32(struct rtw89_dev *rtwdev, u32 addr)
{
- return rtw89_read32(rtwdev, addr | RTW89_PHY_ADDR_OFFSET);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ return rtw89_read32(rtwdev, addr + phy->cr_base);
}
static inline u32 rtw89_phy_read32_mask(struct rtw89_dev *rtwdev,
u32 addr, u32 mask)
{
- return rtw89_read32_mask(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, mask);
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ return rtw89_read32_mask(rtwdev, addr + phy->cr_base, mask);
}
static inline
diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
new file mode 100644
index 000000000000..778e4b0c8e87
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include "phy.h"
+#include "reg.h"
+
+static const struct rtw89_ccx_regs rtw89_ccx_regs_be = {
+ .setting_addr = R_CCX,
+ .edcca_opt_mask = B_CCX_EDCCA_OPT_MSK_V1,
+ .measurement_trig_mask = B_MEASUREMENT_TRIG_MSK,
+ .trig_opt_mask = B_CCX_TRIG_OPT_MSK,
+ .en_mask = B_CCX_EN_MSK,
+ .ifs_cnt_addr = R_IFS_COUNTER,
+ .ifs_clm_period_mask = B_IFS_CLM_PERIOD_MSK,
+ .ifs_clm_cnt_unit_mask = B_IFS_CLM_COUNTER_UNIT_MSK,
+ .ifs_clm_cnt_clear_mask = B_IFS_COUNTER_CLR_MSK,
+ .ifs_collect_en_mask = B_IFS_COLLECT_EN,
+ .ifs_t1_addr = R_IFS_T1,
+ .ifs_t1_th_h_mask = B_IFS_T1_TH_HIGH_MSK,
+ .ifs_t1_en_mask = B_IFS_T1_EN_MSK,
+ .ifs_t1_th_l_mask = B_IFS_T1_TH_LOW_MSK,
+ .ifs_t2_addr = R_IFS_T2,
+ .ifs_t2_th_h_mask = B_IFS_T2_TH_HIGH_MSK,
+ .ifs_t2_en_mask = B_IFS_T2_EN_MSK,
+ .ifs_t2_th_l_mask = B_IFS_T2_TH_LOW_MSK,
+ .ifs_t3_addr = R_IFS_T3,
+ .ifs_t3_th_h_mask = B_IFS_T3_TH_HIGH_MSK,
+ .ifs_t3_en_mask = B_IFS_T3_EN_MSK,
+ .ifs_t3_th_l_mask = B_IFS_T3_TH_LOW_MSK,
+ .ifs_t4_addr = R_IFS_T4,
+ .ifs_t4_th_h_mask = B_IFS_T4_TH_HIGH_MSK,
+ .ifs_t4_en_mask = B_IFS_T4_EN_MSK,
+ .ifs_t4_th_l_mask = B_IFS_T4_TH_LOW_MSK,
+ .ifs_clm_tx_cnt_addr = R_IFS_CLM_TX_CNT_V1,
+ .ifs_clm_edcca_excl_cca_fa_mask = B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK,
+ .ifs_clm_tx_cnt_msk = B_IFS_CLM_TX_CNT_MSK,
+ .ifs_clm_cca_addr = R_IFS_CLM_CCA_V1,
+ .ifs_clm_ofdmcca_excl_fa_mask = B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_cckcca_excl_fa_mask = B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_fa_addr = R_IFS_CLM_FA_V1,
+ .ifs_clm_ofdm_fa_mask = B_IFS_CLM_OFDM_FA_MSK,
+ .ifs_clm_cck_fa_mask = B_IFS_CLM_CCK_FA_MSK,
+ .ifs_his_addr = R_IFS_HIS_V1,
+ .ifs_t4_his_mask = B_IFS_T4_HIS_MSK,
+ .ifs_t3_his_mask = B_IFS_T3_HIS_MSK,
+ .ifs_t2_his_mask = B_IFS_T2_HIS_MSK,
+ .ifs_t1_his_mask = B_IFS_T1_HIS_MSK,
+ .ifs_avg_l_addr = R_IFS_AVG_L_V1,
+ .ifs_t2_avg_mask = B_IFS_T2_AVG_MSK,
+ .ifs_t1_avg_mask = B_IFS_T1_AVG_MSK,
+ .ifs_avg_h_addr = R_IFS_AVG_H_V1,
+ .ifs_t4_avg_mask = B_IFS_T4_AVG_MSK,
+ .ifs_t3_avg_mask = B_IFS_T3_AVG_MSK,
+ .ifs_cca_l_addr = R_IFS_CCA_L_V1,
+ .ifs_t2_cca_mask = B_IFS_T2_CCA_MSK,
+ .ifs_t1_cca_mask = B_IFS_T1_CCA_MSK,
+ .ifs_cca_h_addr = R_IFS_CCA_H_V1,
+ .ifs_t4_cca_mask = B_IFS_T4_CCA_MSK,
+ .ifs_t3_cca_mask = B_IFS_T3_CCA_MSK,
+ .ifs_total_addr = R_IFSCNT_V1,
+ .ifs_cnt_done_mask = B_IFSCNT_DONE_MSK,
+ .ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK,
+};
+
+static const struct rtw89_physts_regs rtw89_physts_regs_be = {
+ .setting_addr = R_PLCP_HISTOGRAM,
+ .dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
+ .dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+};
+
+const struct rtw89_phy_gen_def rtw89_phy_gen_be = {
+ .cr_base = 0x20000,
+ .ccx = &rtw89_ccx_regs_be,
+ .physts = &rtw89_physts_regs_be,
+};
+EXPORT_SYMBOL(rtw89_phy_gen_be);
diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c
index 84201ef19c17..917c01e5e9ed 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.c
+++ b/drivers/net/wireless/realtek/rtw89/ps.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include "chan.h"
#include "coex.h"
#include "core.h"
#include "debug.h"
@@ -257,8 +258,13 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
{
struct ieee80211_vif *vif, *found_vif = NULL;
struct rtw89_vif *rtwvif;
+ enum rtw89_entity_mode mode;
int count = 0;
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ goto disable_lps;
+
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
@@ -273,8 +279,71 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
if (count == 1 && found_vif->cfg.ps) {
rtwdev->lps_enabled = true;
- } else {
- rtw89_leave_lps(rtwdev);
- rtwdev->lps_enabled = false;
+ return;
}
+
+disable_lps:
+ rtw89_leave_lps(rtwdev);
+ rtwdev->lps_enabled = false;
+}
+
+void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)
+{
+ struct rtw89_p2p_noa_setter *setter = &rtwvif->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;
+
+ if (setter->noa_count) {
+ setter->noa_index++;
+ setter->noa_count = 0;
+ }
+
+ memset(ie, 0, sizeof(*ie));
+
+ p2p_head->eid = WLAN_EID_VENDOR_SPECIFIC;
+ p2p_head->ie_len = 4 + sizeof(*noa_head);
+ p2p_head->oui[0] = (WLAN_OUI_WFA >> 16) & 0xff;
+ p2p_head->oui[1] = (WLAN_OUI_WFA >> 8) & 0xff;
+ p2p_head->oui[2] = (WLAN_OUI_WFA >> 0) & 0xff;
+ p2p_head->oui_type = WLAN_OUI_TYPE_WFA_P2P;
+
+ noa_head->attr_type = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
+ noa_head->attr_len = cpu_to_le16(2);
+ noa_head->index = setter->noa_index;
+ noa_head->oppps_ctwindow = 0;
+}
+
+void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+ const struct ieee80211_p2p_noa_desc *desc)
+{
+ struct rtw89_p2p_noa_setter *setter = &rtwvif->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;
+
+ if (!desc->count || !desc->duration)
+ return;
+
+ if (setter->noa_count >= RTW89_P2P_MAX_NOA_NUM)
+ return;
+
+ p2p_head->ie_len += sizeof(*desc);
+ le16_add_cpu(&noa_head->attr_len, sizeof(*desc));
+
+ ie->noa_desc[setter->noa_count++] = *desc;
+}
+
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data)
+{
+ struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+ struct rtw89_p2p_noa_ie *ie = &setter->ie;
+ void *tail;
+
+ if (!setter->noa_count)
+ return 0;
+
+ *data = ie;
+ tail = ie->noa_desc + setter->noa_count;
+ return tail - *data;
}
diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h
index 4c18f49204b2..aff0fba71cb0 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.h
+++ b/drivers/net/wireless/realtek/rtw89/ps.h
@@ -16,6 +16,10 @@ 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_recalc_lps(struct rtw89_dev *rtwdev);
+void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif);
+void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+ const struct ieee80211_p2p_noa_desc *desc);
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, 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 55595fde7494..c0aac4d3678a 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -3625,6 +3625,27 @@
#define B_AX_GNT_BT_TX_SW_VAL BIT(1)
#define B_AX_GNT_BT_TX_SW_CTRL BIT(0)
+#define R_BE_FILTER_MODEL_ADDR 0x0C04
+
+#define R_BE_RX_FLTR_OPT 0x11420
+#define R_BE_RX_FLTR_OPT_C1 0x15420
+#define B_BE_UID_FILTER_MASK GENMASK(31, 24)
+#define B_BE_UNSPT_TYPE BIT(22)
+#define B_BE_RX_MPDU_MAX_LEN_MASK GENMASK(21, 16)
+#define B_BE_A_FTM_REQ BIT(14)
+#define B_BE_A_ERR_PKT BIT(13)
+#define B_BE_A_UNSUP_PKT BIT(12)
+#define B_BE_A_CRC32_ERR BIT(11)
+#define B_BE_A_BCN_CHK_RULE_MASK GENMASK(9, 8)
+#define B_BE_A_BCN_CHK_EN BIT(7)
+#define B_BE_A_MC_LIST_CAM_MATCH BIT(6)
+#define B_BE_A_BC_CAM_MATCH BIT(5)
+#define B_BE_A_UC_CAM_MATCH BIT(4)
+#define B_BE_A_MC BIT(3)
+#define B_BE_A_BC BIT(2)
+#define B_BE_A_A1_MATCH BIT(1)
+#define B_BE_SNIFFER_MODE BIT(0)
+
#define RR_MOD 0x00
#define RR_MOD_V1 0x10000
#define RR_MOD_IQK GENMASK(19, 4)
@@ -3977,6 +3998,7 @@
#define B_DBCC_80P80_SEL_EVM_RPT_EN BIT(0)
#define R_CCX 0x0C00
#define B_CCX_EDCCA_OPT_MSK GENMASK(6, 4)
+#define B_CCX_EDCCA_OPT_MSK_V1 GENMASK(7, 4)
#define B_MEASUREMENT_TRIG_MSK BIT(2)
#define B_CCX_TRIG_OPT_MSK BIT(1)
#define B_CCX_EN_MSK BIT(0)
@@ -4068,32 +4090,41 @@
#define B_SWSI_R_DATA_DONE_V1 BIT(26)
#define R_TX_COUNTER 0x1A40
#define R_IFS_CLM_TX_CNT 0x1ACC
+#define R_IFS_CLM_TX_CNT_V1 0x0ECC
#define B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK GENMASK(31, 16)
#define B_IFS_CLM_TX_CNT_MSK GENMASK(15, 0)
#define R_IFS_CLM_CCA 0x1AD0
+#define R_IFS_CLM_CCA_V1 0x0ED0
#define B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK GENMASK(31, 16)
#define B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK GENMASK(15, 0)
#define R_IFS_CLM_FA 0x1AD4
+#define R_IFS_CLM_FA_V1 0x0ED4
#define B_IFS_CLM_OFDM_FA_MSK GENMASK(31, 16)
#define B_IFS_CLM_CCK_FA_MSK GENMASK(15, 0)
#define R_IFS_HIS 0x1AD8
+#define R_IFS_HIS_V1 0x0ED8
#define B_IFS_T4_HIS_MSK GENMASK(31, 24)
#define B_IFS_T3_HIS_MSK GENMASK(23, 16)
#define B_IFS_T2_HIS_MSK GENMASK(15, 8)
#define B_IFS_T1_HIS_MSK GENMASK(7, 0)
#define R_IFS_AVG_L 0x1ADC
+#define R_IFS_AVG_L_V1 0x0EDC
#define B_IFS_T2_AVG_MSK GENMASK(31, 16)
#define B_IFS_T1_AVG_MSK GENMASK(15, 0)
#define R_IFS_AVG_H 0x1AE0
+#define R_IFS_AVG_H_V1 0x0EE0
#define B_IFS_T4_AVG_MSK GENMASK(31, 16)
#define B_IFS_T3_AVG_MSK GENMASK(15, 0)
#define R_IFS_CCA_L 0x1AE4
+#define R_IFS_CCA_L_V1 0x0EE4
#define B_IFS_T2_CCA_MSK GENMASK(31, 16)
#define B_IFS_T1_CCA_MSK GENMASK(15, 0)
#define R_IFS_CCA_H 0x1AE8
+#define R_IFS_CCA_H_V1 0x0EE8
#define B_IFS_T4_CCA_MSK GENMASK(31, 16)
#define B_IFS_T3_CCA_MSK GENMASK(15, 0)
#define R_IFSCNT 0x1AEC
+#define R_IFSCNT_V1 0x0EEC
#define B_IFSCNT_DONE_MSK BIT(16)
#define B_IFSCNT_TOTAL_CNT_MSK GENMASK(15, 0)
#define R_TXAGC_TP 0x1C04
@@ -4109,6 +4140,8 @@
#define B_TXAGC_BB_OFT GENMASK(31, 16)
#define B_TXAGC_BB GENMASK(31, 24)
#define B_TXAGC_RF GENMASK(5, 0)
+#define R_PATH0_TXPWR 0x1C78
+#define B_PATH0_TXPWR GENMASK(8, 0)
#define R_S0_ADDCK 0x1E00
#define B_S0_ADDCK_I GENMASK(9, 0)
#define B_S0_ADDCK_Q GENMASK(19, 10)
@@ -4184,6 +4217,8 @@
#define R_TXAGC_BB_S1 0x3C60
#define B_TXAGC_BB_S1_OFT GENMASK(31, 16)
#define B_TXAGC_BB_S1 GENMASK(31, 24)
+#define R_PATH1_TXPWR 0x3C78
+#define B_PATH1_TXPWR GENMASK(8, 0)
#define R_S1_ADDCK 0x3E00
#define B_S1_ADDCK_I GENMASK(9, 0)
#define B_S1_ADDCK_Q GENMASK(19, 10)
@@ -4360,6 +4395,7 @@
#define B_PKT_POP_EN BIT(8)
#define R_SEG0R_PD 0x481C
#define R_SEG0R_PD_V1 0x4860
+#define R_SEG0R_PD_V2 0x6A74
#define R_SEG0R_EDCCA_LVL 0x4840
#define R_SEG0R_EDCCA_LVL_V1 0x4884
#define B_SEG0R_PPDU_LVL_MSK GENMASK(31, 24)
@@ -4478,8 +4514,10 @@
#define R_DCFO_COMP_S0_V1 0x4A40
#define B_DCFO_COMP_S0_V1_MSK GENMASK(13, 0)
#define R_BMODE_PDTH_V1 0x4B64
+#define R_BMODE_PDTH_V2 0x6708
#define B_BMODE_PDTH_LOWER_BOUND_MSK_V1 GENMASK(31, 24)
#define R_BMODE_PDTH_EN_V1 0x4B74
+#define R_BMODE_PDTH_EN_V2 0x6718
#define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30)
#define R_CFO_COMP_SEG1_L 0x5384
#define R_CFO_COMP_SEG1_H 0x5388
diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
index 34c4d40cfa02..9e2328db1865 100644
--- a/drivers/net/wireless/realtek/rtw89/regd.c
+++ b/drivers/net/wireless/realtek/rtw89/regd.c
@@ -13,10 +13,10 @@
}
static const struct rtw89_regd rtw89_ww_regd =
- COUNTRY_REGD("00", RTW89_WW, RTW89_WW);
+ COUNTRY_REGD("00", RTW89_WW, RTW89_WW, RTW89_WW);
static const struct rtw89_regd rtw89_regd_map[] = {
- COUNTRY_REGD("AR", RTW89_MEXICO, RTW89_MEXICO, RTW89_NA),
+ COUNTRY_REGD("AR", RTW89_MEXICO, RTW89_MEXICO, RTW89_FCC),
COUNTRY_REGD("BO", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("BR", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("CL", RTW89_CHILE, RTW89_CHILE, RTW89_CHILE),
@@ -26,7 +26,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("SV", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("GT", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("HN", RTW89_FCC, RTW89_FCC, RTW89_FCC),
- COUNTRY_REGD("MX", RTW89_MEXICO, RTW89_MEXICO, RTW89_NA),
+ COUNTRY_REGD("MX", RTW89_MEXICO, RTW89_MEXICO, RTW89_FCC),
COUNTRY_REGD("NI", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("PA", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("PY", RTW89_FCC, RTW89_FCC, RTW89_NA),
@@ -81,7 +81,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("KE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("KW", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("KG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
- COUNTRY_REGD("LB", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("LB", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("LS", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("MK", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("MA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
@@ -96,7 +96,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("SN", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("RS", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("ME", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("ZA", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("ZA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("TR", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("UA", RTW89_UKRAINE, RTW89_UKRAINE, RTW89_UKRAINE),
COUNTRY_REGD("AE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
@@ -115,7 +115,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA),
- COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("TH", RTW89_WW, RTW89_WW, RTW89_WW),
COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA),
COUNTRY_REGD("NZ", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA),
@@ -148,7 +148,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("IO", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("VG", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("BN", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("BF", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("BF", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("MM", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("BI", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("CM", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
@@ -164,7 +164,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("CK", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("CI", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("DJ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
- COUNTRY_REGD("DM", RTW89_FCC, RTW89_FCC, RTW89_FCC),
+ COUNTRY_REGD("DM", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("GQ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("ER", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("ET", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
@@ -179,20 +179,21 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC),
+ COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("GW", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("GY", RTW89_FCC, RTW89_FCC, RTW89_FCC),
- COUNTRY_REGD("HT", RTW89_FCC, RTW89_FCC, RTW89_NA),
+ COUNTRY_REGD("GY", RTW89_FCC, RTW89_FCC, RTW89_NA),
+ COUNTRY_REGD("HT", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("HM", RTW89_ACMA, RTW89_ACMA, RTW89_NA),
COUNTRY_REGD("VA", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("IM", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("JE", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("KI", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("LA", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("XK", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
+ COUNTRY_REGD("LA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("LR", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("LY", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("MO", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
@@ -207,7 +208,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("YT", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("FM", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("MD", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
- COUNTRY_REGD("MN", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("MN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("MS", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("NR", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("NP", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index c3ffcb645ebf..103893f28b51 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -185,6 +185,10 @@ static const struct rtw89_dig_regs rtw8851b_dig_regs = {
.seg0_pd_reg = R_SEG0R_PD_V1,
.pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
.pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1,
+ .bmode_pd_reg = R_BMODE_PDTH_EN_V1,
+ .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1,
+ .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V1,
+ .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1,
.p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK},
.p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK},
.p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1},
@@ -756,9 +760,9 @@ static void rtw8851b_set_channel_mac(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
u8 mac_idx)
{
- u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
- u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx);
- u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx);
+ u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
+ u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx);
+ u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx);
u8 txsc20 = 0, txsc40 = 0;
switch (chan->band_width) {
@@ -1740,14 +1744,14 @@ void rtw8851b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
return;
}
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_CTRL, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN);
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst);
pw_ofst = max_t(s8, pw_ofst - 3, -16);
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst);
}
@@ -2334,10 +2338,14 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8851b = {
const struct rtw89_chip_info rtw8851b_chip_info = {
.chip_id = RTL8851B,
+ .chip_gen = RTW89_CHIP_AX,
.ops = &rtw8851b_chip_ops,
+ .mac_def = &rtw89_mac_gen_ax,
+ .phy_def = &rtw89_phy_gen_ax,
.fw_basename = RTW8851B_FW_BASENAME,
.fw_format_max = RTW8851B_FW_FORMAT_MAX,
.try_ce_fw = true,
+ .needed_fw_elms = 0,
.fifo_size = 196608,
.small_fifo_size = true,
.dle_scc_rsvd_size = 98304,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 6257414a3b4b..d068eae6a2f0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -478,6 +478,10 @@ static const struct rtw89_dig_regs rtw8852a_dig_regs = {
.seg0_pd_reg = R_SEG0R_PD,
.pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
.pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK,
+ .bmode_pd_reg = R_BMODE_PDTH_EN_V1,
+ .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1,
+ .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V1,
+ .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1,
.p0_lna_init = {R_PATH0_LNA_INIT, B_PATH0_LNA_INIT_IDX_MSK},
.p1_lna_init = {R_PATH1_LNA_INIT, B_PATH1_LNA_INIT_IDX_MSK},
.p0_tia_init = {R_PATH0_TIA_INIT, B_PATH0_TIA_INIT_IDX_MSK},
@@ -704,10 +708,9 @@ static void rtw8852a_set_channel_mac(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
u8 mac_idx)
{
- u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx);
- u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE,
- mac_idx);
- u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx);
+ u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx);
+ u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
+ u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx);
u8 txsc20 = 0, txsc40 = 0;
switch (chan->band_width) {
@@ -1380,13 +1383,13 @@ void rtw8852a_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
pw_ofst);
return;
}
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_CTRL, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN);
val_1t = pw_ofst;
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, val_1t);
val_2t = max(val_1t - 3, -16);
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, val_2t);
rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[ULTB] Set TB pwr_offset=(%d, %d)\n",
val_1t, val_2t);
@@ -2071,10 +2074,14 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = {
const struct rtw89_chip_info rtw8852a_chip_info = {
.chip_id = RTL8852A,
+ .chip_gen = RTW89_CHIP_AX,
.ops = &rtw8852a_chip_ops,
+ .mac_def = &rtw89_mac_gen_ax,
+ .phy_def = &rtw89_phy_gen_ax,
.fw_basename = RTW8852A_FW_BASENAME,
.fw_format_max = RTW8852A_FW_FORMAT_MAX,
.try_ce_fw = false,
+ .needed_fw_elms = 0,
.fifo_size = 458752,
.small_fifo_size = false,
.dle_scc_rsvd_size = 0,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 718f993da62a..0063301952b3 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -310,6 +310,10 @@ static const struct rtw89_dig_regs rtw8852b_dig_regs = {
.seg0_pd_reg = R_SEG0R_PD_V1,
.pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
.pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1,
+ .bmode_pd_reg = R_BMODE_PDTH_EN_V1,
+ .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1,
+ .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V1,
+ .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1,
.p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK},
.p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK},
.p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1},
@@ -843,9 +847,9 @@ static void rtw8852b_set_channel_mac(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
u8 mac_idx)
{
- u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx);
- u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
- u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx);
+ u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx);
+ u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
+ u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx);
u8 txsc20 = 0, txsc40 = 0;
switch (chan->band_width) {
@@ -1725,14 +1729,14 @@ void rtw8852b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
return;
}
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_CTRL, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN);
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst);
pw_ofst = max_t(s8, pw_ofst - 3, -16);
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst);
}
@@ -2503,10 +2507,14 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8852b = {
const struct rtw89_chip_info rtw8852b_chip_info = {
.chip_id = RTL8852B,
+ .chip_gen = RTW89_CHIP_AX,
.ops = &rtw8852b_chip_ops,
+ .mac_def = &rtw89_mac_gen_ax,
+ .phy_def = &rtw89_phy_gen_ax,
.fw_basename = RTW8852B_FW_BASENAME,
.fw_format_max = RTW8852B_FW_FORMAT_MAX,
.try_ce_fw = true,
+ .needed_fw_elms = 0,
.fifo_size = 196608,
.small_fifo_size = true,
.dle_scc_rsvd_size = 98304,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
index fa018e1f499b..259df67836a0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
@@ -846,7 +846,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
case ID_NBTXK:
rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0);
rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x011);
- iqk_cmd = 0x308 | (1 << (4 + path));
+ iqk_cmd = 0x408 | (1 << (4 + path));
break;
case ID_NBRXK:
rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1);
@@ -1078,7 +1078,7 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8
{
struct rtw89_iqk_info *iqk_info = &rtwdev->iqk;
bool kfail;
- u8 gp = 0x3;
+ u8 gp = 0x2;
switch (iqk_info->iqk_band[path]) {
case RTW89_BAND_2G:
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 9c7c9812d4f4..1e16cc0a05dc 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -146,6 +146,10 @@ static const struct rtw89_dig_regs rtw8852c_dig_regs = {
.seg0_pd_reg = R_SEG0R_PD,
.pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
.pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK,
+ .bmode_pd_reg = R_BMODE_PDTH_EN_V1,
+ .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1,
+ .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V1,
+ .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1,
.p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK},
.p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK},
.p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1},
@@ -606,10 +610,9 @@ static void rtw8852c_set_channel_mac(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
u8 mac_idx)
{
- u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx);
- u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE,
- mac_idx);
- u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx);
+ u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_AX_WMAC_RFMOD, mac_idx);
+ u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_AX_TX_SUB_CARRIER_VALUE, mac_idx);
+ u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_AX_TXRATE_CHK, mac_idx);
u8 txsc20 = 0, txsc40 = 0, txsc80 = 0;
u8 rf_mod_val = 0, chk_rate_mask = 0;
u32 txsc;
@@ -1654,8 +1657,7 @@ static void rtw8852c_set_channel_bb(struct rtw89_dev *rtwdev,
rtwdev->hal.cv != CHIP_CAV) {
rtw89_phy_write32_idx(rtwdev, R_P80_AT_HIGH_FREQ,
B_P80_AT_HIGH_FREQ, 0x0, phy_idx);
- reg = rtw89_mac_reg_by_idx(R_P80_AT_HIGH_FREQ_BB_WRP,
- phy_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_P80_AT_HIGH_FREQ_BB_WRP, phy_idx);
if (chan->primary_channel > chan->channel) {
rtw89_phy_write32_mask(rtwdev,
R_P80_AT_HIGH_FREQ_RU_ALLOC,
@@ -1859,12 +1861,12 @@ void rtw8852c_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
for (i = 0; i < 4; i++) {
/* 1TX */
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, mac_idx);
rtw89_write32_mask(rtwdev, reg,
B_AX_PWR_UL_TB_1T_V1_MASK << (8 * i),
val_1t);
/* 2TX */
- reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, mac_idx);
rtw89_write32_mask(rtwdev, reg,
B_AX_PWR_UL_TB_2T_V1_MASK << (8 * i),
val_2t);
@@ -2181,7 +2183,7 @@ static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path,
for (addr = R_AX_MACID_ANT_TABLE;
addr <= R_AX_MACID_ANT_TABLE_LAST; addr += 4) {
- reg = rtw89_mac_reg_by_idx(addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, addr, mac_idx);
rtw89_write32(rtwdev, reg, 0);
}
@@ -2211,7 +2213,7 @@ static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path,
for (i = 0; i < cr_size; i++) {
rtw89_debug(rtwdev, RTW89_DBG_TSSI, "0x%x = 0x%x\n",
path_com[i].addr, path_com[i].data);
- reg = rtw89_mac_reg_by_idx(path_com[i].addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, path_com[i].addr, mac_idx);
rtw89_write32(rtwdev, reg, path_com[i].data);
}
}
@@ -2802,10 +2804,14 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
const struct rtw89_chip_info rtw8852c_chip_info = {
.chip_id = RTL8852C,
+ .chip_gen = RTW89_CHIP_AX,
.ops = &rtw8852c_chip_ops,
+ .mac_def = &rtw89_mac_gen_ax,
+ .phy_def = &rtw89_phy_gen_ax,
.fw_basename = RTW8852C_FW_BASENAME,
.fw_format_max = RTW8852C_FW_FORMAT_MAX,
.try_ce_fw = false,
+ .needed_fw_elms = 0,
.fifo_size = 458752,
.small_fifo_size = false,
.dle_scc_rsvd_size = 0,
diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c
index dfccae81c380..aed05b026c6c 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.c
+++ b/drivers/net/wireless/realtek/rtw89/sar.c
@@ -2,9 +2,16 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include "acpi.h"
#include "debug.h"
+#include "phy.h"
+#include "reg.h"
#include "sar.h"
+#define RTW89_TAS_FACTOR 2 /* unit: 0.25 dBm */
+#define RTW89_TAS_DPR_GAP (1 << RTW89_TAS_FACTOR)
+#define RTW89_TAS_DELTA (2 << RTW89_TAS_FACTOR)
+
static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
u32 center_freq)
{
@@ -78,17 +85,15 @@ static const struct rtw89_sar_span rtw89_sar_overlapping_6ghz[] = {
RTW89_DECL_SAR_6GHZ_SPAN(6885, SUBBAND_7_H, SUBBAND_8),
};
-static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
+static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev,
+ u32 center_freq, s32 *cfg)
{
struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- enum rtw89_band band = chan->band_type;
- u32 center_freq = chan->freq;
const struct rtw89_sar_span *span = NULL;
enum rtw89_sar_subband subband_l, subband_h;
int idx;
- if (band == RTW89_BAND_6G) {
+ if (center_freq >= RTW89_SAR_6GHZ_SPAN_HEAD) {
idx = RTW89_SAR_6GHZ_SPAN_IDX(center_freq);
/* To decrease size of rtw89_sar_overlapping_6ghz[],
* RTW89_SAR_6GHZ_SPAN_IDX() truncates the leading NULLs
@@ -108,8 +113,8 @@ static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
}
rtw89_debug(rtwdev, RTW89_DBG_SAR,
- "for {band %u, center_freq %u}, SAR subband: {%u, %u}\n",
- band, center_freq, subband_l, subband_h);
+ "center_freq %u: SAR subband {%u, %u}\n",
+ center_freq, subband_l, subband_h);
if (!rtwsar->set[subband_l] && !rtwsar->set[subband_h])
return -ENODATA;
@@ -157,11 +162,35 @@ static s8 rtw89_txpwr_sar_to_mac(struct rtw89_dev *rtwdev, u8 fct, s32 cfg)
RTW89_SAR_TXPWR_MAC_MAX);
}
-s8 rtw89_query_sar(struct rtw89_dev *rtwdev)
+static s8 rtw89_txpwr_tas_to_sar(const struct rtw89_sar_handler *sar_hdl,
+ s8 cfg)
+{
+ const u8 fct = sar_hdl->txpwr_factor_sar;
+
+ if (fct > RTW89_TAS_FACTOR)
+ return cfg << (fct - RTW89_TAS_FACTOR);
+ else
+ return cfg >> (RTW89_TAS_FACTOR - fct);
+}
+
+static s8 rtw89_txpwr_sar_to_tas(const struct rtw89_sar_handler *sar_hdl,
+ s8 cfg)
+{
+ const u8 fct = sar_hdl->txpwr_factor_sar;
+
+ if (fct > RTW89_TAS_FACTOR)
+ return cfg >> (fct - RTW89_TAS_FACTOR);
+ else
+ return cfg << (RTW89_TAS_FACTOR - fct);
+}
+
+s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s8 delta;
int ret;
s32 cfg;
u8 fct;
@@ -171,16 +200,30 @@ s8 rtw89_query_sar(struct rtw89_dev *rtwdev)
if (src == RTW89_SAR_SOURCE_NONE)
return RTW89_SAR_TXPWR_MAC_MAX;
- ret = sar_hdl->query_sar_config(rtwdev, &cfg);
+ ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
if (ret)
return RTW89_SAR_TXPWR_MAC_MAX;
+ if (tas->enable) {
+ switch (tas->state) {
+ case RTW89_TAS_STATE_DPR_OFF:
+ return RTW89_SAR_TXPWR_MAC_MAX;
+ case RTW89_TAS_STATE_DPR_ON:
+ delta = rtw89_txpwr_tas_to_sar(sar_hdl, tas->delta);
+ cfg -= delta;
+ break;
+ case RTW89_TAS_STATE_DPR_FORBID:
+ default:
+ break;
+ }
+ }
+
fct = sar_hdl->txpwr_factor_sar;
return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg);
}
-void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
+void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev, u32 center_freq)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
@@ -199,7 +242,7 @@ void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
seq_printf(m, "source: %d (%s)\n", src, sar_hdl->descr_sar_source);
- ret = sar_hdl->query_sar_config(rtwdev, &cfg);
+ ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
if (ret) {
seq_printf(m, "config: return code: %d\n", ret);
seq_printf(m, "assign: max setting: %d (unit: 1/%lu dBm)\n",
@@ -212,6 +255,19 @@ void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev)
seq_printf(m, "config: %d (unit: 1/%lu dBm)\n", cfg, BIT(fct));
}
+void rtw89_print_tas(struct seq_file *m, struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+
+ if (!tas->enable) {
+ seq_puts(m, "no TAS is applied\n");
+ return;
+ }
+
+ seq_printf(m, "DPR gap: %d\n", tas->dpr_gap);
+ seq_printf(m, "TAS delta: %d\n", tas->delta);
+}
+
static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev,
const struct rtw89_sar_cfg_common *sar)
{
@@ -292,3 +348,145 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
return rtw89_apply_sar_common(rtwdev, &sar_common);
}
+
+static void rtw89_tas_state_update(struct rtw89_dev *rtwdev)
+{
+ const enum rtw89_sar_sources src = rtwdev->sar.src;
+ /* its members are protected by rtw89_sar_set_src() */
+ const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s32 txpwr_avg = tas->total_txpwr / RTW89_TAS_MAX_WINDOW / PERCENT;
+ s32 dpr_on_threshold, dpr_off_threshold, cfg;
+ enum rtw89_tas_state state = tas->state;
+ const struct rtw89_chan *chan;
+ int ret;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (src == RTW89_SAR_SOURCE_NONE)
+ return;
+
+ chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ ret = sar_hdl->query_sar_config(rtwdev, chan->freq, &cfg);
+ if (ret)
+ return;
+
+ cfg = rtw89_txpwr_sar_to_tas(sar_hdl, cfg);
+
+ if (tas->delta >= cfg) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "TAS delta exceed SAR limit\n");
+ state = RTW89_TAS_STATE_DPR_FORBID;
+ goto out;
+ }
+
+ dpr_on_threshold = cfg;
+ dpr_off_threshold = cfg - tas->dpr_gap;
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "DPR_ON thold: %d, DPR_OFF thold: %d, txpwr_avg: %d\n",
+ dpr_on_threshold, dpr_off_threshold, txpwr_avg);
+
+ if (txpwr_avg >= dpr_on_threshold)
+ state = RTW89_TAS_STATE_DPR_ON;
+ else if (txpwr_avg < dpr_off_threshold)
+ state = RTW89_TAS_STATE_DPR_OFF;
+
+out:
+ if (tas->state == state)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "TAS old state: %d, new state: %d\n", tas->state, state);
+ tas->state = state;
+ rtw89_core_set_chip_txpwr(rtwdev);
+}
+
+void rtw89_tas_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ int ret;
+ u8 val;
+
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "acpi: cannot get TAS: %d\n", ret);
+ return;
+ }
+
+ switch (val) {
+ case 0:
+ tas->enable = false;
+ break;
+ case 1:
+ tas->enable = true;
+ break;
+ default:
+ break;
+ }
+
+ if (!tas->enable) {
+ rtw89_debug(rtwdev, RTW89_DBG_SAR, "TAS not enable\n");
+ return;
+ }
+
+ tas->dpr_gap = RTW89_TAS_DPR_GAP;
+ tas->delta = RTW89_TAS_DELTA;
+}
+
+void rtw89_tas_reset(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+
+ if (!tas->enable)
+ return;
+
+ memset(&tas->txpwr_history, 0, sizeof(tas->txpwr_history));
+ tas->total_txpwr = 0;
+ tas->cur_idx = 0;
+ tas->state = RTW89_TAS_STATE_DPR_OFF;
+}
+
+static const struct rtw89_reg_def txpwr_regs[] = {
+ {R_PATH0_TXPWR, B_PATH0_TXPWR},
+ {R_PATH1_TXPWR, B_PATH1_TXPWR},
+};
+
+void rtw89_tas_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const enum rtw89_sar_sources src = rtwdev->sar.src;
+ u8 max_nss_num = rtwdev->chip->rf_path_num;
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ s16 tmp, txpwr, instant_txpwr = 0;
+ u32 val;
+ int i;
+
+ if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
+ return;
+
+ if (env->ccx_watchdog_result != RTW89_PHY_ENV_MON_IFS_CLM)
+ return;
+
+ for (i = 0; i < max_nss_num; i++) {
+ val = rtw89_phy_read32_mask(rtwdev, txpwr_regs[i].addr,
+ txpwr_regs[i].mask);
+ tmp = sign_extend32(val, 8);
+ if (tmp <= 0)
+ return;
+ instant_txpwr += tmp;
+ }
+
+ instant_txpwr /= max_nss_num;
+ /* in unit of 0.25 dBm multiply by percentage */
+ txpwr = instant_txpwr * env->ifs_clm_tx_ratio;
+ tas->total_txpwr += txpwr - tas->txpwr_history[tas->cur_idx];
+ tas->txpwr_history[tas->cur_idx] = txpwr;
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "instant_txpwr: %d, tx_ratio: %d, txpwr: %d\n",
+ instant_txpwr, env->ifs_clm_tx_ratio, txpwr);
+
+ tas->cur_idx = (tas->cur_idx + 1) % RTW89_TAS_MAX_WINDOW;
+
+ rtw89_tas_state_update(rtwdev);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/sar.h b/drivers/net/wireless/realtek/rtw89/sar.h
index 7b5484c84eb1..bd7a657188d9 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.h
+++ b/drivers/net/wireless/realtek/rtw89/sar.h
@@ -13,14 +13,18 @@
struct rtw89_sar_handler {
const char *descr_sar_source;
u8 txpwr_factor_sar;
- int (*query_sar_config)(struct rtw89_dev *rtwdev, s32 *cfg);
+ int (*query_sar_config)(struct rtw89_dev *rtwdev, u32 center_freq, s32 *cfg);
};
extern const struct cfg80211_sar_capa rtw89_sar_capa;
-s8 rtw89_query_sar(struct rtw89_dev *rtwdev);
-void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev);
+s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq);
+void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev, u32 center_freq);
+void rtw89_print_tas(struct seq_file *m, struct rtw89_dev *rtwdev);
int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar);
+void rtw89_tas_init(struct rtw89_dev *rtwdev);
+void rtw89_tas_reset(struct rtw89_dev *rtwdev);
+void rtw89_tas_track(struct rtw89_dev *rtwdev);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
index 0462ba693f6f..c1644353053f 100644
--- a/drivers/net/wireless/realtek/rtw89/ser.c
+++ b/drivers/net/wireless/realtek/rtw89/ser.c
@@ -529,6 +529,9 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt)
static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf,
u8 sel, u32 start_addr, u32 len)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 filter_model_addr = mac->filter_model_addr;
+ u32 indir_access_addr = mac->indir_access_addr;
u32 *ptr = (u32 *)buf;
u32 base_addr, start_page, residue;
u32 cnt = 0;
@@ -536,14 +539,14 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf,
start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE;
residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE;
- base_addr = rtw89_mac_mem_base_addrs[sel];
+ base_addr = mac->mem_base_addrs[sel];
base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE;
while (cnt < len) {
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr);
+ rtw89_write32(rtwdev, filter_model_addr, base_addr);
- for (i = R_AX_INDIR_ACCESS_ENTRY + residue;
- i < R_AX_INDIR_ACCESS_ENTRY + MAC_MEM_DUMP_PAGE_SIZE;
+ for (i = indir_access_addr + residue;
+ i < indir_access_addr + MAC_MEM_DUMP_PAGE_SIZE;
i += 4, ptr++) {
*ptr = rtw89_read32(rtwdev, i);
cnt += 4;
@@ -585,6 +588,9 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf,
const struct __fw_backtrace_entry *ent)
{
struct __fw_backtrace_info *ptr = (struct __fw_backtrace_info *)buf;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 filter_model_addr = mac->filter_model_addr;
+ u32 indir_access_addr = mac->indir_access_addr;
u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK;
u32 fwbt_size = ent->size;
u32 fwbt_key = ent->key;
@@ -610,10 +616,10 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf,
}
rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace start\n");
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, fwbt_addr);
+ rtw89_write32(rtwdev, filter_model_addr, fwbt_addr);
- for (i = R_AX_INDIR_ACCESS_ENTRY;
- i < R_AX_INDIR_ACCESS_ENTRY + fwbt_size;
+ for (i = indir_access_addr;
+ i < indir_access_addr + fwbt_size;
i += RTW89_FW_BACKTRACE_INFO_SIZE, ptr++) {
*ptr = (struct __fw_backtrace_info){
.ra = rtw89_read32(rtwdev, i),
diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h
index ec96da36eacc..02cff0f7d86b 100644
--- a/drivers/net/wireless/realtek/rtw89/txrx.h
+++ b/drivers/net/wireless/realtek/rtw89/txrx.h
@@ -8,19 +8,56 @@
#include "debug.h"
#define DATA_RATE_MODE_CTRL_MASK GENMASK(8, 7)
+#define DATA_RATE_MODE_CTRL_MASK_V1 GENMASK(10, 8)
#define DATA_RATE_NOT_HT_IDX_MASK GENMASK(3, 0)
#define DATA_RATE_MODE_NON_HT 0x0
#define DATA_RATE_HT_IDX_MASK GENMASK(4, 0)
+#define DATA_RATE_HT_IDX_MASK_V1 GENMASK(4, 0)
#define DATA_RATE_MODE_HT 0x1
#define DATA_RATE_VHT_HE_NSS_MASK GENMASK(6, 4)
#define DATA_RATE_VHT_HE_IDX_MASK GENMASK(3, 0)
+#define DATA_RATE_NSS_MASK_V1 GENMASK(7, 5)
+#define DATA_RATE_MCS_MASK_V1 GENMASK(4, 0)
#define DATA_RATE_MODE_VHT 0x2
#define DATA_RATE_MODE_HE 0x3
-#define GET_DATA_RATE_MODE(r) FIELD_GET(DATA_RATE_MODE_CTRL_MASK, r)
-#define GET_DATA_RATE_NOT_HT_IDX(r) FIELD_GET(DATA_RATE_NOT_HT_IDX_MASK, r)
-#define GET_DATA_RATE_HT_IDX(r) FIELD_GET(DATA_RATE_HT_IDX_MASK, r)
-#define GET_DATA_RATE_VHT_HE_IDX(r) FIELD_GET(DATA_RATE_VHT_HE_IDX_MASK, r)
-#define GET_DATA_RATE_NSS(r) FIELD_GET(DATA_RATE_VHT_HE_NSS_MASK, r)
+#define DATA_RATE_MODE_EHT 0x4
+
+static inline u8 rtw89_get_data_rate_mode(struct rtw89_dev *rtwdev, u16 hw_rate)
+{
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return u16_get_bits(hw_rate, DATA_RATE_MODE_CTRL_MASK_V1);
+
+ return u16_get_bits(hw_rate, DATA_RATE_MODE_CTRL_MASK);
+}
+
+static inline u8 rtw89_get_data_not_ht_idx(struct rtw89_dev *rtwdev, u16 hw_rate)
+{
+ return u16_get_bits(hw_rate, DATA_RATE_NOT_HT_IDX_MASK);
+}
+
+static inline u8 rtw89_get_data_ht_mcs(struct rtw89_dev *rtwdev, u16 hw_rate)
+{
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return u16_get_bits(hw_rate, DATA_RATE_HT_IDX_MASK_V1);
+
+ return u16_get_bits(hw_rate, DATA_RATE_HT_IDX_MASK);
+}
+
+static inline u8 rtw89_get_data_mcs(struct rtw89_dev *rtwdev, u16 hw_rate)
+{
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return u16_get_bits(hw_rate, DATA_RATE_MCS_MASK_V1);
+
+ return u16_get_bits(hw_rate, DATA_RATE_VHT_HE_IDX_MASK);
+}
+
+static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate)
+{
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return u16_get_bits(hw_rate, DATA_RATE_NSS_MASK_V1);
+
+ return u16_get_bits(hw_rate, DATA_RATE_VHT_HE_NSS_MASK);
+}
/* TX WD BODY DWORD 0 */
#define RTW89_TXWD_BODY0_WP_OFFSET GENMASK(31, 24)
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 364e54622150..aa9efca04025 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -40,6 +40,7 @@ static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev)
static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
if (enable_wow) {
@@ -49,7 +50,7 @@ static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow)
return ret;
}
rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP);
- rtw89_write32_clr(rtwdev, R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE);
+ rtw89_write32_clr(rtwdev, mac->rx_fltr, B_AX_SNIFFER_MODE);
rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false);
rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0);
rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0);
diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
index 45ac9371f262..372eaaa2b9ef 100644
--- a/drivers/net/wireless/rsi/rsi_91x_coex.c
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -52,8 +52,7 @@ static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
static void rsi_coex_scheduler_thread(struct rsi_common *common)
{
- struct rsi_coex_ctrl_block *coex_cb =
- (struct rsi_coex_ctrl_block *)common->coex_cb;
+ struct rsi_coex_ctrl_block *coex_cb = common->coex_cb;
u32 timeout = EVENT_WAIT_FOREVER;
do {
@@ -100,9 +99,8 @@ static inline int rsi_map_coex_q(u8 hal_queue)
int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue)
{
- struct rsi_common *common = (struct rsi_common *)priv;
- struct rsi_coex_ctrl_block *coex_cb =
- (struct rsi_coex_ctrl_block *)common->coex_cb;
+ struct rsi_common *common = priv;
+ struct rsi_coex_ctrl_block *coex_cb = common->coex_cb;
struct skb_info *tx_params = NULL;
enum rsi_coex_queues coex_q;
int status;
@@ -168,8 +166,7 @@ int rsi_coex_attach(struct rsi_common *common)
void rsi_coex_detach(struct rsi_common *common)
{
- struct rsi_coex_ctrl_block *coex_cb =
- (struct rsi_coex_ctrl_block *)common->coex_cb;
+ struct rsi_coex_ctrl_block *coex_cb = common->coex_cb;
int cnt;
rsi_kill_thread(&coex_cb->coex_tx_thread);
diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c
index bf22fd948276..c528e6ca2c8d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c
+++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c
@@ -28,8 +28,7 @@ static int rsi_sdio_stats_read(struct seq_file *seq, void *data)
{
struct rsi_common *common = seq->private;
struct rsi_hw *adapter = common->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
seq_printf(seq, "total_sdio_interrupts: %d\n",
dev->rx_info.sdio_int_counter);
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index d4489b943873..2cebe562a1f4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -424,7 +424,7 @@ out:
int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
{
- struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
+ struct rsi_hw *adapter = common->priv;
struct rsi_data_desc *bcn_frm;
struct ieee80211_hw *hw = common->priv->hw;
struct ieee80211_conf *conf = &hw->conf;
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index bc1f038d1655..05890536e353 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1763,8 +1763,8 @@ static int rsi_mac80211_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration,
enum ieee80211_roc_type type)
{
- struct rsi_hw *adapter = (struct rsi_hw *)hw->priv;
- struct rsi_common *common = (struct rsi_common *)adapter->priv;
+ struct rsi_hw *adapter = hw->priv;
+ struct rsi_common *common = adapter->priv;
int status = 0;
rsi_dbg(INFO_ZONE, "***** Remain on channel *****\n");
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index f9f004446b07..2112d8d277a9 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -270,14 +270,14 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common)
#ifdef CONFIG_RSI_COEX
enum rsi_host_intf rsi_get_host_intf(void *priv)
{
- struct rsi_common *common = (struct rsi_common *)priv;
+ struct rsi_common *common = priv;
return common->priv->rsi_host_intf;
}
void rsi_set_bt_context(void *priv, void *bt_context)
{
- struct rsi_common *common = (struct rsi_common *)priv;
+ struct rsi_common *common = priv;
common->bt_adapter = bt_context;
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index 1911fef3bbad..8e7b757475d2 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -144,8 +144,7 @@ static int rsi_issue_sdiocommand(struct sdio_func *func,
static void rsi_handle_interrupt(struct sdio_func *function)
{
struct rsi_hw *adapter = sdio_get_drvdata(function);
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED)
return;
@@ -337,8 +336,7 @@ static void rsi_reset_card(struct sdio_func *pfunction)
*/
static void rsi_setclock(struct rsi_hw *adapter, u32 freq)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
struct mmc_host *host = dev->pfunction->card->host;
u32 clock;
@@ -358,8 +356,7 @@ static void rsi_setclock(struct rsi_hw *adapter, u32 freq)
*/
static int rsi_setblocklength(struct rsi_hw *adapter, u32 length)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
int status;
rsi_dbg(INIT_ZONE, "%s: Setting the block length\n", __func__);
@@ -380,8 +377,7 @@ static int rsi_setblocklength(struct rsi_hw *adapter, u32 length)
*/
static int rsi_setupcard(struct rsi_hw *adapter)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
int status = 0;
rsi_setclock(adapter, 50000);
@@ -407,8 +403,7 @@ int rsi_sdio_read_register(struct rsi_hw *adapter,
u32 addr,
u8 *data)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u8 fun_num = 0;
int status;
@@ -441,8 +436,7 @@ int rsi_sdio_write_register(struct rsi_hw *adapter,
u32 addr,
u8 *data)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
int status = 0;
if (likely(dev->sdio_irq_task != current))
@@ -495,8 +489,7 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter,
u8 *data,
u16 count)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u32 status;
if (likely(dev->sdio_irq_task != current))
@@ -527,8 +520,7 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter,
u8 *data,
u16 count)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
int status;
if (dev->write_fail > 1) {
@@ -762,8 +754,7 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter,
u8 *pkt,
u32 len)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u32 block_size = dev->tx_blk_size;
u32 num_blocks, address, length;
u32 queueno;
@@ -1045,7 +1036,7 @@ static int rsi_probe(struct sdio_func *pfunction,
goto fail_free_adapter;
}
- sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ sdev = adapter->rsi_dev;
rsi_init_event(&sdev->rx_thread.event);
status = rsi_create_kthread(adapter->priv, &sdev->rx_thread,
rsi_sdio_rx_thread, "SDIO-RX-Thread");
@@ -1221,7 +1212,7 @@ static void rsi_disconnect(struct sdio_func *pfunction)
if (!adapter)
return;
- dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ dev = adapter->rsi_dev;
rsi_kill_thread(&dev->rx_thread);
sdio_claim_host(pfunction);
@@ -1255,8 +1246,7 @@ static void rsi_disconnect(struct sdio_func *pfunction)
#ifdef CONFIG_PM
static int rsi_set_sdio_pm_caps(struct rsi_hw *adapter)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
struct sdio_func *func = dev->pfunction;
int ret;
@@ -1407,7 +1397,7 @@ static int rsi_freeze(struct device *dev)
return -ENODEV;
}
common = adapter->priv;
- sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ sdev = adapter->rsi_dev;
if ((common->wow_flags & RSI_WOW_ENABLED) &&
(common->wow_flags & RSI_WOW_NO_CONNECTION))
@@ -1457,8 +1447,7 @@ static void rsi_shutdown(struct device *dev)
{
struct sdio_func *pfunction = dev_to_sdio_func(dev);
struct rsi_hw *adapter = sdio_get_drvdata(pfunction);
- struct rsi_91x_sdiodev *sdev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
struct ieee80211_hw *hw = adapter->hw;
rsi_dbg(ERR_ZONE, "SDIO Bus shutdown =====>\n");
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index b2b47a0abcbf..597b238e2294 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -88,8 +88,7 @@ void rsi_sdio_rx_thread(struct rsi_common *common)
static int rsi_process_pkt(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u8 num_blks = 0;
u32 rcv_pkt_len = 0;
int status = 0;
@@ -147,8 +146,7 @@ static int rsi_process_pkt(struct rsi_common *common)
*/
int rsi_init_sdio_slave_regs(struct rsi_hw *adapter)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u8 function = 0;
u8 byte;
int status = 0;
@@ -233,8 +231,7 @@ int rsi_init_sdio_slave_regs(struct rsi_hw *adapter)
static void rsi_rx_handler(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
int status;
u8 isr_status = 0;
u8 fw_status = 0;
@@ -339,8 +336,7 @@ static void rsi_rx_handler(struct rsi_hw *adapter)
int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num)
{
struct rsi_common *common = adapter->priv;
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
u8 buf_status = 0;
int status = 0;
static int counter = 4;
@@ -409,8 +405,7 @@ out:
*/
int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter)
{
- struct rsi_91x_sdiodev *dev =
- (struct rsi_91x_sdiodev *)adapter->rsi_dev;
+ struct rsi_91x_sdiodev *dev = adapter->rsi_dev;
/* Once buffer full is seen, event timeout to occur every 2 msecs */
if (dev->rx_info.buffer_full)
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 66fe386ec9cc..10a465686439 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -43,7 +43,7 @@ static int rsi_usb_card_write(struct rsi_hw *adapter,
u16 len,
u8 endpoint)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
int status;
u8 *seg = dev->tx_buffer;
int transfer;
@@ -91,7 +91,7 @@ static int rsi_write_multiple(struct rsi_hw *adapter,
if (endpoint == 0)
return -EINVAL;
- dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ dev = adapter->rsi_dev;
if (dev->write_fail)
return -ENETDOWN;
@@ -109,7 +109,7 @@ static int rsi_write_multiple(struct rsi_hw *adapter,
static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface,
struct rsi_hw *adapter)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
__le16 buffer_size;
@@ -306,7 +306,7 @@ out:
static void rsi_rx_urb_kill(struct rsi_hw *adapter, u8 ep_num)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1];
struct urb *urb = rx_cb->rx_urb;
@@ -323,7 +323,7 @@ static void rsi_rx_urb_kill(struct rsi_hw *adapter, u8 ep_num)
*/
static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num, gfp_t mem_flags)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1];
struct urb *urb = rx_cb->rx_urb;
int status;
@@ -362,7 +362,7 @@ static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num, gfp_t mem_flags)
static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr,
u8 *data, u16 count)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
u8 *buf;
u16 transfer;
int status;
@@ -412,7 +412,7 @@ static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr,
static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr,
u8 *data, u16 count)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
u8 *buf;
u16 transfer;
int status = 0;
@@ -559,7 +559,7 @@ static struct rsi_host_intf_ops usb_host_intf_ops = {
*/
static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
rsi_kill_thread(&dev->rx_thread);
@@ -572,7 +572,7 @@ static void rsi_deinit_usb_interface(struct rsi_hw *adapter)
static int rsi_usb_init_rx(struct rsi_hw *adapter)
{
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
struct rx_usb_ctrl_block *rx_cb;
u8 idx, num_rx_cb;
@@ -822,7 +822,7 @@ static int rsi_probe(struct usb_interface *pfunction,
goto err1;
}
- dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ dev = adapter->rsi_dev;
status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2);
if (status < 0)
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
index 5130b0e72adc..25c2b232394a 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c
@@ -28,7 +28,7 @@
void rsi_usb_rx_thread(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
- struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev;
+ struct rsi_91x_usbdev *dev = adapter->rsi_dev;
int status;
struct sk_buff *skb;
diff --git a/drivers/net/wireless/silabs/wfx/bus_sdio.c b/drivers/net/wireless/silabs/wfx/bus_sdio.c
index 51a0d58a9070..909d5f346a01 100644
--- a/drivers/net/wireless/silabs/wfx/bus_sdio.c
+++ b/drivers/net/wireless/silabs/wfx/bus_sdio.c
@@ -10,7 +10,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/interrupt.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/align.h>
diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
index 0b50f7058bbb..ede822d771aa 100644
--- a/drivers/net/wireless/silabs/wfx/main.c
+++ b/drivers/net/wireless/silabs/wfx/main.c
@@ -293,13 +293,12 @@ struct wfx_dev *wfx_init_common(struct device *dev, const struct wfx_platform_da
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations);
hw->wiphy->iface_combinations = wfx_iface_combinations;
- hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL);
+ /* FIXME: also copy wfx_rates and wfx_2ghz_chantable */
+ hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmemdup(dev, &wfx_band_2ghz,
+ sizeof(wfx_band_2ghz), GFP_KERNEL);
if (!hw->wiphy->bands[NL80211_BAND_2GHZ])
goto err;
- /* FIXME: also copy wfx_rates and wfx_2ghz_chantable */
- memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, sizeof(wfx_band_2ghz));
-
wdev = hw->priv;
wdev->hw = hw;
wdev->dev = dev;
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index cf8d909fa826..f0686635db46 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -442,18 +442,7 @@ static struct sdio_driver wl1271_sdio_driver = {
#endif
};
-static int __init wl1271_init(void)
-{
- return sdio_register_driver(&wl1271_sdio_driver);
-}
-
-static void __exit wl1271_exit(void)
-{
- sdio_unregister_driver(&wl1271_sdio_driver);
-}
-
-module_init(wl1271_init);
-module_exit(wl1271_exit);
+module_sdio_driver(wl1271_sdio_driver);
module_param(dump, bool, 0600);
MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 3f88e6a0a510..7d9a139db59e 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -554,7 +554,7 @@ static void wl1271_remove(struct spi_device *spi)
static struct spi_driver wl1271_spi_driver = {
.driver = {
.name = "wl1271_spi",
- .of_match_table = of_match_ptr(wlcore_spi_of_match_table),
+ .of_match_table = wlcore_spi_of_match_table,
},
.probe = wl1271_probe,
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index f446fd0e8cd0..1f524030b186 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -582,9 +582,8 @@ static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
*/
/* Add vendor data */
- err = nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
- if (err)
- return err;
+ nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
+
/* Send the event - this will call nla_nest_end() */
cfg80211_vendor_event(skb, GFP_KERNEL);
}
@@ -5626,14 +5625,15 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
+ if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) ||
+ frame_data_len > IEEE80211_MAX_DATA_LEN)
+ goto err;
+
/* Allocate new skb here */
skb = alloc_skb(frame_data_len, GFP_KERNEL);
if (skb == NULL)
goto err;
- if (frame_data_len > IEEE80211_MAX_DATA_LEN)
- goto err;
-
/* Copy the data */
skb_put_data(skb, frame_data, frame_data_len);
@@ -6314,7 +6314,7 @@ static void hwsim_virtio_tx_done(struct virtqueue *vq)
spin_lock_irqsave(&hwsim_virtio_lock, flags);
while ((skb = virtqueue_get_buf(vq, &len)))
- nlmsg_free(skb);
+ dev_kfree_skb_irq(skb);
spin_unlock_irqrestore(&hwsim_virtio_lock, flags);
}
@@ -6383,14 +6383,14 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
spin_lock_irqsave(&hwsim_virtio_lock, flags);
if (!hwsim_virtio_enabled) {
- nlmsg_free(skb);
+ dev_kfree_skb_irq(skb);
goto out_unlock;
}
vq = hwsim_vqs[HWSIM_VQ_RX];
sg_init_one(sg, skb->head, skb_end_offset(skb));
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_ATOMIC);
if (WARN(err, "virtqueue_add_inbuf returned %d\n", err))
- nlmsg_free(skb);
+ dev_kfree_skb_irq(skb);
else
virtqueue_kick(vq);
schedule_work(&hwsim_virtio_rx);
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
index a85fe7e4c6d4..2814df1ecc78 100644
--- a/drivers/net/wireless/zydas/zd1201.c
+++ b/drivers/net/wireless/zydas/zd1201.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Driver for ZyDAS zd1201 based wireless USB devices.
+ * Driver for ZyDAS zd1201 based USB wireless devices.
*
* Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*
@@ -23,8 +23,8 @@
#include "zd1201.h"
static const struct usb_device_id zd1201_table[] = {
- {USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */
- {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
+ {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */
+ {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */
{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */
{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */
{USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
index 850c26bc9524..8505d84eeed6 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c
@@ -1006,7 +1006,7 @@ resubmit:
* @usb: the zd1211rw-private USB structure
* @skb: a &struct sk_buff pointer
*
- * This function tranmits a frame to the device. It doesn't wait for
+ * This function transmits a frame to the device. It doesn't wait for
* completion. The frame must contain the control set and have all the
* control set information available.
*
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
index 7162bf38a8c9..cc70360364b7 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
@@ -1066,13 +1066,18 @@ static void t7xx_hw_info_init(struct cldma_ctrl *md_ctrl)
struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info;
u32 phy_ao_base, phy_pd_base;
- if (md_ctrl->hif_id != CLDMA_ID_MD)
- return;
-
- phy_ao_base = CLDMA1_AO_BASE;
- phy_pd_base = CLDMA1_PD_BASE;
- hw_info->phy_interrupt_id = CLDMA1_INT;
hw_info->hw_mode = MODE_BIT_64;
+
+ if (md_ctrl->hif_id == CLDMA_ID_MD) {
+ phy_ao_base = CLDMA1_AO_BASE;
+ phy_pd_base = CLDMA1_PD_BASE;
+ hw_info->phy_interrupt_id = CLDMA1_INT;
+ } else {
+ phy_ao_base = CLDMA0_AO_BASE;
+ phy_pd_base = CLDMA0_PD_BASE;
+ hw_info->phy_interrupt_id = CLDMA0_INT;
+ }
+
hw_info->ap_ao_base = t7xx_pcie_addr_transfer(pbase->pcie_ext_reg_base,
pbase->pcie_dev_reg_trsl_addr, phy_ao_base);
hw_info->ap_pdn_base = t7xx_pcie_addr_transfer(pbase->pcie_ext_reg_base,
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
index 47a35e552da7..4410bac6993a 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
@@ -34,7 +34,7 @@
/**
* enum cldma_id - Identifiers for CLDMA HW units.
* @CLDMA_ID_MD: Modem control channel.
- * @CLDMA_ID_AP: Application Processor control channel (not used at the moment).
+ * @CLDMA_ID_AP: Application Processor control channel.
* @CLDMA_NUM: Number of CLDMA HW units available.
*/
enum cldma_id {
diff --git a/drivers/net/wwan/t7xx/t7xx_mhccif.h b/drivers/net/wwan/t7xx/t7xx_mhccif.h
index 209b386bc088..20c50dce9fc3 100644
--- a/drivers/net/wwan/t7xx/t7xx_mhccif.h
+++ b/drivers/net/wwan/t7xx/t7xx_mhccif.h
@@ -25,6 +25,7 @@
D2H_INT_EXCEPTION_CLEARQ_DONE | \
D2H_INT_EXCEPTION_ALLQ_RESET | \
D2H_INT_PORT_ENUM | \
+ D2H_INT_ASYNC_AP_HK | \
D2H_INT_ASYNC_MD_HK)
void t7xx_mhccif_mask_set(struct t7xx_pci_dev *t7xx_dev, u32 val);
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index 7d0f5e4f0a78..24e7d491468e 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -44,6 +44,7 @@
#include "t7xx_state_monitor.h"
#define RT_ID_MD_PORT_ENUM 0
+#define RT_ID_AP_PORT_ENUM 1
/* Modem feature query identification code - "ICCC" */
#define MD_FEATURE_QUERY_ID 0x49434343
@@ -298,6 +299,7 @@ static void t7xx_md_exception(struct t7xx_modem *md, enum hif_ex_stage stage)
}
t7xx_cldma_exception(md->md_ctrl[CLDMA_ID_MD], stage);
+ t7xx_cldma_exception(md->md_ctrl[CLDMA_ID_AP], stage);
if (stage == HIF_EX_INIT)
t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_EXCEPTION_ACK);
@@ -426,7 +428,7 @@ static int t7xx_parse_host_rt_data(struct t7xx_fsm_ctl *ctl, struct t7xx_sys_inf
if (ft_spt_st != MTK_FEATURE_MUST_BE_SUPPORTED)
return -EINVAL;
- if (i == RT_ID_MD_PORT_ENUM)
+ if (i == RT_ID_MD_PORT_ENUM || i == RT_ID_AP_PORT_ENUM)
t7xx_port_enum_msg_handler(ctl->md, rt_feature->data);
}
@@ -456,12 +458,12 @@ static int t7xx_core_reset(struct t7xx_modem *md)
return 0;
}
-static void t7xx_core_hk_handler(struct t7xx_modem *md, struct t7xx_fsm_ctl *ctl,
+static void t7xx_core_hk_handler(struct t7xx_modem *md, struct t7xx_sys_info *core_info,
+ struct t7xx_fsm_ctl *ctl,
enum t7xx_fsm_event_state event_id,
enum t7xx_fsm_event_state err_detect)
{
struct t7xx_fsm_event *event = NULL, *event_next;
- struct t7xx_sys_info *core_info = &md->core_md;
struct device *dev = &md->t7xx_dev->pdev->dev;
unsigned long flags;
int ret;
@@ -531,19 +533,33 @@ static void t7xx_md_hk_wq(struct work_struct *work)
t7xx_cldma_start(md->md_ctrl[CLDMA_ID_MD]);
t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_FOR_HS2);
md->core_md.handshake_ongoing = true;
- t7xx_core_hk_handler(md, ctl, FSM_EVENT_MD_HS2, FSM_EVENT_MD_HS2_EXIT);
+ t7xx_core_hk_handler(md, &md->core_md, ctl, FSM_EVENT_MD_HS2, FSM_EVENT_MD_HS2_EXIT);
+}
+
+static void t7xx_ap_hk_wq(struct work_struct *work)
+{
+ struct t7xx_modem *md = container_of(work, struct t7xx_modem, ap_handshake_work);
+ struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
+
+ /* Clear the HS2 EXIT event appended in t7xx_core_reset(). */
+ t7xx_fsm_clr_event(ctl, FSM_EVENT_AP_HS2_EXIT);
+ t7xx_cldma_stop(md->md_ctrl[CLDMA_ID_AP]);
+ t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_AP]);
+ t7xx_cldma_start(md->md_ctrl[CLDMA_ID_AP]);
+ md->core_ap.handshake_ongoing = true;
+ t7xx_core_hk_handler(md, &md->core_ap, ctl, FSM_EVENT_AP_HS2, FSM_EVENT_AP_HS2_EXIT);
}
void t7xx_md_event_notify(struct t7xx_modem *md, enum md_event_id evt_id)
{
struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
- void __iomem *mhccif_base;
unsigned int int_sta;
unsigned long flags;
switch (evt_id) {
case FSM_PRE_START:
- t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM);
+ t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM | D2H_INT_ASYNC_MD_HK |
+ D2H_INT_ASYNC_AP_HK);
break;
case FSM_START:
@@ -556,16 +572,26 @@ void t7xx_md_event_notify(struct t7xx_modem *md, enum md_event_id evt_id)
ctl->exp_flg = true;
md->exp_id &= ~D2H_INT_EXCEPTION_INIT;
md->exp_id &= ~D2H_INT_ASYNC_MD_HK;
+ md->exp_id &= ~D2H_INT_ASYNC_AP_HK;
} else if (ctl->exp_flg) {
md->exp_id &= ~D2H_INT_ASYNC_MD_HK;
- } else if (md->exp_id & D2H_INT_ASYNC_MD_HK) {
- queue_work(md->handshake_wq, &md->handshake_work);
- md->exp_id &= ~D2H_INT_ASYNC_MD_HK;
- mhccif_base = md->t7xx_dev->base_addr.mhccif_rc_base;
- iowrite32(D2H_INT_ASYNC_MD_HK, mhccif_base + REG_EP2RC_SW_INT_ACK);
- t7xx_mhccif_mask_set(md->t7xx_dev, D2H_INT_ASYNC_MD_HK);
+ md->exp_id &= ~D2H_INT_ASYNC_AP_HK;
} else {
- t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_ASYNC_MD_HK);
+ void __iomem *mhccif_base = md->t7xx_dev->base_addr.mhccif_rc_base;
+
+ if (md->exp_id & D2H_INT_ASYNC_MD_HK) {
+ queue_work(md->handshake_wq, &md->handshake_work);
+ md->exp_id &= ~D2H_INT_ASYNC_MD_HK;
+ iowrite32(D2H_INT_ASYNC_MD_HK, mhccif_base + REG_EP2RC_SW_INT_ACK);
+ t7xx_mhccif_mask_set(md->t7xx_dev, D2H_INT_ASYNC_MD_HK);
+ }
+
+ if (md->exp_id & D2H_INT_ASYNC_AP_HK) {
+ queue_work(md->handshake_wq, &md->ap_handshake_work);
+ md->exp_id &= ~D2H_INT_ASYNC_AP_HK;
+ iowrite32(D2H_INT_ASYNC_AP_HK, mhccif_base + REG_EP2RC_SW_INT_ACK);
+ t7xx_mhccif_mask_set(md->t7xx_dev, D2H_INT_ASYNC_AP_HK);
+ }
}
spin_unlock_irqrestore(&md->exp_lock, flags);
@@ -578,6 +604,7 @@ void t7xx_md_event_notify(struct t7xx_modem *md, enum md_event_id evt_id)
case FSM_READY:
t7xx_mhccif_mask_set(md->t7xx_dev, D2H_INT_ASYNC_MD_HK);
+ t7xx_mhccif_mask_set(md->t7xx_dev, D2H_INT_ASYNC_AP_HK);
break;
default:
@@ -629,6 +656,12 @@ static struct t7xx_modem *t7xx_md_alloc(struct t7xx_pci_dev *t7xx_dev)
md->core_md.feature_set[RT_ID_MD_PORT_ENUM] &= ~FEATURE_MSK;
md->core_md.feature_set[RT_ID_MD_PORT_ENUM] |=
FIELD_PREP(FEATURE_MSK, MTK_FEATURE_MUST_BE_SUPPORTED);
+
+ INIT_WORK(&md->ap_handshake_work, t7xx_ap_hk_wq);
+ md->core_ap.feature_set[RT_ID_AP_PORT_ENUM] &= ~FEATURE_MSK;
+ md->core_ap.feature_set[RT_ID_AP_PORT_ENUM] |=
+ FIELD_PREP(FEATURE_MSK, MTK_FEATURE_MUST_BE_SUPPORTED);
+
return md;
}
@@ -640,6 +673,7 @@ int t7xx_md_reset(struct t7xx_pci_dev *t7xx_dev)
md->exp_id = 0;
t7xx_fsm_reset(md);
t7xx_cldma_reset(md->md_ctrl[CLDMA_ID_MD]);
+ t7xx_cldma_reset(md->md_ctrl[CLDMA_ID_AP]);
t7xx_port_proxy_reset(md->port_prox);
md->md_init_finish = true;
return t7xx_core_reset(md);
@@ -669,6 +703,10 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev)
if (ret)
goto err_destroy_hswq;
+ ret = t7xx_cldma_alloc(CLDMA_ID_AP, t7xx_dev);
+ if (ret)
+ goto err_destroy_hswq;
+
ret = t7xx_fsm_init(md);
if (ret)
goto err_destroy_hswq;
@@ -681,12 +719,16 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev)
if (ret)
goto err_uninit_ccmni;
- ret = t7xx_port_proxy_init(md);
+ ret = t7xx_cldma_init(md->md_ctrl[CLDMA_ID_AP]);
if (ret)
goto err_uninit_md_cldma;
+ ret = t7xx_port_proxy_init(md);
+ if (ret)
+ goto err_uninit_ap_cldma;
+
ret = t7xx_fsm_append_cmd(md->fsm_ctl, FSM_CMD_START, 0);
- if (ret) /* fsm_uninit flushes cmd queue */
+ if (ret) /* t7xx_fsm_uninit() flushes cmd queue */
goto err_uninit_proxy;
t7xx_md_sys_sw_init(t7xx_dev);
@@ -696,6 +738,9 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev)
err_uninit_proxy:
t7xx_port_proxy_uninit(md->port_prox);
+err_uninit_ap_cldma:
+ t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_AP]);
+
err_uninit_md_cldma:
t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_MD]);
@@ -722,6 +767,7 @@ void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev)
t7xx_fsm_append_cmd(md->fsm_ctl, FSM_CMD_PRE_STOP, FSM_CMD_FLAG_WAIT_FOR_COMPLETION);
t7xx_port_proxy_uninit(md->port_prox);
+ t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_AP]);
t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_MD]);
t7xx_ccmni_exit(t7xx_dev);
t7xx_fsm_uninit(md);
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.h b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
index 7469ed636ae8..abe633cf7adc 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.h
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
@@ -66,10 +66,12 @@ struct t7xx_modem {
struct cldma_ctrl *md_ctrl[CLDMA_NUM];
struct t7xx_pci_dev *t7xx_dev;
struct t7xx_sys_info core_md;
+ struct t7xx_sys_info core_ap;
bool md_init_finish;
bool rgu_irq_asserted;
struct workqueue_struct *handshake_wq;
struct work_struct handshake_work;
+ struct work_struct ap_handshake_work;
struct t7xx_fsm_ctl *fsm_ctl;
struct port_proxy *port_prox;
unsigned int exp_id;
diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index 8ea9079af997..4ae8a00a8532 100644
--- a/drivers/net/wwan/t7xx/t7xx_port.h
+++ b/drivers/net/wwan/t7xx/t7xx_port.h
@@ -36,9 +36,13 @@
/* Channel ID and Message ID definitions.
* The channel number consists of peer_id(15:12) , channel_id(11:0)
* peer_id:
- * 0:reserved, 1: to sAP, 2: to MD
+ * 0:reserved, 1: to AP, 2: to MD
*/
enum port_ch {
+ /* to AP */
+ PORT_CH_AP_CONTROL_RX = 0x1000,
+ PORT_CH_AP_CONTROL_TX = 0x1001,
+
/* to MD */
PORT_CH_CONTROL_RX = 0x2000,
PORT_CH_CONTROL_TX = 0x2001,
diff --git a/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c b/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
index 68430b130a67..ae632ef96698 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_ctrl_msg.c
@@ -167,8 +167,12 @@ static int control_msg_handler(struct t7xx_port *port, struct sk_buff *skb)
case CTL_ID_HS2_MSG:
skb_pull(skb, sizeof(*ctrl_msg_h));
- if (port_conf->rx_ch == PORT_CH_CONTROL_RX) {
- ret = t7xx_fsm_append_event(ctl, FSM_EVENT_MD_HS2, skb->data,
+ if (port_conf->rx_ch == PORT_CH_CONTROL_RX ||
+ port_conf->rx_ch == PORT_CH_AP_CONTROL_RX) {
+ int event = port_conf->rx_ch == PORT_CH_CONTROL_RX ?
+ FSM_EVENT_MD_HS2 : FSM_EVENT_AP_HS2;
+
+ ret = t7xx_fsm_append_event(ctl, event, skb->data,
le32_to_cpu(ctrl_msg_h->data_length));
if (ret)
dev_err(port->dev, "Failed to append Handshake 2 event");
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index 894b1d11b2c9..274846d39fbf 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -48,7 +48,7 @@
i < (proxy)->port_count; \
i++, (p) = &(proxy)->ports[i])
-static const struct t7xx_port_conf t7xx_md_port_conf[] = {
+static const struct t7xx_port_conf t7xx_port_conf[] = {
{
.tx_ch = PORT_CH_UART2_TX,
.rx_ch = PORT_CH_UART2_RX,
@@ -89,6 +89,14 @@ static const struct t7xx_port_conf t7xx_md_port_conf[] = {
.path_id = CLDMA_ID_MD,
.ops = &ctl_port_ops,
.name = "t7xx_ctrl",
+ }, {
+ .tx_ch = PORT_CH_AP_CONTROL_TX,
+ .rx_ch = PORT_CH_AP_CONTROL_RX,
+ .txq_index = Q_IDX_CTRL,
+ .rxq_index = Q_IDX_CTRL,
+ .path_id = CLDMA_ID_AP,
+ .ops = &ctl_port_ops,
+ .name = "t7xx_ap_ctrl",
},
};
@@ -428,6 +436,9 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
if (port_conf->tx_ch == PORT_CH_CONTROL_TX)
md->core_md.ctl_port = port;
+ if (port_conf->tx_ch == PORT_CH_AP_CONTROL_TX)
+ md->core_ap.ctl_port = port;
+
port->t7xx_dev = md->t7xx_dev;
port->dev = &md->t7xx_dev->pdev->dev;
spin_lock_init(&port->port_update_lock);
@@ -442,7 +453,7 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
static int t7xx_proxy_alloc(struct t7xx_modem *md)
{
- unsigned int port_count = ARRAY_SIZE(t7xx_md_port_conf);
+ unsigned int port_count = ARRAY_SIZE(t7xx_port_conf);
struct device *dev = &md->t7xx_dev->pdev->dev;
struct port_proxy *port_prox;
int i;
@@ -456,7 +467,7 @@ static int t7xx_proxy_alloc(struct t7xx_modem *md)
port_prox->dev = dev;
for (i = 0; i < port_count; i++)
- port_prox->ports[i].port_conf = &t7xx_md_port_conf[i];
+ port_prox->ports[i].port_conf = &t7xx_port_conf[i];
port_prox->port_count = port_count;
t7xx_proxy_init_all_ports(md);
@@ -481,6 +492,7 @@ int t7xx_port_proxy_init(struct t7xx_modem *md)
if (ret)
return ret;
+ t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_AP], t7xx_port_proxy_recv_skb);
t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_MD], t7xx_port_proxy_recv_skb);
return 0;
}
diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h
index 7c1b81091a0f..c41d7d094c08 100644
--- a/drivers/net/wwan/t7xx/t7xx_reg.h
+++ b/drivers/net/wwan/t7xx/t7xx_reg.h
@@ -56,7 +56,7 @@
#define D2H_INT_RESUME_ACK BIT(12)
#define D2H_INT_SUSPEND_ACK_AP BIT(13)
#define D2H_INT_RESUME_ACK_AP BIT(14)
-#define D2H_INT_ASYNC_SAP_HK BIT(15)
+#define D2H_INT_ASYNC_AP_HK BIT(15)
#define D2H_INT_ASYNC_MD_HK BIT(16)
/* Register base */
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
index 0bcca08ff2bd..80edb8e75a6a 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
@@ -285,8 +285,9 @@ static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl)
t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_FOR_HS1);
t7xx_md_event_notify(md, FSM_START);
- wait_event_interruptible_timeout(ctl->async_hk_wq, md->core_md.ready || ctl->exp_flg,
- HZ * 60);
+ wait_event_interruptible_timeout(ctl->async_hk_wq,
+ (md->core_md.ready && md->core_ap.ready) ||
+ ctl->exp_flg, HZ * 60);
dev = &md->t7xx_dev->pdev->dev;
if (ctl->exp_flg)
@@ -299,6 +300,13 @@ static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl)
fsm_routine_exception(ctl, NULL, EXCEPTION_HS_TIMEOUT);
return -ETIMEDOUT;
+ } else if (!md->core_ap.ready) {
+ dev_err(dev, "AP handshake timeout\n");
+ if (md->core_ap.handshake_ongoing)
+ t7xx_fsm_append_event(ctl, FSM_EVENT_AP_HS2_EXIT, NULL, 0);
+
+ fsm_routine_exception(ctl, NULL, EXCEPTION_HS_TIMEOUT);
+ return -ETIMEDOUT;
}
t7xx_pci_pm_init_late(md->t7xx_dev);
@@ -335,6 +343,7 @@ static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command
return;
}
+ t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
fsm_finish_command(ctl, cmd, fsm_routine_starting(ctl));
}
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.h b/drivers/net/wwan/t7xx/t7xx_state_monitor.h
index b1af0259d4c5..b6e76f3903c8 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.h
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.h
@@ -38,10 +38,12 @@ enum t7xx_fsm_state {
enum t7xx_fsm_event_state {
FSM_EVENT_INVALID,
FSM_EVENT_MD_HS2,
+ FSM_EVENT_AP_HS2,
FSM_EVENT_MD_EX,
FSM_EVENT_MD_EX_REC_OK,
FSM_EVENT_MD_EX_PASS,
FSM_EVENT_MD_HS2_EXIT,
+ FSM_EVENT_AP_HS2_EXIT,
FSM_EVENT_MAX
};
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 47d54d8ea59d..ad29f370034e 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -45,7 +45,7 @@
#include <linux/slab.h>
#include <net/ip.h>
#include <linux/bpf.h>
-#include <net/page_pool.h>
+#include <net/page_pool/types.h>
#include <linux/bpf_trace.h>
#include <xen/xen.h>
diff --git a/drivers/nfc/virtual_ncidev.c b/drivers/nfc/virtual_ncidev.c
index bb76c7c7cc82..b027be0b0b6f 100644
--- a/drivers/nfc/virtual_ncidev.c
+++ b/drivers/nfc/virtual_ncidev.c
@@ -200,18 +200,7 @@ static struct miscdevice miscdev = {
.mode = 0600,
};
-static int __init virtual_ncidev_init(void)
-{
- return misc_register(&miscdev);
-}
-
-static void __exit virtual_ncidev_exit(void)
-{
- misc_deregister(&miscdev);
-}
-
-module_init(virtual_ncidev_init);
-module_exit(virtual_ncidev_exit);
+module_misc_device(miscdev);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Virtual NCI device simulation driver");
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index af7d9301520c..18ad315581ca 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -100,7 +100,7 @@ static unsigned long *nd_pfn_supported_alignments(unsigned long *alignments)
if (has_transparent_hugepage()) {
alignments[1] = HPAGE_PMD_SIZE;
- if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD))
+ if (has_transparent_pud_hugepage())
alignments[2] = HPAGE_PUD_SIZE;
}
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index d39f3219358b..d8ff796fd5f2 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -118,7 +118,6 @@ static void *nvme_add_user_metadata(struct request *req, void __user *ubuf,
goto out_free_meta;
}
- bip->bip_iter.bi_size = len;
bip->bip_iter.bi_sector = seed;
ret = bio_integrity_add_page(bio, virt_to_page(buf), len,
offset_in_page(buf));
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 2733e0158585..468833675cc9 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -206,12 +206,11 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
return PTR_ERR(bip);
}
- bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio));
/* virtual start sector must be in integrity interval units */
bip_set_seed(bip, bio->bi_iter.bi_sector >>
(bi->interval_exp - SECTOR_SHIFT));
- resid = bip->bip_iter.bi_size;
+ resid = bio_integrity_bytes(bi, bio_sectors(bio));
while (resid > 0 && sg_miter_next(miter)) {
len = min_t(size_t, miter->length, resid);
rc = bio_integrity_add_page(bio, miter->page, len,
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index e311d406b170..4999636eaa92 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -63,15 +63,14 @@ int of_reconfig_notifier_unregister(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister);
-#ifdef DEBUG
-const char *action_names[] = {
+static const char *action_names[] = {
+ [0] = "INVALID",
[OF_RECONFIG_ATTACH_NODE] = "ATTACH_NODE",
[OF_RECONFIG_DETACH_NODE] = "DETACH_NODE",
[OF_RECONFIG_ADD_PROPERTY] = "ADD_PROPERTY",
[OF_RECONFIG_REMOVE_PROPERTY] = "REMOVE_PROPERTY",
[OF_RECONFIG_UPDATE_PROPERTY] = "UPDATE_PROPERTY",
};
-#endif
int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
{
@@ -620,21 +619,9 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
}
ret = __of_add_property(ce->np, ce->prop);
- if (ret) {
- pr_err("changeset: add_property failed @%pOF/%s\n",
- ce->np,
- ce->prop->name);
- break;
- }
break;
case OF_RECONFIG_REMOVE_PROPERTY:
ret = __of_remove_property(ce->np, ce->prop);
- if (ret) {
- pr_err("changeset: remove_property failed @%pOF/%s\n",
- ce->np,
- ce->prop->name);
- break;
- }
break;
case OF_RECONFIG_UPDATE_PROPERTY:
@@ -648,20 +635,17 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
}
ret = __of_update_property(ce->np, ce->prop, &old_prop);
- if (ret) {
- pr_err("changeset: update_property failed @%pOF/%s\n",
- ce->np,
- ce->prop->name);
- break;
- }
break;
default:
ret = -EINVAL;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- if (ret)
+ if (ret) {
+ pr_err("changeset: apply failed: %-15s %pOF:%s\n",
+ action_names[ce->action], ce->np, ce->prop->name);
return ret;
+ }
switch (ce->action) {
case OF_RECONFIG_ATTACH_NODE:
@@ -947,6 +931,9 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
if (!ce)
return -ENOMEM;
+ if (WARN_ON(action >= ARRAY_SIZE(action_names)))
+ return -EINVAL;
+
/* get a reference to the node */
ce->action = action;
ce->np = of_node_get(np);
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index f26d2ba8a371..68278340cecf 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -184,7 +184,8 @@ int __init ima_free_kexec_buffer(void)
if (ret)
return ret;
- return memblock_phys_free(addr, size);
+ memblock_free_late(addr, size);
+ return 0;
}
#endif
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 0c3475e7d2ff..6a557eb866d0 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -141,7 +141,7 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
/* setup generic device info */
- device_set_node(&dev->dev, of_fwnode_handle(np));
+ device_set_node(&dev->dev, of_fwnode_handle(of_node_get(np)));
dev->dev.parent = parent ? : &platform_bus;
if (bus_id)
@@ -239,7 +239,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
/* setup generic device info */
- device_set_node(&dev->dev, of_fwnode_handle(node));
+ device_set_node(&dev->dev, of_fwnode_handle(of_node_get(node)));
dev->dev.parent = parent ? : &platform_bus;
dev->dev.platform_data = platform_data;
if (bus_id)
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index a406a12eb208..b545fcb22536 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -664,12 +664,12 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
memset(&args, 0, sizeof(args));
EXPECT_BEGIN(KERN_INFO,
- "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle");
+ "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle 12345678");
rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle",
"phandle", 0, &args);
EXPECT_END(KERN_INFO,
- "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle");
+ "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle 12345678");
unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 3f46e499d615..919cc53bc02e 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -177,25 +177,24 @@ unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
EXPORT_SYMBOL_GPL(dev_pm_opp_get_power);
/**
- * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
- * @opp: opp for which frequency has to be returned for
+ * dev_pm_opp_get_freq_indexed() - Gets the frequency corresponding to an
+ * available opp with specified index
+ * @opp: opp for which frequency has to be returned for
+ * @index: index of the frequency within the required opp
*
- * Return: frequency in hertz corresponding to the opp, else
- * return 0
+ * Return: frequency in hertz corresponding to the opp with specified index,
+ * else return 0
*/
-unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
+unsigned long dev_pm_opp_get_freq_indexed(struct dev_pm_opp *opp, u32 index)
{
- if (IS_ERR_OR_NULL(opp)) {
+ if (IS_ERR_OR_NULL(opp) || index >= opp->opp_table->clk_count) {
pr_err("%s: Invalid parameters\n", __func__);
return 0;
}
- if (!assert_single_clk(opp->opp_table))
- return 0;
-
- return opp->rates[0];
+ return opp->rates[index];
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq_indexed);
/**
* dev_pm_opp_get_level() - Gets the level corresponding to an available opp
@@ -227,20 +226,18 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_level);
unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
unsigned int index)
{
- struct opp_table *opp_table = opp->opp_table;
-
if (IS_ERR_OR_NULL(opp) || !opp->available ||
- index >= opp_table->required_opp_count) {
+ index >= opp->opp_table->required_opp_count) {
pr_err("%s: Invalid parameters\n", __func__);
return 0;
}
/* required-opps not fully initialized yet */
- if (lazy_linking_pending(opp_table))
+ if (lazy_linking_pending(opp->opp_table))
return 0;
/* The required OPP table must belong to a genpd */
- if (unlikely(!opp_table->required_opp_tables[index]->is_genpd)) {
+ if (unlikely(!opp->opp_table->required_opp_tables[index]->is_genpd)) {
pr_err("%s: Performance state is only valid for genpds.\n", __func__);
return 0;
}
@@ -450,7 +447,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
/* Helpers to read keys */
static unsigned long _read_freq(struct dev_pm_opp *opp, int index)
{
- return opp->rates[0];
+ return opp->rates[index];
}
static unsigned long _read_level(struct dev_pm_opp *opp, int index)
@@ -626,6 +623,34 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
+/**
+ * dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
+ * clock corresponding to the index
+ * @dev: Device for which we do this operation
+ * @freq: frequency to search for
+ * @index: Clock index
+ * @available: true/false - match for available opp
+ *
+ * Search for the matching exact OPP for the clock corresponding to the
+ * specified index from a starting freq for a device.
+ *
+ * Return: matching *opp , else returns ERR_PTR in case of error and should be
+ * handled using IS_ERR. Error return values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
+ *
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
+ */
+struct dev_pm_opp *
+dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
+ u32 index, bool available)
+{
+ return _find_key_exact(dev, freq, index, available, _read_freq, NULL);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact_indexed);
+
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
unsigned long *freq)
{
@@ -659,6 +684,34 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
/**
+ * dev_pm_opp_find_freq_ceil_indexed() - Search for a rounded ceil freq for the
+ * clock corresponding to the index
+ * @dev: Device for which we do this operation
+ * @freq: Start frequency
+ * @index: Clock index
+ *
+ * Search for the matching ceil *available* OPP for the clock corresponding to
+ * the specified index from a starting freq for a device.
+ *
+ * Return: matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
+ *
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
+ */
+struct dev_pm_opp *
+dev_pm_opp_find_freq_ceil_indexed(struct device *dev, unsigned long *freq,
+ u32 index)
+{
+ return _find_key_ceil(dev, freq, index, true, _read_freq, NULL);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_indexed);
+
+/**
* dev_pm_opp_find_freq_floor() - Search for a rounded floor freq
* @dev: device for which we do this operation
* @freq: Start frequency
@@ -684,6 +737,34 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
/**
+ * dev_pm_opp_find_freq_floor_indexed() - Search for a rounded floor freq for the
+ * clock corresponding to the index
+ * @dev: Device for which we do this operation
+ * @freq: Start frequency
+ * @index: Clock index
+ *
+ * Search for the matching floor *available* OPP for the clock corresponding to
+ * the specified index from a starting freq for a device.
+ *
+ * Return: matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR. Error return
+ * values can be:
+ * EINVAL: for bad pointer
+ * ERANGE: no match found for search
+ * ENODEV: if device not found in list of registered devices
+ *
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
+ */
+struct dev_pm_opp *
+dev_pm_opp_find_freq_floor_indexed(struct device *dev, unsigned long *freq,
+ u32 index)
+{
+ return _find_key_floor(dev, freq, index, true, _read_freq, NULL);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor_indexed);
+
+/**
* dev_pm_opp_find_level_exact() - search for an exact level
* @dev: device for which we do this operation
* @level: level to search for
@@ -2379,7 +2460,7 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
virt_dev = dev_pm_domain_attach_by_name(dev, *name);
if (IS_ERR_OR_NULL(virt_dev)) {
- ret = PTR_ERR(virt_dev) ? : -ENODEV;
+ ret = virt_dev ? PTR_ERR(virt_dev) : -ENODEV;
dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret);
goto err;
}
diff --git a/drivers/opp/cpu.c b/drivers/opp/cpu.c
index 3c3506021501..12c429b407ca 100644
--- a/drivers/opp/cpu.c
+++ b/drivers/opp/cpu.c
@@ -24,7 +24,7 @@
/**
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
* @dev: device for which we do this operation
- * @table: Cpufreq table returned back to caller
+ * @opp_table: Cpufreq table returned back to caller
*
* Generate a cpufreq table for a provided device- this assumes that the
* opp table is already initialized and ready for usage.
@@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
/**
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
* @dev: device for which we do this operation
- * @table: table to free
+ * @opp_table: table to free
*
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
*/
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 2fc3222d2634..9cbcf15527b6 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -100,8 +100,9 @@ config SUPERIO
config CHASSIS_LCD_LED
bool "Chassis LCD and LED support"
+ depends on LEDS_CLASS=y
default y
- select VM_EVENT_COUNTERS
+ select LEDS_TRIGGERS
help
Say Y here if you want to enable support for the Heartbeat,
Disk/Network activities LEDs on some PA-RISC machines,
diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile
index 99fa6a89e0b9..69860a60bb7a 100644
--- a/drivers/parisc/Makefile
+++ b/drivers/parisc/Makefile
@@ -1,25 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
#
-# Makefile for most of the non-PCI devices in PA-RISC machines
+# Makefile PCI and non-PCI devices in PA-RISC machines
+#
+# Keep the order below, e.g.
+# - ccio before any potential subdevices
+# - gsc is required before lasi and wax
+# - asp and wax before the EISA adapters for the IRQ regions
+# - EISA must come before PCI to be sure it gets IRQ region
#
-# I/O SAPIC is also on IA64 platforms.
-# The two could be merged into a common source some day.
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
obj-$(CONFIG_PCI_LBA) += lba_pci.o
obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
obj-$(CONFIG_GSC) += gsc.o
-
-obj-$(CONFIG_HPPB) += hppb.o
-obj-$(CONFIG_GSC_DINO) += dino.o
obj-$(CONFIG_GSC_LASI) += lasi.o asp.o
obj-$(CONFIG_GSC_WAX) += wax.o
obj-$(CONFIG_EISA) += eisa.o eisa_enumerator.o eisa_eeprom.o
+obj-$(CONFIG_HPPB) += hppb.o
+obj-$(CONFIG_GSC_DINO) += dino.o
obj-$(CONFIG_SUPERIO) += superio.o
obj-$(CONFIG_CHASSIS_LCD_LED) += led.o
obj-$(CONFIG_PDC_STABLE) += pdc_stable.o
obj-y += power.o
-
diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c
index f55018e5cc7c..32af8f095781 100644
--- a/drivers/parisc/asp.c
+++ b/drivers/parisc/asp.c
@@ -4,7 +4,7 @@
*
* (c) Copyright 2000 The Puffin Group Inc.
*
- * by Helge Deller <deller@gmx.de>
+ * (c) 2000-2023 by Helge Deller <deller@gmx.de>
*/
#include <linux/errno.h>
@@ -118,9 +118,16 @@ static const struct parisc_device_id asp_tbl[] __initconst = {
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00070 },
{ 0, }
};
+MODULE_DEVICE_TABLE(parisc, asp_tbl);
-struct parisc_driver asp_driver __refdata = {
+static struct parisc_driver asp_driver __refdata = {
.name = "asp",
.id_table = asp_tbl,
.probe = asp_init_chip,
};
+
+static int __init asp_init(void)
+{
+ return register_parisc_driver(&asp_driver);
+}
+arch_initcall(asp_init);
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 9bf652bd002c..509a4072d50a 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -8,18 +8,10 @@
** (c) Copyright 2000 Ryan Bradetich
** (c) Copyright 2000 Hewlett-Packard Company
**
-**
-**
** "Real Mode" operation refers to U2/Uturn chip operation.
** U2/Uturn were designed to perform coherency checks w/o using
** the I/O MMU - basically what x86 does.
**
-** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at:
-** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
-** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
-**
-** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c.
-**
** Drawbacks of using Real Mode are:
** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal).
** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute.
@@ -71,8 +63,6 @@
#undef CCIO_COLLECT_STATS
#endif
-#include <asm/runway.h> /* for proc_runway_root */
-
#ifdef DEBUG_CCIO_INIT
#define DBG_INIT(x...) printk(x)
#else
@@ -1567,10 +1557,15 @@ static int __init ccio_probe(struct parisc_device *dev)
#ifdef CONFIG_PROC_FS
if (ioc_count == 0) {
- proc_create_single(MODULE_NAME, 0, proc_runway_root,
+ struct proc_dir_entry *runway;
+
+ runway = proc_mkdir("bus/runway", NULL);
+ if (runway) {
+ proc_create_single(MODULE_NAME, 0, runway,
ccio_proc_info);
- proc_create_single(MODULE_NAME"-bitmap", 0, proc_runway_root,
+ proc_create_single(MODULE_NAME"-bitmap", 0, runway,
ccio_proc_bitmap_info);
+ }
}
#endif
ioc_count++;
@@ -1582,8 +1577,8 @@ static int __init ccio_probe(struct parisc_device *dev)
*
* Register this driver.
*/
-void __init ccio_init(void)
+static int __init ccio_init(void)
{
- register_parisc_driver(&ccio_driver);
+ return register_parisc_driver(&ccio_driver);
}
-
+arch_initcall(ccio_init);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index f89f9fb4c84b..01a50a051296 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -1084,8 +1084,8 @@ static struct parisc_driver dino_driver __refdata = {
* This is the only routine which is NOT static.
* Must be called exactly once before pci_init().
*/
-void __init dino_init(void)
+static int __init dino_init(void)
{
- register_parisc_driver(&dino_driver);
+ return register_parisc_driver(&dino_driver);
}
-
+arch_initcall(dino_init);
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 45e487388c6e..9eab974e6baf 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -400,10 +400,11 @@ static struct parisc_driver eisa_driver __refdata = {
.probe = eisa_probe,
};
-void __init parisc_eisa_init(void)
+static int __init parisc_eisa_init(void)
{
- register_parisc_driver(&eisa_driver);
+ return register_parisc_driver(&eisa_driver);
}
+arch_initcall(parisc_eisa_init);
static unsigned int eisa_irq_configured;
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index ec175ae99873..a0daaa548bc3 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -258,18 +258,3 @@ int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
return 0;
}
-
-extern struct parisc_driver lasi_driver;
-extern struct parisc_driver asp_driver;
-extern struct parisc_driver wax_driver;
-
-void __init gsc_init(void)
-{
-#ifdef CONFIG_GSC_LASI
- register_parisc_driver(&lasi_driver);
- register_parisc_driver(&asp_driver);
-#endif
-#ifdef CONFIG_GSC_WAX
- register_parisc_driver(&wax_driver);
-#endif
-}
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index e60e68664654..0f9d80384e3d 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -96,9 +96,10 @@ static struct parisc_driver hppb_driver __refdata = {
/**
* hppb_init - HP-PB bus initialization procedure.
*
- * Register this driver.
+ * Register this driver.
*/
-void __init hppb_init(void)
+static int __init hppb_init(void)
{
- register_parisc_driver(&hppb_driver);
+ return register_parisc_driver(&hppb_driver);
}
+arch_initcall(hppb_init);
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index bcc1dae00780..a7df764f1a72 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -348,13 +348,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
}
-
-void __init iosapic_init(void)
+static int __init iosapic_init(void)
{
unsigned long cell = 0;
- DBG("iosapic_init()\n");
-
#ifdef __LP64__
if (is_pdc_pat()) {
int status;
@@ -371,7 +368,10 @@ void __init iosapic_init(void)
irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (irt_num_entry == 0)
irt_cell = NULL; /* old PDC w/o iosapic */
+
+ return 0;
}
+arch_initcall(iosapic_init);
/*
@@ -890,7 +890,7 @@ iosapic_rd_version(struct iosapic_info *isi)
** o allocate and initialize isi_vector[]
** o allocate irq region
*/
-void *iosapic_register(unsigned long hpa)
+void *iosapic_register(unsigned long hpa, void __iomem *vaddr)
{
struct iosapic_info *isi = NULL;
struct irt_entry *irte = irt_cell;
@@ -919,7 +919,7 @@ void *iosapic_register(unsigned long hpa)
return NULL;
}
- isi->addr = ioremap(hpa, 4096);
+ isi->addr = vaddr;
isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index 6ef621adb63a..73c93e9cfa51 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/types.h>
+#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/hardware.h>
@@ -145,23 +146,19 @@ static void __init lasi_led_init(unsigned long lasi_hpa)
* 1 to PWR_ON_L in the Power Control Register
*
*/
-
-static unsigned long lasi_power_off_hpa __read_mostly;
-
-static void lasi_power_off(void)
+static int lasi_power_off(struct sys_off_data *data)
{
- unsigned long datareg;
+ struct gsc_asic *lasi = data->cb_data;
- /* calculate addr of the Power Control Register */
- datareg = lasi_power_off_hpa + 0x0000C000;
+ /* Power down the machine via Power Control Register */
+ gsc_writel(0x02, lasi->hpa + 0x0000C000);
- /* Power down the machine */
- gsc_writel(0x02, datareg);
+ /* might not be reached: */
+ return NOTIFY_DONE;
}
static int __init lasi_init_chip(struct parisc_device *dev)
{
- extern void (*chassis_power_off)(void);
struct gsc_asic *lasi;
int ret;
@@ -212,13 +209,10 @@ static int __init lasi_init_chip(struct parisc_device *dev)
gsc_fixup_irqs(dev, lasi, lasi_choose_irq);
- /* initialize the power off function */
- /* FIXME: Record the LASI HPA for the power off function. This should
- * ensure that only the first LASI (the one controlling the power off)
- * should set the HPA here */
- lasi_power_off_hpa = lasi->hpa;
- chassis_power_off = lasi_power_off;
-
+ /* register the LASI power off function */
+ register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_DEFAULT, lasi_power_off, lasi);
+
return ret;
}
@@ -226,9 +220,16 @@ static struct parisc_device_id lasi_tbl[] __initdata = {
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00081 },
{ 0, }
};
+MODULE_DEVICE_TABLE(parisc, lasi_tbl);
-struct parisc_driver lasi_driver __refdata = {
+static struct parisc_driver lasi_driver __refdata = {
.name = "lasi",
.id_table = lasi_tbl,
.probe = lasi_init_chip,
};
+
+static int __init lasi_init(void)
+{
+ return register_parisc_driver(&lasi_driver);
+}
+arch_initcall(lasi_init);
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 702bfd64e6e1..3fc3765fddaa 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1535,7 +1535,8 @@ lba_driver_probe(struct parisc_device *dev)
}
/* Tell I/O SAPIC driver we have a IRQ handler/region. */
- tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE);
+ tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE,
+ addr + LBA_IOSAPIC_BASE);
/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
** have an IRT entry will get NULL back from iosapic code.
@@ -1681,10 +1682,11 @@ static struct parisc_driver lba_driver __refdata = {
** One time initialization to let the world know the LBA was found.
** Must be called exactly once before pci_init().
*/
-void __init lba_init(void)
+static int __init lba_init(void)
{
- register_parisc_driver(&lba_driver);
+ return register_parisc_driver(&lba_driver);
}
+arch_initcall(lba_init);
/*
** Initialize the IBASE/IMASK registers for LBA (Elroy).
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 8bdc5e043831..1f75d2416001 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -1,77 +1,46 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Chassis LCD/LED driver for HP-PARISC workstations
+ * Chassis LCD/LED driver for HP-PARISC workstations
*
- * (c) Copyright 2000 Red Hat Software
- * (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
- * (c) Copyright 2001-2009 Helge Deller <deller@gmx.de>
- * (c) Copyright 2001 Randolph Chung <tausq@debian.org>
+ * (c) Copyright 2000 Red Hat Software
+ * (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ * (c) Copyright 2001 Randolph Chung <tausq@debian.org>
+ * (c) Copyright 2000-2023 Helge Deller <deller@gmx.de>
*
- * TODO:
- * - speed-up calculations with inlined assembler
- * - interface to write to second row of LCD from /proc (if technically possible)
+ * The control of the LEDs and LCDs on PARISC machines has to be done
+ * completely in software.
*
- * Changes:
- * - Audit copy_from_user in led_proc_write.
- * Daniele Bellucci <bellucda@tiscali.it>
- * - Switch from using a tasklet to a work queue, so the led_LCD_driver
- * can sleep.
- * David Pye <dmp@davidmpye.dyndns.org>
+ * The LEDs can be configured at runtime in /sys/class/leds/
*/
#include <linux/module.h>
-#include <linux/stddef.h> /* for offsetof() */
#include <linux/init.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/utsname.h>
#include <linux/capability.h>
#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
#include <linux/reboot.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/ctype.h>
-#include <linux/blkdev.h>
-#include <linux/workqueue.h>
-#include <linux/rcupdate.h>
+#include <linux/uaccess.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/hardware.h>
#include <asm/param.h> /* HZ */
#include <asm/led.h>
#include <asm/pdc.h>
-#include <linux/uaccess.h>
-
-/* The control of the LEDs and LCDs on PARISC-machines have to be done
- completely in software. The necessary calculations are done in a work queue
- task which is scheduled regularly, and since the calculations may consume a
- relatively large amount of CPU time, some of the calculations can be
- turned off with the following variables (controlled via procfs) */
-static int led_type __read_mostly = -1;
-static unsigned char lastleds; /* LED state from most recent update */
-static unsigned int led_heartbeat __read_mostly = 1;
-static unsigned int led_diskio __read_mostly = 1;
-static unsigned int led_lanrxtx __read_mostly = 1;
-static char lcd_text[32] __read_mostly;
-static char lcd_text_default[32] __read_mostly;
-static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */
+#define LED_HAS_LCD 1
+#define LED_HAS_LED 2
-
-static struct workqueue_struct *led_wq;
-static void led_work_func(struct work_struct *);
-static DECLARE_DELAYED_WORK(led_task, led_work_func);
-
-#if 0
-#define DPRINTK(x) printk x
-#else
-#define DPRINTK(x)
-#endif
+static unsigned char led_type; /* bitmask of LED_HAS_XXX */
+static unsigned char lastleds; /* LED state from most recent update */
+static unsigned char lcd_new_text;
+static unsigned char lcd_text[20];
+static unsigned char lcd_text_default[20];
+static unsigned char lcd_no_led_support; /* KittyHawk doesn't support LED on its LCD */
struct lcd_block {
unsigned char command; /* stores the command byte */
@@ -80,7 +49,7 @@ struct lcd_block {
};
/* Structure returned by PDC_RETURN_CHASSIS_INFO */
-/* NOTE: we use unsigned long:16 two times, since the following member
+/* NOTE: we use unsigned long:16 two times, since the following member
lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */
struct pdc_chassis_lcd_info_ret_block {
unsigned long model:16; /* DISPLAY_MODEL_XXXX */
@@ -100,15 +69,15 @@ struct pdc_chassis_lcd_info_ret_block {
/* LCD_CMD and LCD_DATA for KittyHawk machines */
-#define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL) /* 64bit-ready */
-#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
+#define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL)
+#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1)
-/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's
+/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's
* HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */
static struct pdc_chassis_lcd_info_ret_block
-lcd_info __attribute__((aligned(8))) __read_mostly =
+lcd_info __attribute__((aligned(8))) =
{
- .model = DISPLAY_MODEL_LCD,
+ .model = DISPLAY_MODEL_NONE,
.lcd_width = 16,
.lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD,
.lcd_data_reg_addr = KITTYHAWK_LCD_DATA,
@@ -117,165 +86,65 @@ lcd_info __attribute__((aligned(8))) __read_mostly =
.reset_cmd2 = 0xc0,
};
-
/* direct access to some of the lcd_info variables */
-#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr
-#define LCD_DATA_REG lcd_info.lcd_data_reg_addr
+#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr
+#define LCD_DATA_REG lcd_info.lcd_data_reg_addr
#define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */
-#define LED_HASLCD 1
-#define LED_NOLCD 0
-
-/* The workqueue must be created at init-time */
-static int start_task(void)
-{
- /* Display the default text now */
- if (led_type == LED_HASLCD) lcd_print( lcd_text_default );
-
- /* KittyHawk has no LED support on its LCD */
- if (lcd_no_led_support) return 0;
-
- /* Create the work queue and queue the LED task */
- led_wq = create_singlethread_workqueue("led_wq");
- if (!led_wq)
- return -ENOMEM;
-
- queue_delayed_work(led_wq, &led_task, 0);
-
- return 0;
-}
-
-device_initcall(start_task);
-
/* ptr to LCD/LED-specific function */
-static void (*led_func_ptr) (unsigned char) __read_mostly;
-
-#ifdef CONFIG_PROC_FS
-static int led_proc_show(struct seq_file *m, void *v)
-{
- switch ((long)m->private)
- {
- case LED_NOLCD:
- seq_printf(m, "Heartbeat: %d\n", led_heartbeat);
- seq_printf(m, "Disk IO: %d\n", led_diskio);
- seq_printf(m, "LAN Rx/Tx: %d\n", led_lanrxtx);
- break;
- case LED_HASLCD:
- seq_printf(m, "%s\n", lcd_text);
- break;
- default:
- return 0;
- }
- return 0;
-}
-
-static int led_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, led_proc_show, pde_data(inode));
-}
+static void (*led_func_ptr) (unsigned char);
-static ssize_t led_proc_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
+static void lcd_print_now(void)
{
- void *data = pde_data(file_inode(file));
- char *cur, lbuf[32];
- int d;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (count >= sizeof(lbuf))
- count = sizeof(lbuf)-1;
-
- if (copy_from_user(lbuf, buf, count))
- return -EFAULT;
- lbuf[count] = 0;
-
- cur = lbuf;
-
- switch ((long)data)
- {
- case LED_NOLCD:
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_heartbeat = d;
-
- if (*cur++ != ' ') goto parse_error;
+ int i;
+ char *str = lcd_text;
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_diskio = d;
+ if (lcd_info.model != DISPLAY_MODEL_LCD)
+ return;
- if (*cur++ != ' ') goto parse_error;
+ if (!lcd_new_text)
+ return;
+ lcd_new_text = 0;
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_lanrxtx = d;
+ /* Set LCD Cursor to 1st character */
+ gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
+ udelay(lcd_info.min_cmd_delay);
- break;
- case LED_HASLCD:
- if (*cur && cur[strlen(cur)-1] == '\n')
- cur[strlen(cur)-1] = 0;
- if (*cur == 0)
- cur = lcd_text_default;
- lcd_print(cur);
- break;
- default:
- return 0;
+ /* Print the string */
+ for (i = 0; i < lcd_info.lcd_width; i++) {
+ gsc_writeb(*str ? *str++ : ' ', LCD_DATA_REG);
+ udelay(lcd_info.min_cmd_delay);
}
-
- return count;
-
-parse_error:
- if ((long)data == LED_NOLCD)
- printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");
- return -EINVAL;
}
-static const struct proc_ops led_proc_ops = {
- .proc_open = led_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
- .proc_write = led_proc_write,
-};
-
-static int __init led_create_procfs(void)
+/**
+ * lcd_print()
+ *
+ * @str: string to show on the LCD. If NULL, print current string again.
+ *
+ * Displays the given string on the LCD-Display of newer machines.
+ */
+void lcd_print(const char *str)
{
- struct proc_dir_entry *proc_pdc_root = NULL;
- struct proc_dir_entry *ent;
-
- if (led_type == -1) return -1;
-
- proc_pdc_root = proc_mkdir("pdc", NULL);
- if (!proc_pdc_root) return -1;
-
- if (!lcd_no_led_support)
- {
- ent = proc_create_data("led", 0644, proc_pdc_root,
- &led_proc_ops, (void *)LED_NOLCD); /* LED */
- if (!ent) return -1;
- }
-
- if (led_type == LED_HASLCD)
- {
- ent = proc_create_data("lcd", 0644, proc_pdc_root,
- &led_proc_ops, (void *)LED_HASLCD); /* LCD */
- if (!ent) return -1;
- }
+ /* copy display string to buffer for procfs */
+ if (str)
+ strscpy(lcd_text, str, sizeof(lcd_text));
+ lcd_new_text = 1;
- return 0;
+ /* print now if LCD without any LEDs */
+ if (led_type == LED_HAS_LCD)
+ lcd_print_now();
}
-#endif
-/*
- **
- ** led_ASP_driver()
- **
- */
#define LED_DATA 0x01 /* data to shift (0:on 1:off) */
#define LED_STROBE 0x02 /* strobe to clock data */
+
+/**
+ * led_ASP_driver() - LED driver for the ASP controller chip
+ *
+ * @leds: bitmap representing the LED status
+ */
static void led_ASP_driver(unsigned char leds)
{
int i;
@@ -290,11 +159,10 @@ static void led_ASP_driver(unsigned char leds)
}
}
-
-/*
- **
- ** led_LASI_driver()
- **
+/**
+ * led_LASI_driver() - LED driver for the LASI controller chip
+ *
+ * @leds: bitmap representing the LED status
*/
static void led_LASI_driver(unsigned char leds)
{
@@ -302,395 +170,298 @@ static void led_LASI_driver(unsigned char leds)
gsc_writeb( leds, LED_DATA_REG );
}
-
-/*
- **
- ** led_LCD_driver()
- **
+/**
+ * led_LCD_driver() - LED & LCD driver for LCD chips
+ *
+ * @leds: bitmap representing the LED status
*/
static void led_LCD_driver(unsigned char leds)
{
- static int i;
- static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO,
+ static const unsigned char mask[4] = {
+ LED_HEARTBEAT, LED_DISK_IO,
LED_LAN_RCV, LED_LAN_TX };
-
- static struct lcd_block * blockp[4] = {
+
+ static struct lcd_block * const blockp[4] = {
&lcd_info.heartbeat,
&lcd_info.disk_io,
&lcd_info.lan_rcv,
&lcd_info.lan_tx
};
+ static unsigned char latest_leds;
+ int i;
- /* Convert min_cmd_delay to milliseconds */
- unsigned int msec_cmd_delay = 1 + (lcd_info.min_cmd_delay / 1000);
-
- for (i=0; i<4; ++i)
- {
- if ((leds & mask[i]) != (lastleds & mask[i]))
- {
- gsc_writeb( blockp[i]->command, LCD_CMD_REG );
- msleep(msec_cmd_delay);
-
- gsc_writeb( leds & mask[i] ? blockp[i]->on :
- blockp[i]->off, LCD_DATA_REG );
- msleep(msec_cmd_delay);
- }
+ for (i = 0; i < 4; ++i) {
+ if ((leds & mask[i]) == (latest_leds & mask[i]))
+ continue;
+
+ gsc_writeb( blockp[i]->command, LCD_CMD_REG );
+ udelay(lcd_info.min_cmd_delay);
+
+ gsc_writeb( leds & mask[i] ? blockp[i]->on :
+ blockp[i]->off, LCD_DATA_REG );
+ udelay(lcd_info.min_cmd_delay);
}
+ latest_leds = leds;
+
+ lcd_print_now();
}
-/*
- **
- ** led_get_net_activity()
- **
- ** calculate if there was TX- or RX-throughput on the network interfaces
- ** (analog to dev_get_info() from net/core/dev.c)
- **
+/**
+ * lcd_system_halt()
+ *
+ * @nb: pointer to the notifier_block structure
+ * @event: the event (SYS_RESTART, SYS_HALT or SYS_POWER_OFF)
+ * @buf: pointer to a buffer (not used)
+ *
+ * Called by the reboot notifier chain at shutdown. Stops all
+ * LED/LCD activities.
*/
-static __inline__ int led_get_net_activity(void)
-{
-#ifndef CONFIG_NET
- return 0;
-#else
- static u64 rx_total_last, tx_total_last;
- u64 rx_total, tx_total;
- struct net_device *dev;
- int retval;
-
- rx_total = tx_total = 0;
-
- /* we are running as a workqueue task, so we can use an RCU lookup */
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- const struct rtnl_link_stats64 *stats;
- struct rtnl_link_stats64 temp;
- struct in_device *in_dev = __in_dev_get_rcu(dev);
- if (!in_dev || !in_dev->ifa_list)
- continue;
- if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
- continue;
- stats = dev_get_stats(dev, &temp);
- rx_total += stats->rx_packets;
- tx_total += stats->tx_packets;
- }
- rcu_read_unlock();
-
- retval = 0;
+static int lcd_system_halt(struct notifier_block *nb, unsigned long event, void *buf)
+{
+ const char *txt;
- if (rx_total != rx_total_last) {
- rx_total_last = rx_total;
- retval |= LED_LAN_RCV;
+ switch (event) {
+ case SYS_RESTART: txt = "SYSTEM RESTART";
+ break;
+ case SYS_HALT: txt = "SYSTEM HALT";
+ break;
+ case SYS_POWER_OFF: txt = "SYSTEM POWER OFF";
+ break;
+ default: return NOTIFY_DONE;
}
- if (tx_total != tx_total_last) {
- tx_total_last = tx_total;
- retval |= LED_LAN_TX;
- }
+ lcd_print(txt);
- return retval;
-#endif
+ return NOTIFY_OK;
}
+static struct notifier_block lcd_system_halt_notifier = {
+ .notifier_call = lcd_system_halt,
+};
-/*
- **
- ** led_get_diskio_activity()
- **
- ** calculate if there was disk-io in the system
- **
- */
-static __inline__ int led_get_diskio_activity(void)
-{
- static unsigned long last_pgpgin, last_pgpgout;
- unsigned long events[NR_VM_EVENT_ITEMS];
- int changed;
-
- all_vm_events(events);
-
- /* Just use a very simple calculation here. Do not care about overflow,
- since we only want to know if there was activity or not. */
- changed = (events[PGPGIN] != last_pgpgin) ||
- (events[PGPGOUT] != last_pgpgout);
- last_pgpgin = events[PGPGIN];
- last_pgpgout = events[PGPGOUT];
-
- return (changed ? LED_DISK_IO : 0);
-}
-
+static void set_led(struct led_classdev *led_cdev, enum led_brightness brightness);
+struct hppa_led {
+ struct led_classdev led_cdev;
+ unsigned char led_bit;
+};
+#define to_hppa_led(d) container_of(d, struct hppa_led, led_cdev)
-/*
- ** led_work_func()
- **
- ** manages when and which chassis LCD/LED gets updated
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+ const char *name;
+ set_handler handler;
+ const char *default_trigger;
+};
- TODO:
- - display load average (older machines like 715/64 have 4 "free" LED's for that)
- - optimizations
- */
+#define NUM_LEDS_PER_BOARD 8
+struct hppa_drvdata {
+ struct hppa_led leds[NUM_LEDS_PER_BOARD];
+};
-#define HEARTBEAT_LEN (HZ*10/100)
-#define HEARTBEAT_2ND_RANGE_START (HZ*28/100)
-#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
+static void set_led(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ struct hppa_led *p = to_hppa_led(led_cdev);
+ unsigned char led_bit = p->led_bit;
-#define LED_UPDATE_INTERVAL (1 + (HZ*19/1000))
+ if (brightness == LED_OFF)
+ lastleds &= ~led_bit;
+ else
+ lastleds |= led_bit;
-static void led_work_func (struct work_struct *unused)
-{
- static unsigned long last_jiffies;
- static unsigned long count_HZ; /* counter in range 0..HZ */
- unsigned char currentleds = 0; /* stores current value of the LEDs */
+ if (led_func_ptr)
+ led_func_ptr(lastleds);
+}
- /* exit if not initialized */
- if (!led_func_ptr)
- return;
- /* increment the heartbeat timekeeper */
- count_HZ += jiffies - last_jiffies;
- last_jiffies = jiffies;
- if (count_HZ >= HZ)
- count_HZ = 0;
+static int hppa_led_generic_probe(struct platform_device *pdev,
+ struct led_type *types)
+{
+ struct hppa_drvdata *p;
+ int i, err;
- if (likely(led_heartbeat))
- {
- /* flash heartbeat-LED like a real heart
- * (2 x short then a long delay)
- */
- if (count_HZ < HEARTBEAT_LEN ||
- (count_HZ >= HEARTBEAT_2ND_RANGE_START &&
- count_HZ < HEARTBEAT_2ND_RANGE_END))
- currentleds |= LED_HEARTBEAT;
- }
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
- if (likely(led_lanrxtx)) currentleds |= led_get_net_activity();
- if (likely(led_diskio)) currentleds |= led_get_diskio_activity();
-
- /* blink LEDs if we got an Oops (HPMC) */
- if (unlikely(oops_in_progress)) {
- if (boot_cpu_data.cpu_type >= pcxl2) {
- /* newer machines don't have loadavg. LEDs, so we
- * let all LEDs blink twice per second instead */
- currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff;
- } else {
- /* old machines: blink loadavg. LEDs twice per second */
- if (count_HZ <= (HZ/2))
- currentleds &= ~(LED4|LED5|LED6|LED7);
- else
- currentleds |= (LED4|LED5|LED6|LED7);
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+ struct led_classdev *lp = &p->leds[i].led_cdev;
+
+ p->leds[i].led_bit = BIT(i);
+ lp->name = types[i].name;
+ lp->brightness = LED_FULL;
+ lp->brightness_set = types[i].handler;
+ lp->default_trigger = types[i].default_trigger;
+ err = led_classdev_register(&pdev->dev, lp);
+ if (err) {
+ dev_err(&pdev->dev, "Could not register %s LED\n",
+ lp->name);
+ for (i--; i >= 0; i--)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+ return err;
}
}
- if (currentleds != lastleds)
- {
- led_func_ptr(currentleds); /* Update the LCD/LEDs */
- lastleds = currentleds;
- }
+ platform_set_drvdata(pdev, p);
- queue_delayed_work(led_wq, &led_task, LED_UPDATE_INTERVAL);
+ return 0;
}
-/*
- ** led_halt()
- **
- ** called by the reboot notifier chain at shutdown and stops all
- ** LED/LCD activities.
- **
- */
+static int platform_led_remove(struct platform_device *pdev)
+{
+ struct hppa_drvdata *p = platform_get_drvdata(pdev);
+ int i;
-static int led_halt(struct notifier_block *, unsigned long, void *);
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+ led_classdev_unregister(&p->leds[i].led_cdev);
-static struct notifier_block led_notifier = {
- .notifier_call = led_halt,
+ return 0;
+}
+
+static struct led_type mainboard_led_types[NUM_LEDS_PER_BOARD] = {
+ {
+ .name = "platform-lan-tx",
+ .handler = set_led,
+ .default_trigger = "tx",
+ },
+ {
+ .name = "platform-lan-rx",
+ .handler = set_led,
+ .default_trigger = "rx",
+ },
+ {
+ .name = "platform-disk",
+ .handler = set_led,
+ .default_trigger = "disk-activity",
+ },
+ {
+ .name = "platform-heartbeat",
+ .handler = set_led,
+ .default_trigger = "heartbeat",
+ },
+ {
+ .name = "platform-LED4",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED5",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED6",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED7",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
};
-static int notifier_disabled = 0;
-static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
+static int platform_led_probe(struct platform_device *pdev)
{
- char *txt;
+ return hppa_led_generic_probe(pdev, mainboard_led_types);
+}
- if (notifier_disabled)
- return NOTIFY_OK;
+MODULE_ALIAS("platform:platform-leds");
- notifier_disabled = 1;
- switch (event) {
- case SYS_RESTART: txt = "SYSTEM RESTART";
- break;
- case SYS_HALT: txt = "SYSTEM HALT";
- break;
- case SYS_POWER_OFF: txt = "SYSTEM POWER OFF";
- break;
- default: return NOTIFY_DONE;
- }
-
- /* Cancel the work item and delete the queue */
- if (led_wq) {
- cancel_delayed_work_sync(&led_task);
- destroy_workqueue(led_wq);
- led_wq = NULL;
- }
-
- if (lcd_info.model == DISPLAY_MODEL_LCD)
- lcd_print(txt);
- else
- if (led_func_ptr)
- led_func_ptr(0xff); /* turn all LEDs ON */
-
- return NOTIFY_OK;
-}
+static struct platform_driver hppa_mainboard_led_driver = {
+ .probe = platform_led_probe,
+ .remove = platform_led_remove,
+ .driver = {
+ .name = "platform-leds",
+ },
+};
-/*
- ** register_led_driver()
- **
- ** registers an external LED or LCD for usage by this driver.
- ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported.
- **
- */
+static struct platform_driver * const drivers[] = {
+ &hppa_mainboard_led_driver,
+};
+static struct platform_device platform_leds = {
+ .name = "platform-leds",
+};
+
+/**
+ * register_led_driver()
+ *
+ * @model: model type, one of the DISPLAY_MODEL_XXXX values
+ * @cmd_reg: physical address of cmd register for the LED/LCD
+ * @data_reg: physical address of data register for the LED/LCD
+ *
+ * Registers a chassis LED or LCD which should be driven by this driver.
+ * Only PDC-based, LASI- or ASP-style LEDs and LCDs are supported.
+ */
int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg)
{
- static int initialized;
-
- if (initialized || !data_reg)
+ if (led_func_ptr || !data_reg)
+ return 1;
+
+ /* No LEDs when running in QEMU */
+ if (running_on_qemu)
return 1;
-
+
lcd_info.model = model; /* store the values */
LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? 0 : cmd_reg;
switch (lcd_info.model) {
case DISPLAY_MODEL_LCD:
LCD_DATA_REG = data_reg;
- printk(KERN_INFO "LCD display at %lx,%lx registered\n",
+ pr_info("led: LCD display at %#lx and %#lx\n",
LCD_CMD_REG , LCD_DATA_REG);
led_func_ptr = led_LCD_driver;
- led_type = LED_HASLCD;
+ if (lcd_no_led_support)
+ led_type = LED_HAS_LCD;
+ else
+ led_type = LED_HAS_LCD | LED_HAS_LED;
break;
case DISPLAY_MODEL_LASI:
- /* Skip to register LED in QEMU */
- if (running_on_qemu)
- return 1;
LED_DATA_REG = data_reg;
led_func_ptr = led_LASI_driver;
- printk(KERN_INFO "LED display at %lx registered\n", LED_DATA_REG);
- led_type = LED_NOLCD;
+ pr_info("led: LED display at %#lx\n", LED_DATA_REG);
+ led_type = LED_HAS_LED;
break;
case DISPLAY_MODEL_OLD_ASP:
LED_DATA_REG = data_reg;
led_func_ptr = led_ASP_driver;
- printk(KERN_INFO "LED (ASP-style) display at %lx registered\n",
+ pr_info("led: LED (ASP-style) display at %#lx\n",
LED_DATA_REG);
- led_type = LED_NOLCD;
+ led_type = LED_HAS_LED;
break;
default:
- printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
- __func__, lcd_info.model);
+ pr_err("led: Unknown LCD/LED model type %d\n", lcd_info.model);
return 1;
}
-
- /* mark the LCD/LED driver now as initialized and
- * register to the reboot notifier chain */
- initialized++;
- register_reboot_notifier(&led_notifier);
-
- /* Ensure the work is queued */
- if (led_wq) {
- queue_delayed_work(led_wq, &led_task, 0);
- }
- return 0;
-}
-
-/*
- ** register_led_regions()
- **
- ** register_led_regions() registers the LCD/LED regions for /procfs.
- ** At bootup - where the initialisation of the LCD/LED normally happens -
- ** not all internal structures of request_region() are properly set up,
- ** so that we delay the led-registration until after busdevices_init()
- ** has been executed.
- **
- */
+ platform_register_drivers(drivers, ARRAY_SIZE(drivers));
-void __init register_led_regions(void)
-{
- switch (lcd_info.model) {
- case DISPLAY_MODEL_LCD:
- request_mem_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd");
- request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
- break;
- case DISPLAY_MODEL_LASI:
- case DISPLAY_MODEL_OLD_ASP:
- request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
- break;
- }
-}
-
-
-/*
- **
- ** lcd_print()
- **
- ** Displays the given string on the LCD-Display of newer machines.
- ** lcd_print() disables/enables the timer-based led work queue to
- ** avoid a race condition while writing the CMD/DATA register pair.
- **
- */
-int lcd_print( const char *str )
-{
- int i;
-
- if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
- return 0;
-
- /* temporarily disable the led work task */
- if (led_wq)
- cancel_delayed_work_sync(&led_task);
-
- /* copy display string to buffer for procfs */
- strscpy(lcd_text, str, sizeof(lcd_text));
-
- /* Set LCD Cursor to 1st character */
- gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
- udelay(lcd_info.min_cmd_delay);
-
- /* Print the string */
- for (i=0; i < lcd_info.lcd_width; i++) {
- if (str && *str)
- gsc_writeb(*str++, LCD_DATA_REG);
- else
- gsc_writeb(' ', LCD_DATA_REG);
- udelay(lcd_info.min_cmd_delay);
- }
-
- /* re-queue the work */
- if (led_wq) {
- queue_delayed_work(led_wq, &led_task, 0);
- }
-
- return lcd_info.lcd_width;
+ return register_reboot_notifier(&lcd_system_halt_notifier);
}
-/*
- ** led_init()
- **
- ** led_init() is called very early in the bootup-process from setup.c
- ** and asks the PDC for an usable chassis LCD or LED.
- ** If the PDC doesn't return any info, then the LED
- ** is detected by lasi.c or asp.c and registered with the
- ** above functions lasi_led_init() or asp_led_init().
- ** KittyHawk machines have often a buggy PDC, so that
- ** we explicitly check for those machines here.
+/**
+ * early_led_init()
+ *
+ * early_led_init() is called early in the bootup-process and asks the
+ * PDC for an usable chassis LCD or LED. If the PDC doesn't return any
+ * info, then a LED might be detected by the LASI or ASP drivers later.
+ * KittyHawk machines have often a buggy PDC, so that we explicitly check
+ * for those machines here.
*/
-
-int __init led_init(void)
+static int __init early_led_init(void)
{
struct pdc_chassis_info chassis_info;
int ret;
snprintf(lcd_text_default, sizeof(lcd_text_default),
"Linux %s", init_utsname()->release);
+ strcpy(lcd_text, lcd_text_default);
+ lcd_new_text = 1;
/* Work around the buggy PDC of KittyHawk-machines */
switch (CPU_HVERSION) {
@@ -699,82 +470,86 @@ int __init led_init(void)
case 0x582: /* KittyHawk DC3 100 (K400) */
case 0x583: /* KittyHawk DC3 120 (K410) */
case 0x58B: /* KittyHawk DC2 100 (K200) */
- printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
- "LED detection skipped.\n", __FILE__, CPU_HVERSION);
+ pr_info("LCD on KittyHawk-Machine found.\n");
+ lcd_info.model = DISPLAY_MODEL_LCD;
+ /* KittyHawk has no LED support on its LCD, so skip LED detection */
lcd_no_led_support = 1;
goto found; /* use the preinitialized values of lcd_info */
}
/* initialize the struct, so that we can check for valid return values */
- lcd_info.model = DISPLAY_MODEL_NONE;
chassis_info.actcnt = chassis_info.maxcnt = 0;
ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info));
- if (ret == PDC_OK) {
- DPRINTK((KERN_INFO "%s: chassis info: model=%d (%s), "
- "lcd_width=%d, cmd_delay=%u,\n"
- "%s: sizecnt=%d, actcnt=%ld, maxcnt=%ld\n",
- __FILE__, lcd_info.model,
- (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" :
- (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown",
- lcd_info.lcd_width, lcd_info.min_cmd_delay,
- __FILE__, sizeof(lcd_info),
- chassis_info.actcnt, chassis_info.maxcnt));
- DPRINTK((KERN_INFO "%s: cmd=%p, data=%p, reset1=%x, reset2=%x, act_enable=%d\n",
- __FILE__, lcd_info.lcd_cmd_reg_addr,
- lcd_info.lcd_data_reg_addr, lcd_info.reset_cmd1,
- lcd_info.reset_cmd2, lcd_info.act_enable ));
-
- /* check the results. Some machines have a buggy PDC */
- if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
- goto not_found;
+ if (ret != PDC_OK) {
+not_found:
+ lcd_info.model = DISPLAY_MODEL_NONE;
+ return 1;
+ }
- switch (lcd_info.model) {
- case DISPLAY_MODEL_LCD: /* LCD display */
- if (chassis_info.actcnt <
- offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
- goto not_found;
- if (!lcd_info.act_enable) {
- DPRINTK((KERN_INFO "PDC prohibited usage of the LCD.\n"));
- goto not_found;
- }
- break;
-
- case DISPLAY_MODEL_NONE: /* no LED or LCD available */
- printk(KERN_INFO "PDC reported no LCD or LED.\n");
+ /* check the results. Some machines have a buggy PDC */
+ if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
+ goto not_found;
+
+ switch (lcd_info.model) {
+ case DISPLAY_MODEL_LCD: /* LCD display */
+ if (chassis_info.actcnt <
+ offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
goto not_found;
+ if (!lcd_info.act_enable) {
+ /* PDC tells LCD should not be used. */
+ goto not_found;
+ }
+ break;
- case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */
- if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
- goto not_found;
- break;
+ case DISPLAY_MODEL_NONE: /* no LED or LCD available */
+ goto not_found;
- default:
- printk(KERN_WARNING "PDC reported unknown LCD/LED model %d\n",
- lcd_info.model);
+ case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */
+ if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
goto not_found;
- } /* switch() */
-
-found:
- /* register the LCD/LED driver */
- register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
- return 0;
+ break;
- } else { /* if() */
- DPRINTK((KERN_INFO "pdc_chassis_info call failed with retval = %d\n", ret));
+ default:
+ pr_warn("PDC reported unknown LCD/LED model %d\n",
+ lcd_info.model);
+ goto not_found;
}
-not_found:
- lcd_info.model = DISPLAY_MODEL_NONE;
- return 1;
+found:
+ /* register the LCD/LED driver */
+ return register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
}
+arch_initcall(early_led_init);
-static void __exit led_exit(void)
+/**
+ * register_led_regions()
+ *
+ * Register_led_regions() registers the LCD/LED regions for /procfs.
+ * At bootup - where the initialisation of the LCD/LED often happens
+ * not all internal structures of request_region() are properly set up,
+ * so that we delay the led-registration until after busdevices_init()
+ * has been executed.
+ */
+static void __init register_led_regions(void)
{
- unregister_reboot_notifier(&led_notifier);
- return;
+ switch (lcd_info.model) {
+ case DISPLAY_MODEL_LCD:
+ request_mem_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd");
+ request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
+ break;
+ case DISPLAY_MODEL_LASI:
+ case DISPLAY_MODEL_OLD_ASP:
+ request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
+ break;
+ }
}
-#ifdef CONFIG_PROC_FS
-module_init(led_create_procfs)
-#endif
+static int __init startup_leds(void)
+{
+ if (platform_device_register(&platform_leds))
+ printk(KERN_INFO "LED: failed to register LEDs\n");
+ register_led_regions();
+ return 0;
+}
+device_initcall(startup_leds);
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 8b1dcd537020..f6b510675318 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -121,7 +121,7 @@ module_param(sba_reserve_agpgart, int, 0444);
MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
#endif
-struct proc_dir_entry *proc_runway_root __ro_after_init;
+static struct proc_dir_entry *proc_runway_root __ro_after_init;
struct proc_dir_entry *proc_mckinley_root __ro_after_init;
/************************************
@@ -1994,10 +1994,11 @@ static int __init sba_driver_callback(struct parisc_device *dev)
** This is the only routine which is NOT static.
** Must be called exactly once before pci_init().
*/
-void __init sba_init(void)
+static int __init sba_init(void)
{
- register_parisc_driver(&sba_driver);
+ return register_parisc_driver(&sba_driver);
}
+arch_initcall(sba_init);
/**
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
index 73a2b01f8d9c..834dbe9a767b 100644
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -4,7 +4,7 @@
*
* (c) Copyright 2000 The Puffin Group Inc.
*
- * by Helge Deller <deller@gmx.de>
+ * (c) 2000-2023 by Helge Deller <deller@gmx.de>
*/
#include <linux/errno.h>
@@ -121,14 +121,20 @@ static int __init wax_init_chip(struct parisc_device *dev)
}
static const struct parisc_device_id wax_tbl[] __initconst = {
- { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e },
+ { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e },
{ 0, }
};
MODULE_DEVICE_TABLE(parisc, wax_tbl);
-struct parisc_driver wax_driver __refdata = {
+static struct parisc_driver wax_driver __refdata = {
.name = "wax",
.id_table = wax_tbl,
.probe = wax_init_chip,
};
+
+static int __init wax_init(void)
+{
+ return register_parisc_driver(&wax_driver);
+}
+arch_initcall(wax_init);
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 83c0ab50676d..11636634ae51 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -22,7 +22,6 @@
#include <linux/bitops.h>
#include <linux/time.h>
#include <linux/ktime.h>
-#include <linux/swiotlb.h>
#include <xen/platform_pci.h>
#include <asm/xen/swiotlb-xen.h>
@@ -669,11 +668,6 @@ static int pcifront_connect_and_init_dma(struct pcifront_device *pdev)
spin_unlock(&pcifront_dev_lock);
- if (!err && !is_swiotlb_active(&pdev->xdev->dev)) {
- err = pci_xen_swiotlb_init_late();
- if (err)
- dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n");
- }
return err;
}
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index f4572a5cca72..273d67ecf6d2 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -92,7 +92,7 @@ config ARM_PMU_ACPI
config ARM_SMMU_V3_PMU
tristate "ARM SMMUv3 Performance Monitors Extension"
- depends on (ARM64 && ACPI) || (COMPILE_TEST && 64BIT)
+ depends on ARM64 || (COMPILE_TEST && 64BIT)
depends on GENERIC_MSI_IRQ
help
Provides support for the ARM SMMUv3 Performance Monitor Counter
diff --git a/drivers/perf/alibaba_uncore_drw_pmu.c b/drivers/perf/alibaba_uncore_drw_pmu.c
index 5c5be9fc1b15..19d459a36be5 100644
--- a/drivers/perf/alibaba_uncore_drw_pmu.c
+++ b/drivers/perf/alibaba_uncore_drw_pmu.c
@@ -236,10 +236,37 @@ static const struct attribute_group ali_drw_pmu_cpumask_attr_group = {
.attrs = ali_drw_pmu_cpumask_attrs,
};
+static ssize_t ali_drw_pmu_identifier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ return sysfs_emit(page, "%s\n", "ali_drw_pmu");
+}
+
+static umode_t ali_drw_pmu_identifier_attr_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ return attr->mode;
+}
+
+static struct device_attribute ali_drw_pmu_identifier_attr =
+ __ATTR(identifier, 0444, ali_drw_pmu_identifier_show, NULL);
+
+static struct attribute *ali_drw_pmu_identifier_attrs[] = {
+ &ali_drw_pmu_identifier_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ali_drw_pmu_identifier_attr_group = {
+ .attrs = ali_drw_pmu_identifier_attrs,
+ .is_visible = ali_drw_pmu_identifier_attr_visible
+};
+
static const struct attribute_group *ali_drw_pmu_attr_groups[] = {
&ali_drw_pmu_events_attr_group,
&ali_drw_pmu_cpumask_attr_group,
&ali_drw_pmu_format_group,
+ &ali_drw_pmu_identifier_attr_group,
NULL,
};
diff --git a/drivers/perf/amlogic/meson_ddr_pmu_core.c b/drivers/perf/amlogic/meson_ddr_pmu_core.c
index 0b24dee1ed3c..bbc7285fd934 100644
--- a/drivers/perf/amlogic/meson_ddr_pmu_core.c
+++ b/drivers/perf/amlogic/meson_ddr_pmu_core.c
@@ -9,8 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
diff --git a/drivers/perf/arm-cci.c b/drivers/perf/arm-cci.c
index 998259f1d973..61de861eaf91 100644
--- a/drivers/perf/arm-cci.c
+++ b/drivers/perf/arm-cci.c
@@ -7,10 +7,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index b8c15878bc86..913dc04b3a40 100644
--- a/drivers/perf/arm-cmn.c
+++ b/drivers/perf/arm-cmn.c
@@ -72,6 +72,8 @@
/* For most nodes, this is all there is */
#define CMN_PMU_EVENT_SEL 0x000
#define CMN__PMU_CBUSY_SNTHROTTLE_SEL GENMASK_ULL(44, 42)
+#define CMN__PMU_SN_HOME_SEL GENMASK_ULL(40, 39)
+#define CMN__PMU_HBT_LBT_SEL GENMASK_ULL(38, 37)
#define CMN__PMU_CLASS_OCCUP_ID GENMASK_ULL(36, 35)
/* Technically this is 4 bits wide on DNs, but we only use 2 there anyway */
#define CMN__PMU_OCCUP1_ID GENMASK_ULL(34, 32)
@@ -226,6 +228,7 @@ enum cmn_revision {
REV_CMN700_R0P0 = 0,
REV_CMN700_R1P0,
REV_CMN700_R2P0,
+ REV_CMN700_R3P0,
REV_CI700_R0P0 = 0,
REV_CI700_R1P0,
REV_CI700_R2P0,
@@ -254,6 +257,9 @@ enum cmn_node_type {
CMN_TYPE_CCHA,
CMN_TYPE_CCLA,
CMN_TYPE_CCLA_RNI,
+ CMN_TYPE_HNS = 0x200,
+ CMN_TYPE_HNS_MPAM_S,
+ CMN_TYPE_HNS_MPAM_NS,
/* Not a real node type */
CMN_TYPE_WP = 0x7770
};
@@ -263,6 +269,8 @@ enum cmn_filter_select {
SEL_OCCUP1ID,
SEL_CLASS_OCCUP_ID,
SEL_CBUSY_SNTHROTTLE_SEL,
+ SEL_HBT_LBT_SEL,
+ SEL_SN_HOME_SEL,
SEL_MAX
};
@@ -742,8 +750,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
_CMN_EVENT_ATTR(_model, dn_##_name, CMN_TYPE_DVM, _event, _occup, _fsel)
#define CMN_EVENT_DTC(_name) \
CMN_EVENT_ATTR(CMN_ANY, dtc_##_name, CMN_TYPE_DTC, 0)
-#define _CMN_EVENT_HNF(_model, _name, _event, _occup, _fsel) \
- _CMN_EVENT_ATTR(_model, hnf_##_name, CMN_TYPE_HNF, _event, _occup, _fsel)
+#define CMN_EVENT_HNF(_model, _name, _event) \
+ CMN_EVENT_ATTR(_model, hnf_##_name, CMN_TYPE_HNF, _event)
#define CMN_EVENT_HNI(_name, _event) \
CMN_EVENT_ATTR(CMN_ANY, hni_##_name, CMN_TYPE_HNI, _event)
#define CMN_EVENT_HNP(_name, _event) \
@@ -768,6 +776,8 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
CMN_EVENT_ATTR(CMN_ANY, ccla_##_name, CMN_TYPE_CCLA, _event)
#define CMN_EVENT_CCLA_RNI(_name, _event) \
CMN_EVENT_ATTR(CMN_ANY, ccla_rni_##_name, CMN_TYPE_CCLA_RNI, _event)
+#define CMN_EVENT_HNS(_name, _event) \
+ CMN_EVENT_ATTR(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
#define CMN_EVENT_DVM(_model, _name, _event) \
_CMN_EVENT_DVM(_model, _name, _event, 0, SEL_NONE)
@@ -775,32 +785,68 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
_CMN_EVENT_DVM(_model, _name##_all, _event, 0, SEL_OCCUP1ID), \
_CMN_EVENT_DVM(_model, _name##_dvmop, _event, 1, SEL_OCCUP1ID), \
_CMN_EVENT_DVM(_model, _name##_dvmsync, _event, 2, SEL_OCCUP1ID)
-#define CMN_EVENT_HNF(_model, _name, _event) \
- _CMN_EVENT_HNF(_model, _name, _event, 0, SEL_NONE)
+
+#define CMN_EVENT_HN_OCC(_model, _name, _type, _event) \
+ _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 1, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 2, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(_model, _name##_atomic, _type, _event, 3, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(_model, _name##_stash, _type, _event, 4, SEL_OCCUP1ID)
+#define CMN_EVENT_HN_CLS(_model, _name, _type, _event) \
+ _CMN_EVENT_ATTR(_model, _name##_class0, _type, _event, 0, SEL_CLASS_OCCUP_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_class1, _type, _event, 1, SEL_CLASS_OCCUP_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_class2, _type, _event, 2, SEL_CLASS_OCCUP_ID), \
+ _CMN_EVENT_ATTR(_model, _name##_class3, _type, _event, 3, SEL_CLASS_OCCUP_ID)
+#define CMN_EVENT_HN_SNT(_model, _name, _type, _event) \
+ _CMN_EVENT_ATTR(_model, _name##_all, _type, _event, 0, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_group0_read, _type, _event, 1, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_group0_write, _type, _event, 2, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_group1_read, _type, _event, 3, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_group1_write, _type, _event, 4, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_read, _type, _event, 5, SEL_CBUSY_SNTHROTTLE_SEL), \
+ _CMN_EVENT_ATTR(_model, _name##_write, _type, _event, 6, SEL_CBUSY_SNTHROTTLE_SEL)
+
+#define CMN_EVENT_HNF_OCC(_model, _name, _event) \
+ CMN_EVENT_HN_OCC(_model, hnf_##_name, CMN_TYPE_HNF, _event)
#define CMN_EVENT_HNF_CLS(_model, _name, _event) \
- _CMN_EVENT_HNF(_model, _name##_class0, _event, 0, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_HNF(_model, _name##_class1, _event, 1, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_HNF(_model, _name##_class2, _event, 2, SEL_CLASS_OCCUP_ID), \
- _CMN_EVENT_HNF(_model, _name##_class3, _event, 3, SEL_CLASS_OCCUP_ID)
+ CMN_EVENT_HN_CLS(_model, hnf_##_name, CMN_TYPE_HNS, _event)
#define CMN_EVENT_HNF_SNT(_model, _name, _event) \
- _CMN_EVENT_HNF(_model, _name##_all, _event, 0, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_group0_read, _event, 1, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_group0_write, _event, 2, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_group1_read, _event, 3, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_group1_write, _event, 4, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_read, _event, 5, SEL_CBUSY_SNTHROTTLE_SEL), \
- _CMN_EVENT_HNF(_model, _name##_write, _event, 6, SEL_CBUSY_SNTHROTTLE_SEL)
-
-#define _CMN_EVENT_XP(_name, _event) \
+ CMN_EVENT_HN_SNT(_model, hnf_##_name, CMN_TYPE_HNF, _event)
+
+#define CMN_EVENT_HNS_OCC(_name, _event) \
+ CMN_EVENT_HN_OCC(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_rxsnp, CMN_TYPE_HNS, _event, 5, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 6, SEL_OCCUP1ID), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 7, SEL_OCCUP1ID)
+#define CMN_EVENT_HNS_CLS( _name, _event) \
+ CMN_EVENT_HN_CLS(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
+#define CMN_EVENT_HNS_SNT(_name, _event) \
+ CMN_EVENT_HN_SNT(CMN_ANY, hns_##_name, CMN_TYPE_HNS, _event)
+#define CMN_EVENT_HNS_HBT(_name, _event) \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, 0, SEL_HBT_LBT_SEL), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_hbt, CMN_TYPE_HNS, _event, 1, SEL_HBT_LBT_SEL), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_lbt, CMN_TYPE_HNS, _event, 2, SEL_HBT_LBT_SEL)
+#define CMN_EVENT_HNS_SNH(_name, _event) \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_all, CMN_TYPE_HNS, _event, 0, SEL_SN_HOME_SEL), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_sn, CMN_TYPE_HNS, _event, 1, SEL_SN_HOME_SEL), \
+ _CMN_EVENT_ATTR(CMN_ANY, hns_##_name##_home, CMN_TYPE_HNS, _event, 2, SEL_SN_HOME_SEL)
+
+#define _CMN_EVENT_XP_MESH(_name, _event) \
__CMN_EVENT_XP(e_##_name, (_event) | (0 << 2)), \
__CMN_EVENT_XP(w_##_name, (_event) | (1 << 2)), \
__CMN_EVENT_XP(n_##_name, (_event) | (2 << 2)), \
- __CMN_EVENT_XP(s_##_name, (_event) | (3 << 2)), \
+ __CMN_EVENT_XP(s_##_name, (_event) | (3 << 2))
+
+#define _CMN_EVENT_XP_PORT(_name, _event) \
__CMN_EVENT_XP(p0_##_name, (_event) | (4 << 2)), \
__CMN_EVENT_XP(p1_##_name, (_event) | (5 << 2)), \
__CMN_EVENT_XP(p2_##_name, (_event) | (6 << 2)), \
__CMN_EVENT_XP(p3_##_name, (_event) | (7 << 2))
+#define _CMN_EVENT_XP(_name, _event) \
+ _CMN_EVENT_XP_MESH(_name, _event), \
+ _CMN_EVENT_XP_PORT(_name, _event)
+
/* Good thing there are only 3 fundamental XP events... */
#define CMN_EVENT_XP(_name, _event) \
_CMN_EVENT_XP(req_##_name, (_event) | (0 << 5)), \
@@ -813,6 +859,10 @@ static umode_t arm_cmn_event_attr_is_visible(struct kobject *kobj,
_CMN_EVENT_XP(snp2_##_name, (_event) | (7 << 5)), \
_CMN_EVENT_XP(req2_##_name, (_event) | (8 << 5))
+#define CMN_EVENT_XP_DAT(_name, _event) \
+ _CMN_EVENT_XP_PORT(dat_##_name, (_event) | (3 << 5)), \
+ _CMN_EVENT_XP_PORT(dat2_##_name, (_event) | (6 << 5))
+
static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_DTC(cycles),
@@ -862,11 +912,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_HNF(CMN_ANY, mc_retries, 0x0c),
CMN_EVENT_HNF(CMN_ANY, mc_reqs, 0x0d),
CMN_EVENT_HNF(CMN_ANY, qos_hh_retry, 0x0e),
- _CMN_EVENT_HNF(CMN_ANY, qos_pocq_occupancy_all, 0x0f, 0, SEL_OCCUP1ID),
- _CMN_EVENT_HNF(CMN_ANY, qos_pocq_occupancy_read, 0x0f, 1, SEL_OCCUP1ID),
- _CMN_EVENT_HNF(CMN_ANY, qos_pocq_occupancy_write, 0x0f, 2, SEL_OCCUP1ID),
- _CMN_EVENT_HNF(CMN_ANY, qos_pocq_occupancy_atomic, 0x0f, 3, SEL_OCCUP1ID),
- _CMN_EVENT_HNF(CMN_ANY, qos_pocq_occupancy_stash, 0x0f, 4, SEL_OCCUP1ID),
+ CMN_EVENT_HNF_OCC(CMN_ANY, qos_pocq_occupancy, 0x0f),
CMN_EVENT_HNF(CMN_ANY, pocq_addrhaz, 0x10),
CMN_EVENT_HNF(CMN_ANY, pocq_atomic_addrhaz, 0x11),
CMN_EVENT_HNF(CMN_ANY, ld_st_swp_adq_full, 0x12),
@@ -943,7 +989,7 @@ static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_XP(txflit_valid, 0x01),
CMN_EVENT_XP(txflit_stall, 0x02),
- CMN_EVENT_XP(partial_dat_flit, 0x03),
+ CMN_EVENT_XP_DAT(partial_dat_flit, 0x03),
/* We treat watchpoints as a special made-up class of XP events */
CMN_EVENT_ATTR(CMN_ANY, watchpoint_up, CMN_TYPE_WP, CMN_WP_UP),
CMN_EVENT_ATTR(CMN_ANY, watchpoint_down, CMN_TYPE_WP, CMN_WP_DOWN),
@@ -1132,6 +1178,66 @@ static struct attribute *arm_cmn_event_attrs[] = {
CMN_EVENT_CCLA(pfwd_sndr_stalls_static_crd, 0x2a),
CMN_EVENT_CCLA(pfwd_sndr_stalls_dynmaic_crd, 0x2b),
+ CMN_EVENT_HNS_HBT(cache_miss, 0x01),
+ CMN_EVENT_HNS_HBT(slc_sf_cache_access, 0x02),
+ CMN_EVENT_HNS_HBT(cache_fill, 0x03),
+ CMN_EVENT_HNS_HBT(pocq_retry, 0x04),
+ CMN_EVENT_HNS_HBT(pocq_reqs_recvd, 0x05),
+ CMN_EVENT_HNS_HBT(sf_hit, 0x06),
+ CMN_EVENT_HNS_HBT(sf_evictions, 0x07),
+ CMN_EVENT_HNS(dir_snoops_sent, 0x08),
+ CMN_EVENT_HNS(brd_snoops_sent, 0x09),
+ CMN_EVENT_HNS_HBT(slc_eviction, 0x0a),
+ CMN_EVENT_HNS_HBT(slc_fill_invalid_way, 0x0b),
+ CMN_EVENT_HNS(mc_retries_local, 0x0c),
+ CMN_EVENT_HNS_SNH(mc_reqs_local, 0x0d),
+ CMN_EVENT_HNS(qos_hh_retry, 0x0e),
+ CMN_EVENT_HNS_OCC(qos_pocq_occupancy, 0x0f),
+ CMN_EVENT_HNS(pocq_addrhaz, 0x10),
+ CMN_EVENT_HNS(pocq_atomic_addrhaz, 0x11),
+ CMN_EVENT_HNS(ld_st_swp_adq_full, 0x12),
+ CMN_EVENT_HNS(cmp_adq_full, 0x13),
+ CMN_EVENT_HNS(txdat_stall, 0x14),
+ CMN_EVENT_HNS(txrsp_stall, 0x15),
+ CMN_EVENT_HNS(seq_full, 0x16),
+ CMN_EVENT_HNS(seq_hit, 0x17),
+ CMN_EVENT_HNS(snp_sent, 0x18),
+ CMN_EVENT_HNS(sfbi_dir_snp_sent, 0x19),
+ CMN_EVENT_HNS(sfbi_brd_snp_sent, 0x1a),
+ CMN_EVENT_HNS(intv_dirty, 0x1c),
+ CMN_EVENT_HNS(stash_snp_sent, 0x1d),
+ CMN_EVENT_HNS(stash_data_pull, 0x1e),
+ CMN_EVENT_HNS(snp_fwded, 0x1f),
+ CMN_EVENT_HNS(atomic_fwd, 0x20),
+ CMN_EVENT_HNS(mpam_hardlim, 0x21),
+ CMN_EVENT_HNS(mpam_softlim, 0x22),
+ CMN_EVENT_HNS(snp_sent_cluster, 0x23),
+ CMN_EVENT_HNS(sf_imprecise_evict, 0x24),
+ CMN_EVENT_HNS(sf_evict_shared_line, 0x25),
+ CMN_EVENT_HNS_CLS(pocq_class_occup, 0x26),
+ CMN_EVENT_HNS_CLS(pocq_class_retry, 0x27),
+ CMN_EVENT_HNS_CLS(class_mc_reqs_local, 0x28),
+ CMN_EVENT_HNS_CLS(class_cgnt_cmin, 0x29),
+ CMN_EVENT_HNS_SNT(sn_throttle, 0x2a),
+ CMN_EVENT_HNS_SNT(sn_throttle_min, 0x2b),
+ CMN_EVENT_HNS(sf_precise_to_imprecise, 0x2c),
+ CMN_EVENT_HNS(snp_intv_cln, 0x2d),
+ CMN_EVENT_HNS(nc_excl, 0x2e),
+ CMN_EVENT_HNS(excl_mon_ovfl, 0x2f),
+ CMN_EVENT_HNS(snp_req_recvd, 0x30),
+ CMN_EVENT_HNS(snp_req_byp_pocq, 0x31),
+ CMN_EVENT_HNS(dir_ccgha_snp_sent, 0x32),
+ CMN_EVENT_HNS(brd_ccgha_snp_sent, 0x33),
+ CMN_EVENT_HNS(ccgha_snp_stall, 0x34),
+ CMN_EVENT_HNS(lbt_req_hardlim, 0x35),
+ CMN_EVENT_HNS(hbt_req_hardlim, 0x36),
+ CMN_EVENT_HNS(sf_reupdate, 0x37),
+ CMN_EVENT_HNS(excl_sf_imprecise, 0x38),
+ CMN_EVENT_HNS(snp_pocq_addrhaz, 0x39),
+ CMN_EVENT_HNS(mc_retries_remote, 0x3a),
+ CMN_EVENT_HNS_SNH(mc_reqs_remote, 0x3b),
+ CMN_EVENT_HNS_CLS(class_mc_reqs_remote, 0x3c),
+
NULL
};
@@ -1373,6 +1479,10 @@ static int arm_cmn_set_event_sel_hi(struct arm_cmn_node *dn,
dn->occupid[fsel].val = occupid;
reg = FIELD_PREP(CMN__PMU_CBUSY_SNTHROTTLE_SEL,
dn->occupid[SEL_CBUSY_SNTHROTTLE_SEL].val) |
+ FIELD_PREP(CMN__PMU_SN_HOME_SEL,
+ dn->occupid[SEL_SN_HOME_SEL].val) |
+ FIELD_PREP(CMN__PMU_HBT_LBT_SEL,
+ dn->occupid[SEL_HBT_LBT_SEL].val) |
FIELD_PREP(CMN__PMU_CLASS_OCCUP_ID,
dn->occupid[SEL_CLASS_OCCUP_ID].val) |
FIELD_PREP(CMN__PMU_OCCUP1_ID,
@@ -2200,6 +2310,7 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
case CMN_TYPE_CCRA:
case CMN_TYPE_CCHA:
case CMN_TYPE_CCLA:
+ case CMN_TYPE_HNS:
dn++;
break;
/* Nothing to see here */
@@ -2207,6 +2318,8 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
case CMN_TYPE_MPAM_NS:
case CMN_TYPE_RNSAM:
case CMN_TYPE_CXLA:
+ case CMN_TYPE_HNS_MPAM_S:
+ case CMN_TYPE_HNS_MPAM_NS:
break;
/*
* Split "optimised" combination nodes into separate
diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c
index 9d0f01c4455a..30cea6859574 100644
--- a/drivers/perf/arm_dmc620_pmu.c
+++ b/drivers/perf/arm_dmc620_pmu.c
@@ -66,8 +66,13 @@
#define DMC620_PMU_COUNTERn_OFFSET(n) \
(DMC620_PMU_COUNTERS_BASE + 0x28 * (n))
-static LIST_HEAD(dmc620_pmu_irqs);
+/*
+ * dmc620_pmu_irqs_lock: protects dmc620_pmu_irqs list
+ * dmc620_pmu_node_lock: protects pmus_node lists in all dmc620_pmu instances
+ */
static DEFINE_MUTEX(dmc620_pmu_irqs_lock);
+static DEFINE_MUTEX(dmc620_pmu_node_lock);
+static LIST_HEAD(dmc620_pmu_irqs);
struct dmc620_pmu_irq {
struct hlist_node node;
@@ -475,9 +480,9 @@ static int dmc620_pmu_get_irq(struct dmc620_pmu *dmc620_pmu, int irq_num)
return PTR_ERR(irq);
dmc620_pmu->irq = irq;
- mutex_lock(&dmc620_pmu_irqs_lock);
+ mutex_lock(&dmc620_pmu_node_lock);
list_add_rcu(&dmc620_pmu->pmus_node, &irq->pmus_node);
- mutex_unlock(&dmc620_pmu_irqs_lock);
+ mutex_unlock(&dmc620_pmu_node_lock);
return 0;
}
@@ -486,9 +491,11 @@ static void dmc620_pmu_put_irq(struct dmc620_pmu *dmc620_pmu)
{
struct dmc620_pmu_irq *irq = dmc620_pmu->irq;
- mutex_lock(&dmc620_pmu_irqs_lock);
+ mutex_lock(&dmc620_pmu_node_lock);
list_del_rcu(&dmc620_pmu->pmus_node);
+ mutex_unlock(&dmc620_pmu_node_lock);
+ mutex_lock(&dmc620_pmu_irqs_lock);
if (!refcount_dec_and_test(&irq->refcount)) {
mutex_unlock(&dmc620_pmu_irqs_lock);
return;
@@ -638,10 +645,10 @@ static int dmc620_pmu_cpu_teardown(unsigned int cpu,
return 0;
/* We're only reading, but this isn't the place to be involving RCU */
- mutex_lock(&dmc620_pmu_irqs_lock);
+ mutex_lock(&dmc620_pmu_node_lock);
list_for_each_entry(dmc620_pmu, &irq->pmus_node, pmus_node)
perf_pmu_migrate_context(&dmc620_pmu->pmu, irq->cpu, target);
- mutex_unlock(&dmc620_pmu_irqs_lock);
+ mutex_unlock(&dmc620_pmu_node_lock);
WARN_ON(irq_set_affinity(irq->irq_num, cpumask_of(target)));
irq->cpu = target;
diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
index fe2abb412c00..8223c49bd082 100644
--- a/drivers/perf/arm_dsu_pmu.c
+++ b/drivers/perf/arm_dsu_pmu.c
@@ -20,7 +20,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index f6ccb2cd4dfc..d712a19e47ac 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -877,11 +877,13 @@ struct arm_pmu *armpmu_alloc(void)
.attr_groups = pmu->attr_groups,
/*
* This is a CPU PMU potentially in a heterogeneous
- * configuration (e.g. big.LITTLE). This is not an uncore PMU,
- * and we have taken ctx sharing into account (e.g. with our
- * pmu::filter callback and pmu::event_init group validation).
+ * configuration (e.g. big.LITTLE) so
+ * PERF_PMU_CAP_EXTENDED_HW_TYPE is required to open
+ * PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE events on a
+ * specific PMU.
*/
- .capabilities = PERF_PMU_CAP_HETEROGENEOUS_CPUS | PERF_PMU_CAP_EXTENDED_REGS,
+ .capabilities = PERF_PMU_CAP_EXTENDED_REGS |
+ PERF_PMU_CAP_EXTENDED_HW_TYPE,
};
pmu->attr_groups[ARMPMU_ATTR_GROUP_COMMON] =
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index 90815ad762eb..05dda19c5359 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -69,6 +69,62 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
acpi_unregister_gsi(gsi);
}
+static int __maybe_unused
+arm_acpi_register_pmu_device(struct platform_device *pdev, u8 len,
+ u16 (*parse_gsi)(struct acpi_madt_generic_interrupt *))
+{
+ int cpu, this_hetid, hetid, irq, ret;
+ u16 this_gsi = 0, gsi = 0;
+
+ /*
+ * Ensure that platform device must have IORESOURCE_IRQ
+ * resource to hold gsi interrupt.
+ */
+ if (pdev->num_resources != 1)
+ return -ENXIO;
+
+ if (pdev->resource[0].flags != IORESOURCE_IRQ)
+ return -ENXIO;
+
+ /*
+ * Sanity check all the GICC tables for the same interrupt
+ * number. For now, only support homogeneous ACPI machines.
+ */
+ for_each_possible_cpu(cpu) {
+ struct acpi_madt_generic_interrupt *gicc;
+
+ gicc = acpi_cpu_get_madt_gicc(cpu);
+ if (gicc->header.length < len)
+ return gsi ? -ENXIO : 0;
+
+ this_gsi = parse_gsi(gicc);
+ this_hetid = find_acpi_cpu_topology_hetero_id(cpu);
+ if (!gsi) {
+ hetid = this_hetid;
+ gsi = this_gsi;
+ } else if (hetid != this_hetid || gsi != this_gsi) {
+ pr_warn("ACPI: %s: must be homogeneous\n", pdev->name);
+ return -ENXIO;
+ }
+ }
+
+ if (!this_gsi)
+ return 0;
+
+ irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+ if (irq < 0) {
+ pr_warn("ACPI: %s Unable to register interrupt: %d\n", pdev->name, gsi);
+ return -ENXIO;
+ }
+
+ pdev->resource[0].start = irq;
+ ret = platform_device_register(pdev);
+ if (ret)
+ acpi_unregister_gsi(gsi);
+
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_ARM_SPE_PMU)
static struct resource spe_resources[] = {
{
@@ -84,6 +140,11 @@ static struct platform_device spe_dev = {
.num_resources = ARRAY_SIZE(spe_resources)
};
+static u16 arm_spe_parse_gsi(struct acpi_madt_generic_interrupt *gicc)
+{
+ return gicc->spe_interrupt;
+}
+
/*
* For lack of a better place, hook the normal PMU MADT walk
* and create a SPE device if we detect a recent MADT with
@@ -91,53 +152,50 @@ static struct platform_device spe_dev = {
*/
static void arm_spe_acpi_register_device(void)
{
- int cpu, hetid, irq, ret;
- bool first = true;
- u16 gsi = 0;
-
- /*
- * Sanity check all the GICC tables for the same interrupt number.
- * For now, we only support homogeneous ACPI/SPE machines.
- */
- for_each_possible_cpu(cpu) {
- struct acpi_madt_generic_interrupt *gicc;
+ int ret = arm_acpi_register_pmu_device(&spe_dev, ACPI_MADT_GICC_SPE,
+ arm_spe_parse_gsi);
+ if (ret)
+ pr_warn("ACPI: SPE: Unable to register device\n");
+}
+#else
+static inline void arm_spe_acpi_register_device(void)
+{
+}
+#endif /* CONFIG_ARM_SPE_PMU */
- gicc = acpi_cpu_get_madt_gicc(cpu);
- if (gicc->header.length < ACPI_MADT_GICC_SPE)
- return;
-
- if (first) {
- gsi = gicc->spe_interrupt;
- if (!gsi)
- return;
- hetid = find_acpi_cpu_topology_hetero_id(cpu);
- first = false;
- } else if ((gsi != gicc->spe_interrupt) ||
- (hetid != find_acpi_cpu_topology_hetero_id(cpu))) {
- pr_warn("ACPI: SPE must be homogeneous\n");
- return;
- }
+#if IS_ENABLED(CONFIG_CORESIGHT_TRBE)
+static struct resource trbe_resources[] = {
+ {
+ /* irq */
+ .flags = IORESOURCE_IRQ,
}
+};
- irq = acpi_register_gsi(NULL, gsi, ACPI_LEVEL_SENSITIVE,
- ACPI_ACTIVE_HIGH);
- if (irq < 0) {
- pr_warn("ACPI: SPE Unable to register interrupt: %d\n", gsi);
- return;
- }
+static struct platform_device trbe_dev = {
+ .name = ARMV8_TRBE_PDEV_NAME,
+ .id = -1,
+ .resource = trbe_resources,
+ .num_resources = ARRAY_SIZE(trbe_resources)
+};
- spe_resources[0].start = irq;
- ret = platform_device_register(&spe_dev);
- if (ret < 0) {
- pr_warn("ACPI: SPE: Unable to register device\n");
- acpi_unregister_gsi(gsi);
- }
+static u16 arm_trbe_parse_gsi(struct acpi_madt_generic_interrupt *gicc)
+{
+ return gicc->trbe_interrupt;
+}
+
+static void arm_trbe_acpi_register_device(void)
+{
+ int ret = arm_acpi_register_pmu_device(&trbe_dev, ACPI_MADT_GICC_TRBE,
+ arm_trbe_parse_gsi);
+ if (ret)
+ pr_warn("ACPI: TRBE: Unable to register device\n");
}
#else
-static inline void arm_spe_acpi_register_device(void)
+static inline void arm_trbe_acpi_register_device(void)
{
+
}
-#endif /* CONFIG_ARM_SPE_PMU */
+#endif /* CONFIG_CORESIGHT_TRBE */
static int arm_pmu_acpi_parse_irqs(void)
{
@@ -374,6 +432,7 @@ static int arm_pmu_acpi_init(void)
return 0;
arm_spe_acpi_register_device();
+ arm_trbe_acpi_register_device();
return 0;
}
diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c
index 933b96e243b8..3596db36cbff 100644
--- a/drivers/perf/arm_pmu_platform.c
+++ b/drivers/perf/arm_pmu_platform.c
@@ -16,7 +16,6 @@
#include <linux/irqdesc.h>
#include <linux/kconfig.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/percpu.h>
#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 08b3a1bf0ef6..e5a2ac4155f6 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -721,38 +721,15 @@ static void armv8pmu_enable_event(struct perf_event *event)
* Enable counter and interrupt, and set the counter to count
* the event that we're interested in.
*/
-
- /*
- * Disable counter
- */
armv8pmu_disable_event_counter(event);
-
- /*
- * Set event.
- */
armv8pmu_write_event_type(event);
-
- /*
- * Enable interrupt for this counter
- */
armv8pmu_enable_event_irq(event);
-
- /*
- * Enable counter
- */
armv8pmu_enable_event_counter(event);
}
static void armv8pmu_disable_event(struct perf_event *event)
{
- /*
- * Disable counter
- */
armv8pmu_disable_event_counter(event);
-
- /*
- * Disable interrupt for this counter
- */
armv8pmu_disable_event_irq(event);
}
@@ -1266,9 +1243,14 @@ PMUV3_INIT_SIMPLE(armv8_cortex_a76)
PMUV3_INIT_SIMPLE(armv8_cortex_a77)
PMUV3_INIT_SIMPLE(armv8_cortex_a78)
PMUV3_INIT_SIMPLE(armv9_cortex_a510)
+PMUV3_INIT_SIMPLE(armv9_cortex_a520)
PMUV3_INIT_SIMPLE(armv9_cortex_a710)
+PMUV3_INIT_SIMPLE(armv9_cortex_a715)
+PMUV3_INIT_SIMPLE(armv9_cortex_a720)
PMUV3_INIT_SIMPLE(armv8_cortex_x1)
PMUV3_INIT_SIMPLE(armv9_cortex_x2)
+PMUV3_INIT_SIMPLE(armv9_cortex_x3)
+PMUV3_INIT_SIMPLE(armv9_cortex_x4)
PMUV3_INIT_SIMPLE(armv8_neoverse_e1)
PMUV3_INIT_SIMPLE(armv8_neoverse_n1)
PMUV3_INIT_SIMPLE(armv9_neoverse_n2)
@@ -1334,9 +1316,14 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
{.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init},
{.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init},
{.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init},
+ {.compatible = "arm,cortex-a520-pmu", .data = armv9_cortex_a520_pmu_init},
{.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init},
+ {.compatible = "arm,cortex-a715-pmu", .data = armv9_cortex_a715_pmu_init},
+ {.compatible = "arm,cortex-a720-pmu", .data = armv9_cortex_a720_pmu_init},
{.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init},
{.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init},
+ {.compatible = "arm,cortex-x3-pmu", .data = armv9_cortex_x3_pmu_init},
+ {.compatible = "arm,cortex-x4-pmu", .data = armv9_cortex_x4_pmu_init},
{.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init},
{.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init},
{.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init},
diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c
index 25a269d431e4..6303b82566f9 100644
--- a/drivers/perf/arm_smmuv3_pmu.c
+++ b/drivers/perf/arm_smmuv3_pmu.c
@@ -115,6 +115,7 @@
#define SMMU_PMCG_PA_SHIFT 12
#define SMMU_PMCG_EVCNTR_RDONLY BIT(0)
+#define SMMU_PMCG_HARDEN_DISABLE BIT(1)
static int cpuhp_state_num;
@@ -159,6 +160,20 @@ static inline void smmu_pmu_enable(struct pmu *pmu)
writel(SMMU_PMCG_CR_ENABLE, smmu_pmu->reg_base + SMMU_PMCG_CR);
}
+static int smmu_pmu_apply_event_filter(struct smmu_pmu *smmu_pmu,
+ struct perf_event *event, int idx);
+
+static inline void smmu_pmu_enable_quirk_hip08_09(struct pmu *pmu)
+{
+ struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
+ unsigned int idx;
+
+ for_each_set_bit(idx, smmu_pmu->used_counters, smmu_pmu->num_counters)
+ smmu_pmu_apply_event_filter(smmu_pmu, smmu_pmu->events[idx], idx);
+
+ smmu_pmu_enable(pmu);
+}
+
static inline void smmu_pmu_disable(struct pmu *pmu)
{
struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
@@ -167,6 +182,22 @@ static inline void smmu_pmu_disable(struct pmu *pmu)
writel(0, smmu_pmu->reg_base + SMMU_PMCG_IRQ_CTRL);
}
+static inline void smmu_pmu_disable_quirk_hip08_09(struct pmu *pmu)
+{
+ struct smmu_pmu *smmu_pmu = to_smmu_pmu(pmu);
+ unsigned int idx;
+
+ /*
+ * The global disable of PMU sometimes fail to stop the counting.
+ * Harden this by writing an invalid event type to each used counter
+ * to forcibly stop counting.
+ */
+ for_each_set_bit(idx, smmu_pmu->used_counters, smmu_pmu->num_counters)
+ writel(0xffff, smmu_pmu->reg_base + SMMU_PMCG_EVTYPER(idx));
+
+ smmu_pmu_disable(pmu);
+}
+
static inline void smmu_pmu_counter_set_value(struct smmu_pmu *smmu_pmu,
u32 idx, u64 value)
{
@@ -765,7 +796,10 @@ static void smmu_pmu_get_acpi_options(struct smmu_pmu *smmu_pmu)
switch (model) {
case IORT_SMMU_V3_PMCG_HISI_HIP08:
/* HiSilicon Erratum 162001800 */
- smmu_pmu->options |= SMMU_PMCG_EVCNTR_RDONLY;
+ smmu_pmu->options |= SMMU_PMCG_EVCNTR_RDONLY | SMMU_PMCG_HARDEN_DISABLE;
+ break;
+ case IORT_SMMU_V3_PMCG_HISI_HIP09:
+ smmu_pmu->options |= SMMU_PMCG_HARDEN_DISABLE;
break;
}
@@ -890,6 +924,16 @@ static int smmu_pmu_probe(struct platform_device *pdev)
if (!dev->of_node)
smmu_pmu_get_acpi_options(smmu_pmu);
+ /*
+ * For platforms suffer this quirk, the PMU disable sometimes fails to
+ * stop the counters. This will leads to inaccurate or error counting.
+ * Forcibly disable the counters with these quirk handler.
+ */
+ if (smmu_pmu->options & SMMU_PMCG_HARDEN_DISABLE) {
+ smmu_pmu->pmu.pmu_enable = smmu_pmu_enable_quirk_hip08_09;
+ smmu_pmu->pmu.pmu_disable = smmu_pmu_disable_quirk_hip08_09;
+ }
+
/* Pick one CPU to be the preferred one to use */
smmu_pmu->on_cpu = raw_smp_processor_id();
WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(smmu_pmu->on_cpu)));
@@ -984,6 +1028,7 @@ static void __exit arm_smmu_pmu_exit(void)
module_exit(arm_smmu_pmu_exit);
+MODULE_ALIAS("platform:arm-smmu-v3-pmcg");
MODULE_DESCRIPTION("PMU driver for ARM SMMUv3 Performance Monitors Extension");
MODULE_AUTHOR("Neil Leeder <nleeder@codeaurora.org>");
MODULE_AUTHOR("Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>");
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index b9ba4c4fe5a2..d2b0cbf0e0c4 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -25,8 +25,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/perf_event.h>
#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
index 5222ba1e79d0..92611c98120f 100644
--- a/drivers/perf/fsl_imx8_ddr_perf.c
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -10,10 +10,9 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/perf_event.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#define COUNTER_CNTL 0x0
@@ -28,6 +27,8 @@
#define CNTL_CLEAR_MASK 0xFFFFFFFD
#define CNTL_OVER_MASK 0xFFFFFFFE
+#define CNTL_CP_SHIFT 16
+#define CNTL_CP_MASK (0xFF << CNTL_CP_SHIFT)
#define CNTL_CSV_SHIFT 24
#define CNTL_CSV_MASK (0xFFU << CNTL_CSV_SHIFT)
@@ -35,6 +36,8 @@
#define EVENT_CYCLES_COUNTER 0
#define NUM_COUNTERS 4
+/* For removing bias if cycle counter CNTL.CP is set to 0xf0 */
+#define CYCLES_COUNTER_MASK 0x0FFFFFFF
#define AXI_MASKING_REVERT 0xffff0000 /* AXI_MASKING(MSB 16bits) + AXI_ID(LSB 16bits) */
#define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu)
@@ -101,6 +104,7 @@ struct ddr_pmu {
const struct fsl_ddr_devtype_data *devtype_data;
int irq;
int id;
+ int active_counter;
};
static ssize_t ddr_perf_identifier_show(struct device *dev,
@@ -427,6 +431,17 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
writel(0, pmu->base + reg);
val = CNTL_EN | CNTL_CLEAR;
val |= FIELD_PREP(CNTL_CSV_MASK, config);
+
+ /*
+ * On i.MX8MP we need to bias the cycle counter to overflow more often.
+ * We do this by initializing bits [23:16] of the counter value via the
+ * COUNTER_CTRL Counter Parameter (CP) field.
+ */
+ if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER_ENHANCED) {
+ if (counter == EVENT_CYCLES_COUNTER)
+ val |= FIELD_PREP(CNTL_CP_MASK, 0xf0);
+ }
+
writel(val, pmu->base + reg);
} else {
/* Disable counter */
@@ -466,6 +481,12 @@ static void ddr_perf_event_update(struct perf_event *event)
int ret;
new_raw_count = ddr_perf_read_counter(pmu, counter);
+ /* Remove the bias applied in ddr_perf_counter_enable(). */
+ if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER_ENHANCED) {
+ if (counter == EVENT_CYCLES_COUNTER)
+ new_raw_count &= CYCLES_COUNTER_MASK;
+ }
+
local64_add(new_raw_count, &event->count);
/*
@@ -495,6 +516,10 @@ static void ddr_perf_event_start(struct perf_event *event, int flags)
ddr_perf_counter_enable(pmu, event->attr.config, counter, true);
+ if (!pmu->active_counter++)
+ ddr_perf_counter_enable(pmu, EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER, true);
+
hwc->state = 0;
}
@@ -548,6 +573,10 @@ static void ddr_perf_event_stop(struct perf_event *event, int flags)
ddr_perf_counter_enable(pmu, event->attr.config, counter, false);
ddr_perf_event_update(event);
+ if (!--pmu->active_counter)
+ ddr_perf_counter_enable(pmu, EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER, false);
+
hwc->state |= PERF_HES_STOPPED;
}
@@ -565,25 +594,10 @@ static void ddr_perf_event_del(struct perf_event *event, int flags)
static void ddr_perf_pmu_enable(struct pmu *pmu)
{
- struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu);
-
- /* enable cycle counter if cycle is not active event list */
- if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL)
- ddr_perf_counter_enable(ddr_pmu,
- EVENT_CYCLES_ID,
- EVENT_CYCLES_COUNTER,
- true);
}
static void ddr_perf_pmu_disable(struct pmu *pmu)
{
- struct ddr_pmu *ddr_pmu = to_ddr_pmu(pmu);
-
- if (ddr_pmu->events[EVENT_CYCLES_COUNTER] == NULL)
- ddr_perf_counter_enable(ddr_pmu,
- EVENT_CYCLES_ID,
- EVENT_CYCLES_COUNTER,
- false);
}
static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base,
diff --git a/drivers/perf/fsl_imx9_ddr_perf.c b/drivers/perf/fsl_imx9_ddr_perf.c
index 71d5b07e3aff..5cf770a1bc31 100644
--- a/drivers/perf/fsl_imx9_ddr_perf.c
+++ b/drivers/perf/fsl_imx9_ddr_perf.c
@@ -7,9 +7,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/perf_event.h>
/* Performance monitor configuration */
diff --git a/drivers/perf/hisilicon/hisi_pcie_pmu.c b/drivers/perf/hisilicon/hisi_pcie_pmu.c
index e10fc7cb9493..5a00adb2de8c 100644
--- a/drivers/perf/hisilicon/hisi_pcie_pmu.c
+++ b/drivers/perf/hisilicon/hisi_pcie_pmu.c
@@ -665,8 +665,8 @@ static int hisi_pcie_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
struct hisi_pcie_pmu *pcie_pmu = hlist_entry_safe(node, struct hisi_pcie_pmu, node);
if (pcie_pmu->on_cpu == -1) {
- pcie_pmu->on_cpu = cpu;
- WARN_ON(irq_set_affinity(pcie_pmu->irq, cpumask_of(cpu)));
+ pcie_pmu->on_cpu = cpumask_local_spread(0, dev_to_node(&pcie_pmu->pdev->dev));
+ WARN_ON(irq_set_affinity(pcie_pmu->irq, cpumask_of(pcie_pmu->on_cpu)));
}
return 0;
@@ -676,14 +676,23 @@ static int hisi_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
{
struct hisi_pcie_pmu *pcie_pmu = hlist_entry_safe(node, struct hisi_pcie_pmu, node);
unsigned int target;
+ cpumask_t mask;
+ int numa_node;
/* Nothing to do if this CPU doesn't own the PMU */
if (pcie_pmu->on_cpu != cpu)
return 0;
pcie_pmu->on_cpu = -1;
- /* Choose a new CPU from all online cpus. */
- target = cpumask_any_but(cpu_online_mask, cpu);
+
+ /* Choose a local CPU from all online cpus. */
+ numa_node = dev_to_node(&pcie_pmu->pdev->dev);
+ if (cpumask_and(&mask, cpumask_of_node(numa_node), cpu_online_mask) &&
+ cpumask_andnot(&mask, &mask, cpumask_of(cpu)))
+ target = cpumask_any(&mask);
+ else
+ target = cpumask_any_but(cpu_online_mask, cpu);
+
if (target >= nr_cpu_ids) {
pci_err(pcie_pmu->pdev, "There is no CPU to set\n");
return 0;
diff --git a/drivers/perf/marvell_cn10k_ddr_pmu.c b/drivers/perf/marvell_cn10k_ddr_pmu.c
index b94a5f6cc22b..524ba82bfce2 100644
--- a/drivers/perf/marvell_cn10k_ddr_pmu.c
+++ b/drivers/perf/marvell_cn10k_ddr_pmu.c
@@ -8,11 +8,10 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/perf_event.h>
#include <linux/hrtimer.h>
#include <linux/acpi.h>
+#include <linux/platform_device.h>
/* Performance Counters Operating Mode Control Registers */
#define DDRC_PERF_CNT_OP_MODE_CTRL 0x8020
diff --git a/drivers/perf/marvell_cn10k_tad_pmu.c b/drivers/perf/marvell_cn10k_tad_pmu.c
index 3972197e2210..fec8e82edb95 100644
--- a/drivers/perf/marvell_cn10k_tad_pmu.c
+++ b/drivers/perf/marvell_cn10k_tad_pmu.c
@@ -6,10 +6,9 @@
#define pr_fmt(fmt) "tad_pmu: " fmt
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/cpuhotplug.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c
index 0c32dffc7ede..9972bfc11a5c 100644
--- a/drivers/perf/xgene_pmu.c
+++ b/drivers/perf/xgene_pmu.c
@@ -1833,7 +1833,6 @@ static int xgene_pmu_probe(struct platform_device *pdev)
const struct xgene_pmu_data *dev_data;
const struct of_device_id *of_id;
struct xgene_pmu *xgene_pmu;
- struct resource *res;
int irq, rc;
int version;
@@ -1883,8 +1882,7 @@ static int xgene_pmu_probe(struct platform_device *pdev)
xgene_pmu->version = version;
dev_info(&pdev->dev, "X-Gene PMU version %d\n", xgene_pmu->version);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- xgene_pmu->pcppmu_csr = devm_ioremap_resource(&pdev->dev, res);
+ xgene_pmu->pcppmu_csr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xgene_pmu->pcppmu_csr)) {
dev_err(&pdev->dev, "ioremap failed for PCP PMU resource\n");
return PTR_ERR(xgene_pmu->pcppmu_csr);
diff --git a/drivers/pinctrl/cirrus/Kconfig b/drivers/pinctrl/cirrus/Kconfig
index 530426a74f75..d6318cb57aff 100644
--- a/drivers/pinctrl/cirrus/Kconfig
+++ b/drivers/pinctrl/cirrus/Kconfig
@@ -1,4 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
+config PINCTRL_CS42L43
+ tristate "Cirrus Logic CS42L43 Pinctrl Driver"
+ depends on MFD_CS42L43
+ select GPIOLIB
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ help
+ Select this to support the GPIO/Pinctrl functions of the Cirrus
+ Logic CS42L43 PC CODEC.
+
config PINCTRL_LOCHNAGAR
tristate "Cirrus Logic Lochnagar pinctrl driver"
depends on MFD_LOCHNAGAR
diff --git a/drivers/pinctrl/cirrus/Makefile b/drivers/pinctrl/cirrus/Makefile
index a484518c840e..9b618d766907 100644
--- a/drivers/pinctrl/cirrus/Makefile
+++ b/drivers/pinctrl/cirrus/Makefile
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
# Cirrus Logic pinctrl drivers
+obj-$(CONFIG_PINCTRL_CS42L43) += pinctrl-cs42l43.o
+
obj-$(CONFIG_PINCTRL_LOCHNAGAR) += pinctrl-lochnagar.o
pinctrl-madera-objs := pinctrl-madera-core.o
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
new file mode 100644
index 000000000000..c09646318419
--- /dev/null
+++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 Pinctrl and GPIO driver
+//
+// Copyright (c) 2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/bits.h>
+#include <linux/build_bug.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/string_helpers.h>
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "../pinctrl-utils.h"
+
+#define CS42L43_NUM_GPIOS 3
+
+struct cs42l43_pin {
+ struct gpio_chip gpio_chip;
+
+ struct device *dev;
+ struct regmap *regmap;
+ bool shutters_locked;
+};
+
+struct cs42l43_pin_data {
+ unsigned int reg;
+ unsigned int shift;
+ unsigned int mask;
+};
+
+#define CS42L43_PIN(_number, _name, _reg, _field) { \
+ .number = _number, .name = _name, \
+ .drv_data = &((struct cs42l43_pin_data){ \
+ .reg = CS42L43_##_reg, \
+ .shift = CS42L43_##_field##_DRV_SHIFT, \
+ .mask = CS42L43_##_field##_DRV_MASK, \
+ }), \
+}
+
+static const struct pinctrl_pin_desc cs42l43_pin_pins[] = {
+ CS42L43_PIN(0, "gpio1", DRV_CTRL4, GPIO1),
+ CS42L43_PIN(1, "gpio2", DRV_CTRL4, GPIO2),
+ CS42L43_PIN(2, "gpio3", DRV_CTRL4, GPIO3),
+ CS42L43_PIN(3, "asp_dout", DRV_CTRL1, ASP_DOUT),
+ CS42L43_PIN(4, "asp_fsync", DRV_CTRL1, ASP_FSYNC),
+ CS42L43_PIN(5, "asp_bclk", DRV_CTRL1, ASP_BCLK),
+ CS42L43_PIN(6, "pdmout2_clk", DRV_CTRL3, PDMOUT2_CLK),
+ CS42L43_PIN(7, "pdmout2_data", DRV_CTRL3, PDMOUT2_DATA),
+ CS42L43_PIN(8, "pdmout1_clk", DRV_CTRL3, PDMOUT1_CLK),
+ CS42L43_PIN(9, "pdmout1_data", DRV_CTRL3, PDMOUT1_DATA),
+ CS42L43_PIN(10, "i2c_sda", DRV_CTRL3, I2C_SDA),
+ CS42L43_PIN(11, "i2c_scl", DRV_CTRL_5, I2C_SCL),
+ CS42L43_PIN(12, "spi_miso", DRV_CTRL3, SPI_MISO),
+ CS42L43_PIN(13, "spi_sck", DRV_CTRL_5, SPI_SCK),
+ CS42L43_PIN(14, "spi_ssb", DRV_CTRL_5, SPI_SSB),
+};
+
+static const unsigned int cs42l43_pin_gpio1_pins[] = { 0 };
+static const unsigned int cs42l43_pin_gpio2_pins[] = { 1 };
+static const unsigned int cs42l43_pin_gpio3_pins[] = { 2 };
+static const unsigned int cs42l43_pin_asp_pins[] = { 3, 4, 5 };
+static const unsigned int cs42l43_pin_pdmout2_pins[] = { 6, 7 };
+static const unsigned int cs42l43_pin_pdmout1_pins[] = { 8, 9 };
+static const unsigned int cs42l43_pin_i2c_pins[] = { 10, 11 };
+static const unsigned int cs42l43_pin_spi_pins[] = { 12, 13, 14 };
+
+#define CS42L43_PINGROUP(_name) \
+ PINCTRL_PINGROUP(#_name, cs42l43_pin_##_name##_pins, \
+ ARRAY_SIZE(cs42l43_pin_##_name##_pins))
+
+static const struct pingroup cs42l43_pin_groups[] = {
+ CS42L43_PINGROUP(gpio1),
+ CS42L43_PINGROUP(gpio2),
+ CS42L43_PINGROUP(gpio3),
+ CS42L43_PINGROUP(asp),
+ CS42L43_PINGROUP(pdmout2),
+ CS42L43_PINGROUP(pdmout1),
+ CS42L43_PINGROUP(i2c),
+ CS42L43_PINGROUP(spi),
+};
+
+static int cs42l43_pin_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(cs42l43_pin_groups);
+}
+
+static const char *cs42l43_pin_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int group_idx)
+{
+ return cs42l43_pin_groups[group_idx].name;
+}
+
+static int cs42l43_pin_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int group_idx,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = cs42l43_pin_groups[group_idx].pins;
+ *num_pins = cs42l43_pin_groups[group_idx].npins;
+
+ return 0;
+}
+
+static const struct pinctrl_ops cs42l43_pin_group_ops = {
+ .get_groups_count = cs42l43_pin_get_groups_count,
+ .get_group_name = cs42l43_pin_get_group_name,
+ .get_group_pins = cs42l43_pin_get_group_pins,
+#if IS_ENABLED(CONFIG_OF)
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+#endif
+};
+
+enum cs42l43_pin_funcs {
+ CS42L43_FUNC_GPIO,
+ CS42L43_FUNC_SPDIF,
+ CS42L43_FUNC_IRQ,
+ CS42L43_FUNC_MIC_SHT,
+ CS42L43_FUNC_SPK_SHT,
+ CS42L43_FUNC_MAX
+};
+
+static const char * const cs42l43_pin_funcs[] = {
+ "gpio", "spdif", "irq", "mic-shutter", "spk-shutter",
+};
+
+static const char * const cs42l43_pin_gpio_groups[] = { "gpio1", "gpio3" };
+static const char * const cs42l43_pin_spdif_groups[] = { "gpio3" };
+static const char * const cs42l43_pin_irq_groups[] = { "gpio1" };
+static const char * const cs42l43_pin_shutter_groups[] = { "gpio1", "gpio2", "gpio3" };
+
+static const struct pinfunction cs42l43_pin_func_groups[] = {
+ PINCTRL_PINFUNCTION("gpio", cs42l43_pin_gpio_groups,
+ ARRAY_SIZE(cs42l43_pin_gpio_groups)),
+ PINCTRL_PINFUNCTION("spdif", cs42l43_pin_spdif_groups,
+ ARRAY_SIZE(cs42l43_pin_spdif_groups)),
+ PINCTRL_PINFUNCTION("irq", cs42l43_pin_irq_groups,
+ ARRAY_SIZE(cs42l43_pin_irq_groups)),
+ PINCTRL_PINFUNCTION("mic-shutter", cs42l43_pin_shutter_groups,
+ ARRAY_SIZE(cs42l43_pin_shutter_groups)),
+ PINCTRL_PINFUNCTION("spk-shutter", cs42l43_pin_shutter_groups,
+ ARRAY_SIZE(cs42l43_pin_shutter_groups)),
+};
+
+static_assert(ARRAY_SIZE(cs42l43_pin_funcs) == CS42L43_FUNC_MAX);
+static_assert(ARRAY_SIZE(cs42l43_pin_func_groups) == CS42L43_FUNC_MAX);
+
+static int cs42l43_pin_get_func_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(cs42l43_pin_funcs);
+}
+
+static const char *cs42l43_pin_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned int func_idx)
+{
+ return cs42l43_pin_funcs[func_idx];
+}
+
+static int cs42l43_pin_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned int func_idx,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ *groups = cs42l43_pin_func_groups[func_idx].groups;
+ *num_groups = cs42l43_pin_func_groups[func_idx].ngroups;
+
+ return 0;
+}
+
+static int cs42l43_pin_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int func_idx, unsigned int group_idx)
+{
+ struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int reg, mask, val;
+
+ dev_dbg(priv->dev, "Setting %s to %s\n",
+ cs42l43_pin_groups[group_idx].name, cs42l43_pin_funcs[func_idx]);
+
+ switch (func_idx) {
+ case CS42L43_FUNC_MIC_SHT:
+ reg = CS42L43_SHUTTER_CONTROL;
+ mask = CS42L43_MIC_SHUTTER_CFG_MASK;
+ val = 0x2 << (group_idx + CS42L43_MIC_SHUTTER_CFG_SHIFT);
+ break;
+ case CS42L43_FUNC_SPK_SHT:
+ reg = CS42L43_SHUTTER_CONTROL;
+ mask = CS42L43_SPK_SHUTTER_CFG_MASK;
+ val = 0x2 << (group_idx + CS42L43_SPK_SHUTTER_CFG_SHIFT);
+ break;
+ default:
+ reg = CS42L43_GPIO_FN_SEL;
+ mask = BIT(group_idx + CS42L43_GPIO1_FN_SEL_SHIFT);
+ val = (func_idx == CS42L43_FUNC_GPIO) ?
+ (0x1 << (group_idx + CS42L43_GPIO1_FN_SEL_SHIFT)) : 0;
+ break;
+ }
+
+ if (priv->shutters_locked && reg == CS42L43_SHUTTER_CONTROL) {
+ dev_err(priv->dev, "Shutter configuration not available\n");
+ return -EPERM;
+ }
+
+ return regmap_update_bits(priv->regmap, reg, mask, val);
+}
+
+static int cs42l43_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset, bool input)
+{
+ struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int shift = offset + CS42L43_GPIO1_DIR_SHIFT;
+ int ret;
+
+ dev_dbg(priv->dev, "Setting gpio%d to %s\n",
+ offset + 1, input ? "input" : "output");
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for direction: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1,
+ BIT(shift), !!input << shift);
+ if (ret)
+ dev_err(priv->dev, "Failed to set gpio%d direction: %d\n",
+ offset + 1, ret);
+
+ pm_runtime_put(priv->dev);
+
+ return ret;
+}
+
+static int cs42l43_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ return cs42l43_pin_set_mux(pctldev, 0, offset);
+}
+
+static void cs42l43_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset)
+{
+ cs42l43_gpio_set_direction(pctldev, range, offset, true);
+}
+
+static const struct pinmux_ops cs42l43_pin_mux_ops = {
+ .get_functions_count = cs42l43_pin_get_func_count,
+ .get_function_name = cs42l43_pin_get_func_name,
+ .get_function_groups = cs42l43_pin_get_func_groups,
+
+ .set_mux = cs42l43_pin_set_mux,
+
+ .gpio_request_enable = cs42l43_gpio_request_enable,
+ .gpio_disable_free = cs42l43_gpio_disable_free,
+ .gpio_set_direction = cs42l43_gpio_set_direction,
+
+ .strict = true,
+};
+
+static const unsigned int cs42l43_pin_drv_str_ma[] = { 1, 2, 4, 8, 9, 10, 12, 16 };
+
+static inline int cs42l43_pin_get_drv_str(struct cs42l43_pin *priv, unsigned int pin)
+{
+ const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(priv->regmap, pdat->reg, &val);
+ if (ret)
+ return ret;
+
+ return cs42l43_pin_drv_str_ma[(val & pdat->mask) >> pdat->shift];
+}
+
+static inline int cs42l43_pin_set_drv_str(struct cs42l43_pin *priv, unsigned int pin,
+ unsigned int ma)
+{
+ const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_pin_drv_str_ma); i++) {
+ if (ma == cs42l43_pin_drv_str_ma[i]) {
+ if ((i << pdat->shift) > pdat->mask)
+ goto err;
+
+ dev_dbg(priv->dev, "Set drive strength for %s to %d mA\n",
+ cs42l43_pin_pins[pin].name, ma);
+
+ return regmap_update_bits(priv->regmap, pdat->reg,
+ pdat->mask, i << pdat->shift);
+ }
+ }
+
+err:
+ dev_err(priv->dev, "Invalid drive strength for %s: %d mA\n",
+ cs42l43_pin_pins[pin].name, ma);
+ return -EINVAL;
+}
+
+static inline int cs42l43_pin_get_db(struct cs42l43_pin *priv, unsigned int pin)
+{
+ unsigned int val;
+ int ret;
+
+ if (pin >= CS42L43_NUM_GPIOS)
+ return -ENOTSUPP;
+
+ ret = regmap_read(priv->regmap, CS42L43_GPIO_CTRL2, &val);
+ if (ret)
+ return ret;
+
+ if (val & (CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin))
+ return 0;
+
+ return 85; // Debounce is roughly 85uS
+}
+
+static inline int cs42l43_pin_set_db(struct cs42l43_pin *priv, unsigned int pin,
+ unsigned int us)
+{
+ if (pin >= CS42L43_NUM_GPIOS)
+ return -ENOTSUPP;
+
+ dev_dbg(priv->dev, "Set debounce %s for %s\n",
+ str_on_off(us), cs42l43_pin_pins[pin].name);
+
+ return regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL2,
+ CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin,
+ !!us << pin);
+}
+
+static int cs42l43_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int param = pinconf_to_config_param(*config);
+ int ret;
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = cs42l43_pin_get_drv_str(priv, pin);
+ if (ret < 0)
+ return ret;
+ break;
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ ret = cs42l43_pin_get_db(priv, pin);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, ret);
+
+ return 0;
+}
+
+static int cs42l43_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int val;
+ int ret;
+
+ while (num_configs) {
+ val = pinconf_to_config_argument(*configs);
+
+ switch (pinconf_to_config_param(*configs)) {
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = cs42l43_pin_set_drv_str(priv, pin, val);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ ret = cs42l43_pin_set_db(priv, pin, val);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ configs++;
+ num_configs--;
+ }
+
+ return 0;
+}
+
+static int cs42l43_pin_config_group_get(struct pinctrl_dev *pctldev,
+ unsigned int selector, unsigned long *config)
+{
+ int i, ret;
+
+ for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) {
+ ret = cs42l43_pin_config_get(pctldev,
+ cs42l43_pin_groups[selector].pins[i],
+ config);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cs42l43_pin_config_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ int i, ret;
+
+ for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) {
+ ret = cs42l43_pin_config_set(pctldev,
+ cs42l43_pin_groups[selector].pins[i],
+ configs, num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops cs42l43_pin_conf_ops = {
+ .is_generic = true,
+
+ .pin_config_get = cs42l43_pin_config_get,
+ .pin_config_set = cs42l43_pin_config_set,
+ .pin_config_group_get = cs42l43_pin_config_group_get,
+ .pin_config_group_set = cs42l43_pin_config_group_set,
+};
+
+static struct pinctrl_desc cs42l43_pin_desc = {
+ .name = "cs42l43-pinctrl",
+ .owner = THIS_MODULE,
+
+ .pins = cs42l43_pin_pins,
+ .npins = ARRAY_SIZE(cs42l43_pin_pins),
+
+ .pctlops = &cs42l43_pin_group_ops,
+ .pmxops = &cs42l43_pin_mux_ops,
+ .confops = &cs42l43_pin_conf_ops,
+};
+
+static int cs42l43_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct cs42l43_pin *priv = gpiochip_get_data(chip);
+ unsigned int val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for get: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(priv->regmap, CS42L43_GPIO_STS, &val);
+ if (ret)
+ dev_err(priv->dev, "Failed to get gpio%d: %d\n", offset + 1, ret);
+ else
+ ret = !!(val & BIT(offset + CS42L43_GPIO1_STS_SHIFT));
+
+ pm_runtime_put(priv->dev);
+
+ return ret;
+}
+
+static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct cs42l43_pin *priv = gpiochip_get_data(chip);
+ unsigned int shift = offset + CS42L43_GPIO1_LVL_SHIFT;
+ int ret;
+
+ dev_dbg(priv->dev, "Setting gpio%d to %s\n",
+ offset + 1, value ? "high" : "low");
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for set: %d\n", ret);
+ return;
+ }
+
+ ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1,
+ BIT(shift), value << shift);
+ if (ret)
+ dev_err(priv->dev, "Failed to set gpio%d: %d\n", offset + 1, ret);
+
+ pm_runtime_put(priv->dev);
+}
+
+static int cs42l43_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
+{
+ return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ cs42l43_gpio_set(chip, offset, value);
+
+ return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static int cs42l43_gpio_add_pin_ranges(struct gpio_chip *chip)
+{
+ struct cs42l43_pin *priv = gpiochip_get_data(chip);
+ int ret;
+
+ ret = gpiochip_add_pin_range(&priv->gpio_chip, priv->gpio_chip.label,
+ 0, 0, CS42L43_NUM_GPIOS);
+ if (ret)
+ dev_err(priv->dev, "Failed to add GPIO pin range: %d\n", ret);
+
+ return ret;
+}
+
+static int cs42l43_pin_probe(struct platform_device *pdev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+ struct cs42l43_pin *priv;
+ struct pinctrl_dev *pctldev;
+ struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->regmap = cs42l43->regmap;
+
+ priv->shutters_locked = cs42l43->hw_lock;
+
+ priv->gpio_chip.request = gpiochip_generic_request;
+ priv->gpio_chip.free = gpiochip_generic_free;
+ priv->gpio_chip.direction_input = cs42l43_gpio_direction_in;
+ priv->gpio_chip.direction_output = cs42l43_gpio_direction_out;
+ priv->gpio_chip.add_pin_ranges = cs42l43_gpio_add_pin_ranges;
+ priv->gpio_chip.get = cs42l43_gpio_get;
+ priv->gpio_chip.set = cs42l43_gpio_set;
+ priv->gpio_chip.label = dev_name(priv->dev);
+ priv->gpio_chip.parent = priv->dev;
+ priv->gpio_chip.can_sleep = true;
+ priv->gpio_chip.base = -1;
+ priv->gpio_chip.ngpio = CS42L43_NUM_GPIOS;
+
+ if (is_of_node(fwnode)) {
+ fwnode = fwnode_get_named_child_node(fwnode, "pinctrl");
+
+ if (fwnode && !fwnode->dev)
+ fwnode->dev = priv->dev;
+ }
+
+ priv->gpio_chip.fwnode = fwnode;
+
+ device_set_node(priv->dev, fwnode);
+
+ devm_pm_runtime_enable(priv->dev);
+ pm_runtime_idle(priv->dev);
+
+ pctldev = devm_pinctrl_register(priv->dev, &cs42l43_pin_desc, priv);
+ if (IS_ERR(pctldev))
+ return dev_err_probe(priv->dev, PTR_ERR(pctldev),
+ "Failed to register pinctrl\n");
+
+ ret = devm_gpiochip_add_data(priv->dev, &priv->gpio_chip, priv);
+ if (ret)
+ return dev_err_probe(priv->dev, ret,
+ "Failed to register gpiochip\n");
+
+ return 0;
+}
+
+static const struct platform_device_id cs42l43_pin_id_table[] = {
+ { "cs42l43-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs42l43_pin_id_table);
+
+static struct platform_driver cs42l43_pin_driver = {
+ .driver = {
+ .name = "cs42l43-pinctrl",
+ },
+ .probe = cs42l43_pin_probe,
+ .id_table = cs42l43_pin_id_table,
+};
+module_platform_driver(cs42l43_pin_driver);
+
+MODULE_DESCRIPTION("CS42L43 Pinctrl Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 4a8c1b57a90d..4dff656af3ad 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -862,6 +862,33 @@ static const struct pinconf_ops amd_pinconf_ops = {
.pin_config_group_set = amd_pinconf_group_set,
};
+static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
+{
+ struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ unsigned long flags;
+ u32 pin_reg, mask;
+ int i;
+
+ mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) |
+ BIT(WAKE_CNTRL_OFF_S4);
+
+ for (i = 0; i < desc->npins; i++) {
+ int pin = desc->pins[i].number;
+ const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin);
+
+ if (!pd)
+ continue;
+
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+
+ pin_reg = readl(gpio_dev->base + pin * 4);
+ pin_reg &= ~mask;
+ writel(pin_reg, gpio_dev->base + pin * 4);
+
+ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+ }
+}
+
#ifdef CONFIG_PM_SLEEP
static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin)
{
@@ -1099,6 +1126,9 @@ static int amd_gpio_probe(struct platform_device *pdev)
return PTR_ERR(gpio_dev->pctrl);
}
+ /* Disable and mask interrupts */
+ amd_gpio_irq_init(gpio_dev);
+
girq = &gpio_dev->gc.irq;
gpio_irq_chip_set_chip(girq, &amd_gpio_irqchip);
/* This will let us handle the parent IRQ in the driver */
diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c
index 40b1326a1077..5591ddf16fdf 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza2.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza2.c
@@ -14,6 +14,7 @@
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinmux.h>
@@ -46,6 +47,7 @@ struct rza2_pinctrl_priv {
struct pinctrl_dev *pctl;
struct pinctrl_gpio_range gpio_range;
int npins;
+ struct mutex mutex; /* serialize adding groups and functions */
};
#define RZA2_PDR(port) (0x0000 + (port) * 2) /* Direction 16-bit */
@@ -358,10 +360,14 @@ static int rza2_dt_node_to_map(struct pinctrl_dev *pctldev,
psel_val[i] = MUX_FUNC(value);
}
+ mutex_lock(&priv->mutex);
+
/* Register a single pin group listing all the pins we read from DT */
gsel = pinctrl_generic_add_group(pctldev, np->name, pins, npins, NULL);
- if (gsel < 0)
- return gsel;
+ if (gsel < 0) {
+ ret = gsel;
+ goto unlock;
+ }
/*
* Register a single group function where the 'data' is an array PSEL
@@ -390,6 +396,8 @@ static int rza2_dt_node_to_map(struct pinctrl_dev *pctldev,
(*map)->data.mux.function = np->name;
*num_maps = 1;
+ mutex_unlock(&priv->mutex);
+
return 0;
remove_function:
@@ -398,6 +406,9 @@ remove_function:
remove_group:
pinctrl_generic_remove_group(pctldev, gsel);
+unlock:
+ mutex_unlock(&priv->mutex);
+
dev_err(priv->dev, "Unable to parse DT node %s\n", np->name);
return ret;
@@ -473,6 +484,8 @@ static int rza2_pinctrl_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
+ mutex_init(&priv->mutex);
+
platform_set_drvdata(pdev, priv);
priv->npins = (int)(uintptr_t)of_device_get_match_data(&pdev->dev) *
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index b53d26167da5..6e8a76556e23 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/seq_file.h>
@@ -149,10 +150,11 @@ struct rzg2l_pinctrl {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
DECLARE_BITMAP(tint_slot, RZG2L_TINT_MAX_INTERRUPT);
- spinlock_t bitmap_lock;
+ spinlock_t bitmap_lock; /* protect tint_slot bitmap */
unsigned int hwirq[RZG2L_TINT_MAX_INTERRUPT];
- spinlock_t lock;
+ spinlock_t lock; /* lock read/write registers */
+ struct mutex mutex; /* serialize adding groups and functions */
};
static const unsigned int iolh_groupa_mA[] = { 2, 4, 8, 12 };
@@ -362,11 +364,13 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
name = np->name;
}
+ mutex_lock(&pctrl->mutex);
+
/* Register a single pin group listing all the pins we read from DT */
gsel = pinctrl_generic_add_group(pctldev, name, pins, num_pinmux, NULL);
if (gsel < 0) {
ret = gsel;
- goto done;
+ goto unlock;
}
/*
@@ -380,6 +384,8 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
goto remove_group;
}
+ mutex_unlock(&pctrl->mutex);
+
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
maps[idx].data.mux.group = name;
maps[idx].data.mux.function = name;
@@ -391,6 +397,8 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
remove_group:
pinctrl_generic_remove_group(pctldev, gsel);
+unlock:
+ mutex_unlock(&pctrl->mutex);
done:
*index = idx;
kfree(configs);
@@ -1509,6 +1517,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
spin_lock_init(&pctrl->lock);
spin_lock_init(&pctrl->bitmap_lock);
+ mutex_init(&pctrl->mutex);
platform_set_drvdata(pdev, pctrl);
diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
index 35b23c1a5684..9146101ea9e2 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
@@ -14,6 +14,7 @@
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
@@ -123,7 +124,8 @@ struct rzv2m_pinctrl {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
- spinlock_t lock;
+ spinlock_t lock; /* lock read/write registers */
+ struct mutex mutex; /* serialize adding groups and functions */
};
static const unsigned int drv_1_8V_group2_uA[] = { 1800, 3800, 7800, 11000 };
@@ -322,11 +324,13 @@ static int rzv2m_dt_subnode_to_map(struct pinctrl_dev *pctldev,
name = np->name;
}
+ mutex_lock(&pctrl->mutex);
+
/* Register a single pin group listing all the pins we read from DT */
gsel = pinctrl_generic_add_group(pctldev, name, pins, num_pinmux, NULL);
if (gsel < 0) {
ret = gsel;
- goto done;
+ goto unlock;
}
/*
@@ -340,6 +344,8 @@ static int rzv2m_dt_subnode_to_map(struct pinctrl_dev *pctldev,
goto remove_group;
}
+ mutex_unlock(&pctrl->mutex);
+
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
maps[idx].data.mux.group = name;
maps[idx].data.mux.function = name;
@@ -351,6 +357,8 @@ static int rzv2m_dt_subnode_to_map(struct pinctrl_dev *pctldev,
remove_group:
pinctrl_generic_remove_group(pctldev, gsel);
+unlock:
+ mutex_unlock(&pctrl->mutex);
done:
*index = idx;
kfree(configs);
@@ -1071,6 +1079,7 @@ static int rzv2m_pinctrl_probe(struct platform_device *pdev)
}
spin_lock_init(&pctrl->lock);
+ mutex_init(&pctrl->mutex);
platform_set_drvdata(pdev, pctrl);
diff --git a/drivers/platform/chrome/chromeos_acpi.c b/drivers/platform/chrome/chromeos_acpi.c
index 50d8a4d4352d..e6e6dcfc74d1 100644
--- a/drivers/platform/chrome/chromeos_acpi.c
+++ b/drivers/platform/chrome/chromeos_acpi.c
@@ -90,7 +90,36 @@ static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *o
case ACPI_TYPE_STRING:
return sysfs_emit(buf, "%s\n", element->string.pointer);
case ACPI_TYPE_BUFFER:
- return sysfs_emit(buf, "%s\n", element->buffer.pointer);
+ {
+ int i, r, at, room_left;
+ const int byte_per_line = 16;
+
+ at = 0;
+ room_left = PAGE_SIZE - 1;
+ for (i = 0; i < element->buffer.length && room_left; i += byte_per_line) {
+ r = hex_dump_to_buffer(element->buffer.pointer + i,
+ element->buffer.length - i,
+ byte_per_line, 1, buf + at, room_left,
+ false);
+ if (r > room_left)
+ goto truncating;
+ at += r;
+ room_left -= r;
+
+ r = sysfs_emit_at(buf, at, "\n");
+ if (!r)
+ goto truncating;
+ at += r;
+ room_left -= r;
+ }
+
+ buf[at] = 0;
+ return at;
+truncating:
+ dev_info_once(dev, "truncating sysfs content for %s\n", name);
+ sysfs_emit_at(buf, PAGE_SIZE - 4, "..\n");
+ return PAGE_SIZE - 1;
+ }
default:
dev_err(dev, "element type %d not supported\n", element->type);
return -EINVAL;
@@ -235,9 +264,9 @@ static int chromeos_acpi_device_probe(struct platform_device *pdev)
return 0;
}
-/* GGL is valid PNP ID of Google. PNP ID can be used with the ACPI devices. */
static const struct acpi_device_id chromeos_device_ids[] = {
{ "GGL0001", 0 },
+ { "GOOG0016", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 500a61b093e4..356572452898 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -327,8 +327,8 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!");
blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev);
kobject_uevent_env(&ec_dev->dev->kobj, KOBJ_CHANGE, (char **)env);
- /* Begin orderly shutdown. Force shutdown after 1 second. */
- hw_protection_shutdown("CrOS EC Panic", 1000);
+ /* Begin orderly shutdown. EC will force reset after a short period. */
+ hw_protection_shutdown("CrOS EC Panic", -1);
/* Do not query for other events after a panic is reported */
return;
}
diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c
index a79318e90a13..b600b77d91ef 100644
--- a/drivers/platform/mellanox/mlxbf-tmfifo.c
+++ b/drivers/platform/mellanox/mlxbf-tmfifo.c
@@ -887,6 +887,7 @@ static bool mlxbf_tmfifo_virtio_notify(struct virtqueue *vq)
tm_vdev = fifo->vdev[VIRTIO_ID_CONSOLE];
mlxbf_tmfifo_console_output(tm_vdev, vring);
spin_unlock_irqrestore(&fifo->spin_lock[0], flags);
+ set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events);
} else if (test_and_set_bit(MLXBF_TM_TX_LWM_IRQ,
&fifo->pend_events)) {
return true;
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 62b71e8e3567..ff1b70269ccb 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1394,7 +1394,7 @@ static int eeepc_acpi_add(struct acpi_device *device)
* and machine-specific scripts find the fixed name convenient. But
* It's also good for us to exclude multiple instances because both
* our hwmon and our wlan rfkill subdevice use global ACPI objects
- * (the EC and the wlan PCI slot respectively).
+ * (the EC and the PCI wlan slot respectively).
*/
result = eeepc_platform_init(eeepc);
if (result)
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index d2fee9a3e239..6d9297c1d96c 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1049,6 +1049,11 @@ static const struct key_entry ideapad_keymap[] = {
{ KE_IGNORE, 0x03 | IDEAPAD_WMI_KEY },
/* Customizable Lenovo Hotkey ("star" with 'S' inside) */
{ KE_KEY, 0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } },
+ { KE_KEY, 0x04 | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } },
+ /* Lenovo Support */
+ { KE_KEY, 0x07 | IDEAPAD_WMI_KEY, { KEY_HELP } },
+ { KE_KEY, 0x0e | IDEAPAD_WMI_KEY, { KEY_PICKUP_PHONE } },
+ { KE_KEY, 0x0f | IDEAPAD_WMI_KEY, { KEY_HANGUP_PHONE } },
/* Dark mode toggle */
{ KE_KEY, 0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
/* Sound profile switch */
diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index e6ae8265f3a3..cefd0d886cfd 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -3,7 +3,7 @@
#include <linux/firmware.h>
#include <asm/cpu.h>
-#include <asm/microcode_intel.h>
+#include <asm/microcode.h>
#include "ifs.h"
@@ -56,12 +56,13 @@ struct metadata_header {
static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_type)
{
+ struct microcode_header_intel *hdr = &((struct microcode_intel *)ucode)->hdr;
struct metadata_header *meta_header;
unsigned long data_size, total_meta;
unsigned long meta_size = 0;
- data_size = get_datasize(ucode);
- total_meta = ((struct microcode_intel *)ucode)->hdr.metasize;
+ data_size = intel_microcode_get_datasize(hdr);
+ total_meta = hdr->metasize;
if (!total_meta)
return NULL;
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index 5a36b3f77bc5..84c175b9721a 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -1123,7 +1123,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, icl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, tgl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, tgl_core_init),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, tgl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, tgl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, adl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, tgl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, adl_core_init),
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
index a95004e3d80b..08df9494603c 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
@@ -720,7 +720,7 @@ static struct miscdevice isst_if_char_driver = {
static const struct x86_cpu_id hpm_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(SIERRAFOREST_X, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT_X, NULL),
{}
};
diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c
index f360370d5002..e1fbc35504d4 100644
--- a/drivers/platform/x86/lenovo-ymc.c
+++ b/drivers/platform/x86/lenovo-ymc.c
@@ -36,6 +36,13 @@ static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
},
},
+ {
+ /* Lenovo Yoga 7 14ACN6 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
+ },
+ },
{ }
};
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 38928ff7472b..6ab272c84b7b 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -254,6 +254,9 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
else
strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
+ /* Handle possible string truncation */
+ dev->name[sizeof(dev->name) - 1] = '\0';
+
if (dev->active)
pnpacpi_parse_allocated_resource(dev);
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index fff07b2bd77b..59e1ebb7842e 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -148,13 +148,6 @@ config POWER_RESET_ODROID_GO_ULTRA_POWEROFF
help
This driver supports Power off for Odroid Go Ultra device.
-config POWER_RESET_OXNAS
- bool "OXNAS SoC restart driver"
- depends on ARCH_OXNAS
- default MACH_OX820
- help
- Restart support for OXNAS/PLXTECH OX820 SoC.
-
config POWER_RESET_PIIX4_POWEROFF
tristate "Intel PIIX4 power-off driver"
depends on PCI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index d763e6735ee3..a95d1bd275d1 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_LINKSTATION) += linkstation-poweroff.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
-obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
obj-$(CONFIG_POWER_RESET_ODROID_GO_ULTRA_POWEROFF) += odroid-go-ultra-poweroff.o
diff --git a/drivers/power/reset/as3722-poweroff.c b/drivers/power/reset/as3722-poweroff.c
index 80edff1a556f..829e0dba2fda 100644
--- a/drivers/power/reset/as3722-poweroff.c
+++ b/drivers/power/reset/as3722-poweroff.c
@@ -10,7 +10,6 @@
#include <linux/mfd/as3722.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c
index 9e74e131c675..dd5399785b69 100644
--- a/drivers/power/reset/at91-poweroff.c
+++ b/drivers/power/reset/at91-poweroff.c
@@ -151,13 +151,11 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
static int __init at91_poweroff_probe(struct platform_device *pdev)
{
- struct resource *res;
struct device_node *np;
u32 ddr_type;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- at91_shdwc.shdwc_base = devm_ioremap_resource(&pdev->dev, res);
+ at91_shdwc.shdwc_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(at91_shdwc.shdwc_base))
return PTR_ERR(at91_shdwc.shdwc_base);
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index d6884841a6dc..aa9b012d3d00 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/reset-controller.h>
+#include <linux/power/power_on_reason.h>
#include <soc/at91/at91sam9_ddrsdr.h>
#include <soc/at91/at91sam9_sdramc.h>
@@ -149,44 +150,54 @@ static int at91_reset(struct notifier_block *this, unsigned long mode,
return NOTIFY_DONE;
}
-static const char * __init at91_reset_reason(struct at91_reset *reset)
+static const char *at91_reset_reason(struct at91_reset *reset)
{
u32 reg = readl(reset->rstc_base + AT91_RSTC_SR);
const char *reason;
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
case RESET_TYPE_GENERAL:
- reason = "general reset";
+ reason = POWER_ON_REASON_REGULAR;
break;
case RESET_TYPE_WAKEUP:
- reason = "wakeup";
+ reason = POWER_ON_REASON_RTC;
break;
case RESET_TYPE_WATCHDOG:
- reason = "watchdog reset";
+ reason = POWER_ON_REASON_WATCHDOG;
break;
case RESET_TYPE_SOFTWARE:
- reason = "software reset";
+ reason = POWER_ON_REASON_SOFTWARE;
break;
case RESET_TYPE_USER:
- reason = "user reset";
+ reason = POWER_ON_REASON_RST_BTN;
break;
case RESET_TYPE_CPU_FAIL:
- reason = "CPU clock failure detection";
+ reason = POWER_ON_REASON_CPU_CLK_FAIL;
break;
case RESET_TYPE_XTAL_FAIL:
- reason = "32.768 kHz crystal failure detection";
+ reason = POWER_ON_REASON_XTAL_FAIL;
break;
case RESET_TYPE_ULP2:
- reason = "ULP2 reset";
+ reason = POWER_ON_REASON_BROWN_OUT;
break;
default:
- reason = "unknown reset";
+ reason = POWER_ON_REASON_UNKNOWN;
break;
}
return reason;
}
+static ssize_t power_on_reason_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct at91_reset *reset = platform_get_drvdata(pdev);
+
+ return sprintf(buf, "%s\n", at91_reset_reason(reset));
+}
+static DEVICE_ATTR_RO(power_on_reason);
+
static const struct of_device_id at91_ramc_of_match[] = {
{
.compatible = "atmel,at91sam9260-sdramc",
@@ -391,6 +402,12 @@ static int __init at91_reset_probe(struct platform_device *pdev)
if (ret)
goto disable_clk;
+ ret = device_create_file(&pdev->dev, &dev_attr_power_on_reason);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not create sysfs entry\n");
+ return ret;
+ }
+
dev_info(&pdev->dev, "Starting after %s\n", at91_reset_reason(reset));
return 0;
diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c
index d8ecffe72f16..e76b102b57b1 100644
--- a/drivers/power/reset/at91-sama5d2_shdwc.c
+++ b/drivers/power/reset/at91-sama5d2_shdwc.c
@@ -331,7 +331,6 @@ static const struct of_device_id at91_pmc_ids[] = {
static int __init at91_shdwc_probe(struct platform_device *pdev)
{
- struct resource *res;
const struct of_device_id *match;
struct device_node *np;
u32 ddr_type;
@@ -349,8 +348,7 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, at91_shdwc);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- at91_shdwc->shdwc_base = devm_ioremap_resource(&pdev->dev, res);
+ at91_shdwc->shdwc_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(at91_shdwc->shdwc_base))
return PTR_ERR(at91_shdwc->shdwc_base);
diff --git a/drivers/power/reset/brcm-kona-reset.c b/drivers/power/reset/brcm-kona-reset.c
index 3de024e3ceb7..d05728b1db09 100644
--- a/drivers/power/reset/brcm-kona-reset.c
+++ b/drivers/power/reset/brcm-kona-reset.c
@@ -2,8 +2,8 @@
// Copyright (C) 2016 Broadcom
#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#include <linux/reboot.h>
#define RSTMGR_REG_WR_ACCESS_OFFSET 0
@@ -38,9 +38,7 @@ static struct notifier_block kona_reset_nb = {
static int kona_reset_probe(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- kona_reset_base = devm_ioremap_resource(&pdev->dev, res);
+ kona_reset_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(kona_reset_base))
return PTR_ERR(kona_reset_base);
diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c
index b7f7a8225f22..d309b610142c 100644
--- a/drivers/power/reset/gemini-poweroff.c
+++ b/drivers/power/reset/gemini-poweroff.c
@@ -91,7 +91,6 @@ static void gemini_poweroff(void)
static int gemini_poweroff_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct resource *res;
struct gemini_powercon *gpw;
u32 val;
int irq;
@@ -101,8 +100,7 @@ static int gemini_poweroff_probe(struct platform_device *pdev)
if (!gpw)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gpw->base = devm_ioremap_resource(dev, res);
+ gpw->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gpw->base))
return PTR_ERR(gpw->base);
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
index 84b3c3528afa..b28f24da1b3c 100644
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -11,8 +11,9 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_platform.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#define DEFAULT_TIMEOUT_MS 3000
diff --git a/drivers/power/reset/gpio-restart.c b/drivers/power/reset/gpio-restart.c
index a479d3536eb1..3aa19765772d 100644
--- a/drivers/power/reset/gpio-restart.c
+++ b/drivers/power/reset/gpio-restart.c
@@ -12,8 +12,8 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_platform.h>
#include <linux/module.h>
+#include <linux/of.h>
struct gpio_restart {
struct gpio_desc *reset_gpio;
diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c
index 83a4e1c9bf94..dbc4ff61cd74 100644
--- a/drivers/power/reset/keystone-reset.c
+++ b/drivers/power/reset/keystone-reset.c
@@ -10,10 +10,11 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/notifier.h>
+#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#define RSTYPE_RG 0x0
#define RSCTRL_RG 0x4
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index 0c439f83bf65..b9a401bd280b 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -35,11 +35,7 @@ static void do_msm_poweroff(void)
static int msm_restart_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct resource *mem;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- msm_ps_hold = devm_ioremap_resource(dev, mem);
+ msm_ps_hold = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(msm_ps_hold))
return PTR_ERR(msm_ps_hold);
diff --git a/drivers/power/reset/ocelot-reset.c b/drivers/power/reset/ocelot-reset.c
index 8caa90cb58fc..56be64decf54 100644
--- a/drivers/power/reset/ocelot-reset.c
+++ b/drivers/power/reset/ocelot-reset.c
@@ -8,10 +8,10 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/notifier.h>
+#include <linux/mod_devicetable.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
@@ -69,8 +69,6 @@ static int ocelot_restart_handle(struct notifier_block *this,
static int ocelot_reset_probe(struct platform_device *pdev)
{
struct ocelot_reset_context *ctx;
- struct resource *res;
-
struct device *dev = &pdev->dev;
int err;
@@ -78,8 +76,7 @@ static int ocelot_reset_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->base = devm_ioremap_resource(dev, res);
+ ctx->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctx->base))
return PTR_ERR(ctx->base);
diff --git a/drivers/power/reset/odroid-go-ultra-poweroff.c b/drivers/power/reset/odroid-go-ultra-poweroff.c
index f46271da4e8e..9cac7aef77f0 100644
--- a/drivers/power/reset/odroid-go-ultra-poweroff.c
+++ b/drivers/power/reset/odroid-go-ultra-poweroff.c
@@ -4,7 +4,8 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/mfd/rk808.h>
#include <linux/regmap.h>
#include <linux/module.h>
diff --git a/drivers/power/reset/oxnas-restart.c b/drivers/power/reset/oxnas-restart.c
deleted file mode 100644
index 13090bec058a..000000000000
--- a/drivers/power/reset/oxnas-restart.c
+++ /dev/null
@@ -1,233 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0)
-/*
- * oxnas SoC reset driver
- * based on:
- * Microsemi MIPS SoC reset driver
- * and ox820_assert_system_reset() written by Ma Hajun <mahaijuns@gmail.com>
- *
- * Copyright (c) 2013 Ma Hajun <mahaijuns@gmail.com>
- * Copyright (c) 2017 Microsemi Corporation
- * Copyright (c) 2020 Daniel Golle <daniel@makrotopia.org>
- */
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/notifier.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/reboot.h>
-#include <linux/regmap.h>
-
-/* bit numbers of reset control register */
-#define OX820_SYS_CTRL_RST_SCU 0
-#define OX820_SYS_CTRL_RST_COPRO 1
-#define OX820_SYS_CTRL_RST_ARM0 2
-#define OX820_SYS_CTRL_RST_ARM1 3
-#define OX820_SYS_CTRL_RST_USBHS 4
-#define OX820_SYS_CTRL_RST_USBHSPHYA 5
-#define OX820_SYS_CTRL_RST_MACA 6
-#define OX820_SYS_CTRL_RST_MAC OX820_SYS_CTRL_RST_MACA
-#define OX820_SYS_CTRL_RST_PCIEA 7
-#define OX820_SYS_CTRL_RST_SGDMA 8
-#define OX820_SYS_CTRL_RST_CIPHER 9
-#define OX820_SYS_CTRL_RST_DDR 10
-#define OX820_SYS_CTRL_RST_SATA 11
-#define OX820_SYS_CTRL_RST_SATA_LINK 12
-#define OX820_SYS_CTRL_RST_SATA_PHY 13
-#define OX820_SYS_CTRL_RST_PCIEPHY 14
-#define OX820_SYS_CTRL_RST_STATIC 15
-#define OX820_SYS_CTRL_RST_GPIO 16
-#define OX820_SYS_CTRL_RST_UART1 17
-#define OX820_SYS_CTRL_RST_UART2 18
-#define OX820_SYS_CTRL_RST_MISC 19
-#define OX820_SYS_CTRL_RST_I2S 20
-#define OX820_SYS_CTRL_RST_SD 21
-#define OX820_SYS_CTRL_RST_MACB 22
-#define OX820_SYS_CTRL_RST_PCIEB 23
-#define OX820_SYS_CTRL_RST_VIDEO 24
-#define OX820_SYS_CTRL_RST_DDR_PHY 25
-#define OX820_SYS_CTRL_RST_USBHSPHYB 26
-#define OX820_SYS_CTRL_RST_USBDEV 27
-#define OX820_SYS_CTRL_RST_ARMDBG 29
-#define OX820_SYS_CTRL_RST_PLLA 30
-#define OX820_SYS_CTRL_RST_PLLB 31
-
-/* bit numbers of clock control register */
-#define OX820_SYS_CTRL_CLK_COPRO 0
-#define OX820_SYS_CTRL_CLK_DMA 1
-#define OX820_SYS_CTRL_CLK_CIPHER 2
-#define OX820_SYS_CTRL_CLK_SD 3
-#define OX820_SYS_CTRL_CLK_SATA 4
-#define OX820_SYS_CTRL_CLK_I2S 5
-#define OX820_SYS_CTRL_CLK_USBHS 6
-#define OX820_SYS_CTRL_CLK_MACA 7
-#define OX820_SYS_CTRL_CLK_MAC OX820_SYS_CTRL_CLK_MACA
-#define OX820_SYS_CTRL_CLK_PCIEA 8
-#define OX820_SYS_CTRL_CLK_STATIC 9
-#define OX820_SYS_CTRL_CLK_MACB 10
-#define OX820_SYS_CTRL_CLK_PCIEB 11
-#define OX820_SYS_CTRL_CLK_REF600 12
-#define OX820_SYS_CTRL_CLK_USBDEV 13
-#define OX820_SYS_CTRL_CLK_DDR 14
-#define OX820_SYS_CTRL_CLK_DDRPHY 15
-#define OX820_SYS_CTRL_CLK_DDRCK 16
-
-/* Regmap offsets */
-#define OX820_CLK_SET_REGOFFSET 0x2c
-#define OX820_CLK_CLR_REGOFFSET 0x30
-#define OX820_RST_SET_REGOFFSET 0x34
-#define OX820_RST_CLR_REGOFFSET 0x38
-#define OX820_SECONDARY_SEL_REGOFFSET 0x14
-#define OX820_TERTIARY_SEL_REGOFFSET 0x8c
-#define OX820_QUATERNARY_SEL_REGOFFSET 0x94
-#define OX820_DEBUG_SEL_REGOFFSET 0x9c
-#define OX820_ALTERNATIVE_SEL_REGOFFSET 0xa4
-#define OX820_PULLUP_SEL_REGOFFSET 0xac
-#define OX820_SEC_SECONDARY_SEL_REGOFFSET 0x100014
-#define OX820_SEC_TERTIARY_SEL_REGOFFSET 0x10008c
-#define OX820_SEC_QUATERNARY_SEL_REGOFFSET 0x100094
-#define OX820_SEC_DEBUG_SEL_REGOFFSET 0x10009c
-#define OX820_SEC_ALTERNATIVE_SEL_REGOFFSET 0x1000a4
-#define OX820_SEC_PULLUP_SEL_REGOFFSET 0x1000ac
-
-struct oxnas_restart_context {
- struct regmap *sys_ctrl;
- struct notifier_block restart_handler;
-};
-
-static int ox820_restart_handle(struct notifier_block *this,
- unsigned long mode, void *cmd)
-{
- struct oxnas_restart_context *ctx = container_of(this, struct
- oxnas_restart_context,
- restart_handler);
- u32 value;
-
- /*
- * Assert reset to cores as per power on defaults
- * Don't touch the DDR interface as things will come to an impromptu
- * stop NB Possibly should be asserting reset for PLLB, but there are
- * timing concerns here according to the docs
- */
- value = BIT(OX820_SYS_CTRL_RST_COPRO) |
- BIT(OX820_SYS_CTRL_RST_USBHS) |
- BIT(OX820_SYS_CTRL_RST_USBHSPHYA) |
- BIT(OX820_SYS_CTRL_RST_MACA) |
- BIT(OX820_SYS_CTRL_RST_PCIEA) |
- BIT(OX820_SYS_CTRL_RST_SGDMA) |
- BIT(OX820_SYS_CTRL_RST_CIPHER) |
- BIT(OX820_SYS_CTRL_RST_SATA) |
- BIT(OX820_SYS_CTRL_RST_SATA_LINK) |
- BIT(OX820_SYS_CTRL_RST_SATA_PHY) |
- BIT(OX820_SYS_CTRL_RST_PCIEPHY) |
- BIT(OX820_SYS_CTRL_RST_STATIC) |
- BIT(OX820_SYS_CTRL_RST_UART1) |
- BIT(OX820_SYS_CTRL_RST_UART2) |
- BIT(OX820_SYS_CTRL_RST_MISC) |
- BIT(OX820_SYS_CTRL_RST_I2S) |
- BIT(OX820_SYS_CTRL_RST_SD) |
- BIT(OX820_SYS_CTRL_RST_MACB) |
- BIT(OX820_SYS_CTRL_RST_PCIEB) |
- BIT(OX820_SYS_CTRL_RST_VIDEO) |
- BIT(OX820_SYS_CTRL_RST_USBHSPHYB) |
- BIT(OX820_SYS_CTRL_RST_USBDEV);
-
- regmap_write(ctx->sys_ctrl, OX820_RST_SET_REGOFFSET, value);
-
- /* Release reset to cores as per power on defaults */
- regmap_write(ctx->sys_ctrl, OX820_RST_CLR_REGOFFSET,
- BIT(OX820_SYS_CTRL_RST_GPIO));
-
- /*
- * Disable clocks to cores as per power-on defaults - must leave DDR
- * related clocks enabled otherwise we'll stop rather abruptly.
- */
- value = BIT(OX820_SYS_CTRL_CLK_COPRO) |
- BIT(OX820_SYS_CTRL_CLK_DMA) |
- BIT(OX820_SYS_CTRL_CLK_CIPHER) |
- BIT(OX820_SYS_CTRL_CLK_SD) |
- BIT(OX820_SYS_CTRL_CLK_SATA) |
- BIT(OX820_SYS_CTRL_CLK_I2S) |
- BIT(OX820_SYS_CTRL_CLK_USBHS) |
- BIT(OX820_SYS_CTRL_CLK_MAC) |
- BIT(OX820_SYS_CTRL_CLK_PCIEA) |
- BIT(OX820_SYS_CTRL_CLK_STATIC) |
- BIT(OX820_SYS_CTRL_CLK_MACB) |
- BIT(OX820_SYS_CTRL_CLK_PCIEB) |
- BIT(OX820_SYS_CTRL_CLK_REF600) |
- BIT(OX820_SYS_CTRL_CLK_USBDEV);
-
- regmap_write(ctx->sys_ctrl, OX820_CLK_CLR_REGOFFSET, value);
-
- /* Enable clocks to cores as per power-on defaults */
-
- /* Set sys-control pin mux'ing as per power-on defaults */
- regmap_write(ctx->sys_ctrl, OX820_SECONDARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_TERTIARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_QUATERNARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_DEBUG_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_ALTERNATIVE_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_PULLUP_SEL_REGOFFSET, 0);
-
- regmap_write(ctx->sys_ctrl, OX820_SEC_SECONDARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_SEC_TERTIARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_SEC_QUATERNARY_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_SEC_DEBUG_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_SEC_ALTERNATIVE_SEL_REGOFFSET, 0);
- regmap_write(ctx->sys_ctrl, OX820_SEC_PULLUP_SEL_REGOFFSET, 0);
-
- /*
- * No need to save any state, as the ROM loader can determine whether
- * reset is due to power cycling or programatic action, just hit the
- * (self-clearing) CPU reset bit of the block reset register
- */
- value =
- BIT(OX820_SYS_CTRL_RST_SCU) |
- BIT(OX820_SYS_CTRL_RST_ARM0) |
- BIT(OX820_SYS_CTRL_RST_ARM1);
-
- regmap_write(ctx->sys_ctrl, OX820_RST_SET_REGOFFSET, value);
-
- pr_emerg("Unable to restart system\n");
- return NOTIFY_DONE;
-}
-
-static int ox820_restart_probe(struct platform_device *pdev)
-{
- struct oxnas_restart_context *ctx;
- struct regmap *sys_ctrl;
- struct device *dev = &pdev->dev;
- int err = 0;
-
- sys_ctrl = syscon_node_to_regmap(pdev->dev.of_node);
- if (IS_ERR(sys_ctrl))
- return PTR_ERR(sys_ctrl);
-
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- ctx->sys_ctrl = sys_ctrl;
- ctx->restart_handler.notifier_call = ox820_restart_handle;
- ctx->restart_handler.priority = 192;
- err = register_restart_handler(&ctx->restart_handler);
- if (err)
- dev_err(dev, "can't register restart notifier (err=%d)\n", err);
-
- return err;
-}
-
-static const struct of_device_id ox820_restart_of_match[] = {
- { .compatible = "oxsemi,ox820-sys-ctrl" },
- {}
-};
-
-static struct platform_driver ox820_restart_driver = {
- .probe = ox820_restart_probe,
- .driver = {
- .name = "ox820-chip-reset",
- .of_match_table = ox820_restart_of_match,
- },
-};
-builtin_platform_driver(ox820_restart_driver);
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
index 5ccaacffab54..56ba21873882 100644
--- a/drivers/power/reset/st-poweroff.c
+++ b/drivers/power/reset/st-poweroff.c
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/reboot.h>
diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c
index ed58bdf41e27..430d440d55c6 100644
--- a/drivers/power/reset/syscon-poweroff.c
+++ b/drivers/power/reset/syscon-poweroff.c
@@ -10,8 +10,7 @@
#include <linux/io.h>
#include <linux/notifier.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h>
diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c
index 45e34e6885f7..4d622c19bc48 100644
--- a/drivers/power/reset/syscon-reboot.c
+++ b/drivers/power/reset/syscon-reboot.c
@@ -9,8 +9,7 @@
#include <linux/io.h>
#include <linux/notifier.h>
#include <linux/mfd/syscon.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
index 0b0d2fd2bd0c..3260bd93158e 100644
--- a/drivers/power/reset/xgene-reboot.c
+++ b/drivers/power/reset/xgene-reboot.c
@@ -13,7 +13,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/notifier.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c
index 57e50208d537..19a118633115 100644
--- a/drivers/power/supply/axp20x_ac_power.c
+++ b/drivers/power/supply/axp20x_ac_power.c
@@ -13,7 +13,6 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
index 9106077c0dbb..6ac5c80cfda2 100644
--- a/drivers/power/supply/axp20x_battery.c
+++ b/drivers/power/supply/axp20x_battery.c
@@ -22,7 +22,6 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c
index 51c3f9b6458d..bde17406c130 100644
--- a/drivers/power/supply/axp20x_usb_power.c
+++ b/drivers/power/supply/axp20x_usb_power.c
@@ -15,7 +15,6 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/supply/bd99954-charger.c b/drivers/power/supply/bd99954-charger.c
index 086dcf4033c1..1ed1d9f99fb3 100644
--- a/drivers/power/supply/bd99954-charger.c
+++ b/drivers/power/supply/bd99954-charger.c
@@ -536,7 +536,7 @@ static irqreturn_t bd9995x_irq_handler_thread(int irq, void *private)
for_each_set_bit(i, &tmp, 7) {
int sub_status, sub_mask;
- int sub_status_reg[] = {
+ static const int sub_status_reg[] = {
INT1_STATUS, INT2_STATUS, INT3_STATUS, INT4_STATUS,
INT5_STATUS, INT6_STATUS, INT7_STATUS,
};
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index ef8235848f56..3f99cb9590ba 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -965,7 +965,7 @@ static int bq24190_charger_get_precharge(struct bq24190_dev_info *bdi,
union power_supply_propval *val)
{
u8 v;
- int ret;
+ int curr, ret;
ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC,
BQ24190_REG_PCTCC_IPRECHG_MASK,
@@ -973,7 +973,20 @@ static int bq24190_charger_get_precharge(struct bq24190_dev_info *bdi,
if (ret < 0)
return ret;
- val->intval = ++v * 128 * 1000;
+ curr = ++v * 128 * 1000;
+
+ ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+ BQ24190_REG_CCC_FORCE_20PCT_MASK,
+ BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
+ if (ret < 0)
+ return ret;
+
+ /* If FORCE_20PCT is enabled, then current is 50% of IPRECHG value */
+ if (v)
+ curr /= 2;
+
+ val->intval = curr;
+
return 0;
}
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index d98d9244e394..5dd76c0ac98d 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -15,7 +15,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/reboot.h>
diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c
index a87aeaea38e1..27f897067aa3 100644
--- a/drivers/power/supply/da9150-charger.c
+++ b/drivers/power/supply/da9150-charger.c
@@ -11,8 +11,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
#include <linux/notifier.h>
diff --git a/drivers/power/supply/da9150-fg.c b/drivers/power/supply/da9150-fg.c
index 8c5e2c49d6c1..652c1f213af1 100644
--- a/drivers/power/supply/da9150-fg.c
+++ b/drivers/power/supply/da9150-fg.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c
index ccb00be38e2c..9085de0ae1b2 100644
--- a/drivers/power/supply/lego_ev3_battery.c
+++ b/drivers/power/supply/lego_ev3_battery.c
@@ -20,7 +20,7 @@
#include <linux/iio/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/supply/ltc2941-battery-gauge.c b/drivers/power/supply/ltc2941-battery-gauge.c
index cad39a8f829d..a1ddc4b060ce 100644
--- a/drivers/power/supply/ltc2941-battery-gauge.c
+++ b/drivers/power/supply/ltc2941-battery-gauge.c
@@ -11,7 +11,7 @@
#include <linux/devm-helpers.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/swab.h>
diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c
index ec5b4a20ad43..f0eace731480 100644
--- a/drivers/power/supply/ltc4162-l-charger.c
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -6,7 +6,7 @@
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>
#include <linux/i2c.h>
diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c
index fbdf12cf64eb..89f2af72dfcd 100644
--- a/drivers/power/supply/max14656_charger_detector.c
+++ b/drivers/power/supply/max14656_charger_detector.c
@@ -14,8 +14,8 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
#include <linux/devm-helpers.h>
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 22ea7de47a53..ff42db672899 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -15,7 +15,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/power_supply.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>
diff --git a/drivers/power/supply/max8903_charger.c b/drivers/power/supply/max8903_charger.c
index 54d50b55fbae..e65d0141f260 100644
--- a/drivers/power/supply/max8903_charger.c
+++ b/drivers/power/supply/max8903_charger.c
@@ -10,7 +10,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include <linux/platform_device.h>
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 3791aec69ddc..4aa466c945e2 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1305,8 +1305,12 @@ static int psy_register_thermal(struct power_supply *psy)
/* Register battery zone device psy reports temperature */
if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_TEMP)) {
+ /* Prefer our hwmon device and avoid duplicates */
+ struct thermal_zone_params tzp = {
+ .no_hwmon = IS_ENABLED(CONFIG_POWER_SUPPLY_HWMON)
+ };
psy->tzd = thermal_zone_device_register(psy->desc->name,
- 0, 0, psy, &psy_tzd_ops, NULL, 0, 0);
+ 0, 0, psy, &psy_tzd_ops, &tzp, 0, 0);
if (IS_ERR(psy->tzd))
return PTR_ERR(psy->tzd);
ret = thermal_zone_device_enable(psy->tzd);
diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c
index d16c5ee17249..10f4dd0caca1 100644
--- a/drivers/power/supply/qcom_pmi8998_charger.c
+++ b/drivers/power/supply/qcom_pmi8998_charger.c
@@ -409,8 +409,6 @@ static enum power_supply_property smb2_properties[] = {
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_USB_TYPE,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
};
static enum power_supply_usb_type smb2_usb_types[] = {
@@ -519,9 +517,9 @@ static int smb2_get_prop_status(struct smb2_chip *chip, int *val)
*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
return rc;
case TERMINATE_CHARGE:
+ case INHIBIT_CHARGE:
*val = POWER_SUPPLY_STATUS_FULL;
return rc;
- case INHIBIT_CHARGE:
default:
*val = POWER_SUPPLY_STATUS_UNKNOWN;
return rc;
@@ -556,7 +554,8 @@ static int smb2_set_current_limit(struct smb2_chip *chip, unsigned int val)
static void smb2_status_change_work(struct work_struct *work)
{
unsigned int charger_type, current_ua;
- int usb_online, count, rc;
+ int usb_online = 0;
+ int count, rc;
struct smb2_chip *chip;
chip = container_of(work, struct smb2_chip, status_change_work.work);
@@ -673,11 +672,7 @@ static int smb2_get_property(struct power_supply *psy,
val->strval = chip->name;
return 0;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return smb2_get_current_limit(chip, &val->intval);
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
- val->intval = DCP_CURRENT_UA;
- return 0;
case POWER_SUPPLY_PROP_CURRENT_NOW:
return smb2_get_iio_chan(chip, chip->usb_in_i_chan,
&val->intval);
@@ -706,7 +701,6 @@ static int smb2_set_property(struct power_supply *psy,
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return smb2_set_current_limit(chip, val->intval);
default:
dev_err(chip->dev, "No setter for property: %d\n", psp);
@@ -719,7 +713,6 @@ static int smb2_property_is_writable(struct power_supply *psy,
{
switch (psp) {
case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return 1;
default:
return 0;
diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c
index a5e09ac78a50..ebea3522a2ac 100644
--- a/drivers/power/supply/rn5t618_power.c
+++ b/drivers/power/supply/rn5t618_power.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mfd/rn5t618.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c
index 5218dfbf5e1b..c0c516f22c66 100644
--- a/drivers/power/supply/rt5033_charger.c
+++ b/drivers/power/supply/rt5033_charger.c
@@ -6,8 +6,8 @@
* Author: Beomho Seo <beomho.seo@samsung.com>
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
diff --git a/drivers/power/supply/rt9455_charger.c b/drivers/power/supply/rt9455_charger.c
index ff4dcf77c788..c345a77f9f78 100644
--- a/drivers/power/supply/rt9455_charger.c
+++ b/drivers/power/supply/rt9455_charger.c
@@ -8,8 +8,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>
#include <linux/i2c.h>
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 62a354e01204..cdfc8466d129 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -16,7 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/power/sbs-battery.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c
index 0990b2fa6cd8..f96c705e0a9f 100644
--- a/drivers/power/supply/tps65090-charger.c
+++ b/drivers/power/supply/tps65090-charger.c
@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c
index a4bc9f2a10bc..96341cbde4fa 100644
--- a/drivers/power/supply/tps65217_charger.c
+++ b/drivers/power/supply/tps65217_charger.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/core.h>
diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index 7adfd69fe649..e78d061d8d32 100644
--- a/drivers/power/supply/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mfd/twl.h>
diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index 5231f6d52ae3..a081f177e702 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/powercap.h>
#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
#define to_scmi_powercap_zone(z) \
container_of(z, struct scmi_powercap_zone, zone)
@@ -19,6 +20,8 @@
static const struct scmi_powercap_proto_ops *powercap_ops;
struct scmi_powercap_zone {
+ bool registered;
+ bool invalid;
unsigned int height;
struct device *dev;
struct scmi_protocol_handle *ph;
@@ -32,6 +35,7 @@ struct scmi_powercap_root {
unsigned int num_zones;
struct scmi_powercap_zone *spzones;
struct list_head *registered_zones;
+ struct list_head scmi_zones;
};
static struct powercap_control_type *scmi_top_pcntrl;
@@ -271,12 +275,6 @@ static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr)
}
}
-static inline bool
-scmi_powercap_is_zone_registered(struct scmi_powercap_zone *spz)
-{
- return !list_empty(&spz->node);
-}
-
static inline unsigned int
scmi_powercap_get_zone_height(struct scmi_powercap_zone *spz)
{
@@ -295,11 +293,46 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
return &spz->spzones[spz->info->parent_id];
}
+static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
+ struct scmi_powercap_zone *spz,
+ struct scmi_powercap_zone *parent)
+{
+ int ret = 0;
+ struct powercap_zone *z;
+
+ if (spz->invalid) {
+ list_del(&spz->node);
+ return -EINVAL;
+ }
+
+ z = powercap_register_zone(&spz->zone, scmi_top_pcntrl, spz->info->name,
+ parent ? &parent->zone : NULL,
+ &zone_ops, 1, &constraint_ops);
+ if (!IS_ERR(z)) {
+ spz->height = scmi_powercap_get_zone_height(spz);
+ spz->registered = true;
+ list_move(&spz->node, &pr->registered_zones[spz->height]);
+ dev_dbg(spz->dev, "Registered node %s - parent %s - height:%d\n",
+ spz->info->name, parent ? parent->info->name : "ROOT",
+ spz->height);
+ } else {
+ list_del(&spz->node);
+ ret = PTR_ERR(z);
+ dev_err(spz->dev,
+ "Error registering node:%s - parent:%s - h:%d - ret:%d\n",
+ spz->info->name,
+ parent ? parent->info->name : "ROOT",
+ spz->height, ret);
+ }
+
+ return ret;
+}
+
/**
- * scmi_powercap_register_zone - Register an SCMI powercap zone recursively
+ * scmi_zones_register- Register SCMI powercap zones starting from parent zones
*
+ * @dev: A reference to the SCMI device
* @pr: A reference to the root powercap zones descriptors
- * @spz: A reference to the SCMI powercap zone to register
*
* When registering SCMI powercap zones with the powercap framework we should
* take care to always register zones starting from the root ones and to
@@ -309,10 +342,10 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
* zones provided by the SCMI platform firmware is built to comply with such
* requirement.
*
- * This function, given an SCMI powercap zone to register, takes care to walk
- * the SCMI powercap zones tree up to the root looking recursively for
- * unregistered parent zones before registering the provided zone; at the same
- * time each registered zone height in such a tree is accounted for and each
+ * This function, given the set of SCMI powercap zones to register, takes care
+ * to walk the SCMI powercap zones trees up to the root registering any
+ * unregistered parent zone before registering the child zones; at the same
+ * time each registered-zone height in such a tree is accounted for and each
* zone, once registered, is stored in the @registered_zones array that is
* indexed by zone height: this way will be trivial, at unregister time, to walk
* the @registered_zones array backward and unregister all the zones starting
@@ -330,57 +363,55 @@ scmi_powercap_get_parent_zone(struct scmi_powercap_zone *spz)
*
* Return: 0 on Success
*/
-static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
- struct scmi_powercap_zone *spz)
+static int scmi_zones_register(struct device *dev,
+ struct scmi_powercap_root *pr)
{
int ret = 0;
- struct scmi_powercap_zone *parent;
-
- if (!spz->info)
- return ret;
+ unsigned int sp = 0, reg_zones = 0;
+ struct scmi_powercap_zone *spz, **zones_stack;
- parent = scmi_powercap_get_parent_zone(spz);
- if (parent && !scmi_powercap_is_zone_registered(parent)) {
- /*
- * Bail out if a parent domain was marked as unsupported:
- * only domains participating as leaves can be skipped.
- */
- if (!parent->info)
- return -ENODEV;
+ zones_stack = kcalloc(pr->num_zones, sizeof(spz), GFP_KERNEL);
+ if (!zones_stack)
+ return -ENOMEM;
- ret = scmi_powercap_register_zone(pr, parent);
- if (ret)
- return ret;
- }
+ spz = list_first_entry_or_null(&pr->scmi_zones,
+ struct scmi_powercap_zone, node);
+ while (spz) {
+ struct scmi_powercap_zone *parent;
- if (!scmi_powercap_is_zone_registered(spz)) {
- struct powercap_zone *z;
-
- z = powercap_register_zone(&spz->zone,
- scmi_top_pcntrl,
- spz->info->name,
- parent ? &parent->zone : NULL,
- &zone_ops, 1, &constraint_ops);
- if (!IS_ERR(z)) {
- spz->height = scmi_powercap_get_zone_height(spz);
- list_add(&spz->node,
- &pr->registered_zones[spz->height]);
- dev_dbg(spz->dev,
- "Registered node %s - parent %s - height:%d\n",
- spz->info->name,
- parent ? parent->info->name : "ROOT",
- spz->height);
- ret = 0;
+ parent = scmi_powercap_get_parent_zone(spz);
+ if (parent && !parent->registered) {
+ zones_stack[sp++] = spz;
+ spz = parent;
} else {
- ret = PTR_ERR(z);
- dev_err(spz->dev,
- "Error registering node:%s - parent:%s - h:%d - ret:%d\n",
- spz->info->name,
- parent ? parent->info->name : "ROOT",
- spz->height, ret);
+ ret = scmi_powercap_register_zone(pr, spz, parent);
+ if (!ret) {
+ reg_zones++;
+ } else if (sp) {
+ /* Failed to register a non-leaf zone.
+ * Bail-out.
+ */
+ dev_err(dev,
+ "Failed to register non-leaf zone - ret:%d\n",
+ ret);
+ scmi_powercap_unregister_all_zones(pr);
+ reg_zones = 0;
+ goto out;
+ }
+ /* Pick next zone to process */
+ if (sp)
+ spz = zones_stack[--sp];
+ else
+ spz = list_first_entry_or_null(&pr->scmi_zones,
+ struct scmi_powercap_zone,
+ node);
}
}
+out:
+ kfree(zones_stack);
+ dev_info(dev, "Registered %d SCMI Powercap domains !\n", reg_zones);
+
return ret;
}
@@ -424,6 +455,8 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
if (!pr->registered_zones)
return -ENOMEM;
+ INIT_LIST_HEAD(&pr->scmi_zones);
+
for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
/*
* Powercap domains are validate by the protocol layer, i.e.
@@ -438,6 +471,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
INIT_LIST_HEAD(&spz->node);
INIT_LIST_HEAD(&pr->registered_zones[i]);
+ list_add_tail(&spz->node, &pr->scmi_zones);
/*
* Forcibly skip powercap domains using an abstract scale.
* Note that only leaves domains can be skipped, so this could
@@ -448,7 +482,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
dev_warn(dev,
"Abstract power scale not supported. Skip %s.\n",
spz->info->name);
- spz->info = NULL;
+ spz->invalid = true;
continue;
}
}
@@ -457,21 +491,12 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
* Scan array of retrieved SCMI powercap domains and register them
* recursively starting from the root domains.
*/
- for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
- ret = scmi_powercap_register_zone(pr, spz);
- if (ret) {
- dev_err(dev,
- "Failed to register powercap zone %s - ret:%d\n",
- spz->info->name, ret);
- scmi_powercap_unregister_all_zones(pr);
- return ret;
- }
- }
+ ret = scmi_zones_register(dev, pr);
+ if (ret)
+ return ret;
dev_set_drvdata(dev, pr);
- dev_info(dev, "Registered %d SCMI Powercap domains !\n", pr->num_zones);
-
return ret;
}
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index 8fac57b28f8a..5c2e6d5eea2a 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -1250,7 +1250,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &rapl_defaults_core),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &rapl_defaults_core),
@@ -1485,7 +1485,7 @@ static int rapl_detect_domains(struct rapl_package *rp)
}
pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name);
- rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain),
+ rp->domains = kcalloc(rp->nr_domains, sizeof(struct rapl_domain),
GFP_KERNEL);
if (!rp->domains)
return -ENOMEM;
diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c
index dd471021f237..250bd41a588c 100644
--- a/drivers/powercap/intel_rapl_msr.c
+++ b/drivers/powercap/intel_rapl_msr.c
@@ -142,7 +142,7 @@ static const struct x86_cpu_id pl4_support_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, NULL),
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 32dff1b4f891..ed9d97a032f1 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -155,6 +155,17 @@ config PTP_1588_CLOCK_IDTCM
To compile this driver as a module, choose M here: the module
will be called ptp_clockmatrix.
+config PTP_1588_CLOCK_MOCK
+ tristate "Mock-up PTP clock"
+ depends on PTP_1588_CLOCK
+ help
+ This driver offers a set of PTP clock manipulation operations over
+ the system monotonic time. It can be used by virtual network device
+ drivers to emulate PTP capabilities.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ptp_mock.
+
config PTP_1588_CLOCK_VMW
tristate "VMware virtual PTP clock"
depends on ACPI && HYPERVISOR_GUEST && X86
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 553f18bf3c83..dea0cebd2303 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -16,6 +16,7 @@ ptp-qoriq-y += ptp_qoriq.o
ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o
obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o
obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o
+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
diff --git a/drivers/ptp/ptp_mock.c b/drivers/ptp/ptp_mock.c
new file mode 100644
index 000000000000..e7b459c846a2
--- /dev/null
+++ b/drivers/ptp/ptp_mock.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2023 NXP
+ *
+ * Mock-up PTP Hardware Clock driver for virtual network devices
+ *
+ * Create a PTP clock which offers PTP time manipulation operations
+ * using a timecounter/cyclecounter on top of CLOCK_MONOTONIC_RAW.
+ */
+
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_mock.h>
+#include <linux/timecounter.h>
+
+/* Clamp scaled_ppm between -2,097,152,000 and 2,097,152,000,
+ * and thus "adj" between -68,719,476 and 68,719,476
+ */
+#define MOCK_PHC_MAX_ADJ_PPB 32000000
+/* Timestamps from ktime_get_raw() have 1 ns resolution, so the scale factor
+ * (MULT >> SHIFT) needs to be 1. Pick SHIFT as 31 bits, which translates
+ * MULT(freq 0) into 0x80000000.
+ */
+#define MOCK_PHC_CC_SHIFT 31
+#define MOCK_PHC_CC_MULT (1 << MOCK_PHC_CC_SHIFT)
+#define MOCK_PHC_FADJ_SHIFT 9
+#define MOCK_PHC_FADJ_DENOMINATOR 15625ULL
+
+/* The largest cycle_delta that timecounter_read_delta() can handle without a
+ * 64-bit overflow during the multiplication with cc->mult, given the max "adj"
+ * we permit, is ~8.3 seconds. Make sure readouts are more frequent than that.
+ */
+#define MOCK_PHC_REFRESH_INTERVAL (HZ * 5)
+
+#define info_to_phc(d) container_of((d), struct mock_phc, info)
+
+struct mock_phc {
+ struct ptp_clock_info info;
+ struct ptp_clock *clock;
+ struct timecounter tc;
+ struct cyclecounter cc;
+ spinlock_t lock;
+};
+
+static u64 mock_phc_cc_read(const struct cyclecounter *cc)
+{
+ return ktime_get_raw_ns();
+}
+
+static int mock_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
+{
+ struct mock_phc *phc = info_to_phc(info);
+ s64 adj;
+
+ adj = (s64)scaled_ppm << MOCK_PHC_FADJ_SHIFT;
+ adj = div_s64(adj, MOCK_PHC_FADJ_DENOMINATOR);
+
+ spin_lock(&phc->lock);
+ timecounter_read(&phc->tc);
+ phc->cc.mult = MOCK_PHC_CC_MULT + adj;
+ spin_unlock(&phc->lock);
+
+ return 0;
+}
+
+static int mock_phc_adjtime(struct ptp_clock_info *info, s64 delta)
+{
+ struct mock_phc *phc = info_to_phc(info);
+
+ spin_lock(&phc->lock);
+ timecounter_adjtime(&phc->tc, delta);
+ spin_unlock(&phc->lock);
+
+ return 0;
+}
+
+static int mock_phc_settime64(struct ptp_clock_info *info,
+ const struct timespec64 *ts)
+{
+ struct mock_phc *phc = info_to_phc(info);
+ u64 ns = timespec64_to_ns(ts);
+
+ spin_lock(&phc->lock);
+ timecounter_init(&phc->tc, &phc->cc, ns);
+ spin_unlock(&phc->lock);
+
+ return 0;
+}
+
+static int mock_phc_gettime64(struct ptp_clock_info *info, struct timespec64 *ts)
+{
+ struct mock_phc *phc = info_to_phc(info);
+ u64 ns;
+
+ spin_lock(&phc->lock);
+ ns = timecounter_read(&phc->tc);
+ spin_unlock(&phc->lock);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static long mock_phc_refresh(struct ptp_clock_info *info)
+{
+ struct timespec64 ts;
+
+ mock_phc_gettime64(info, &ts);
+
+ return MOCK_PHC_REFRESH_INTERVAL;
+}
+
+int mock_phc_index(struct mock_phc *phc)
+{
+ return ptp_clock_index(phc->clock);
+}
+EXPORT_SYMBOL_GPL(mock_phc_index);
+
+struct mock_phc *mock_phc_create(struct device *dev)
+{
+ struct mock_phc *phc;
+ int err;
+
+ phc = kzalloc(sizeof(*phc), GFP_KERNEL);
+ if (!phc) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ phc->info = (struct ptp_clock_info) {
+ .owner = THIS_MODULE,
+ .name = "Mock-up PTP clock",
+ .max_adj = MOCK_PHC_MAX_ADJ_PPB,
+ .adjfine = mock_phc_adjfine,
+ .adjtime = mock_phc_adjtime,
+ .gettime64 = mock_phc_gettime64,
+ .settime64 = mock_phc_settime64,
+ .do_aux_work = mock_phc_refresh,
+ };
+
+ phc->cc = (struct cyclecounter) {
+ .read = mock_phc_cc_read,
+ .mask = CYCLECOUNTER_MASK(64),
+ .mult = MOCK_PHC_CC_MULT,
+ .shift = MOCK_PHC_CC_SHIFT,
+ };
+
+ spin_lock_init(&phc->lock);
+ timecounter_init(&phc->tc, &phc->cc, 0);
+
+ phc->clock = ptp_clock_register(&phc->info, dev);
+ if (IS_ERR(phc->clock)) {
+ err = PTR_ERR(phc->clock);
+ goto out_free_phc;
+ }
+
+ ptp_schedule_worker(phc->clock, MOCK_PHC_REFRESH_INTERVAL);
+
+ return phc;
+
+out_free_phc:
+ kfree(phc);
+out:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(mock_phc_create);
+
+void mock_phc_destroy(struct mock_phc *phc)
+{
+ ptp_clock_unregister(phc->clock);
+ kfree(phc);
+}
+EXPORT_SYMBOL_GPL(mock_phc_destroy);
+
+MODULE_DESCRIPTION("Mock-up PTP Hardware Clock driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c
index 350154e4c2b5..a52859d024f0 100644
--- a/drivers/ptp/ptp_qoriq.c
+++ b/drivers/ptp/ptp_qoriq.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/clk.h>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 823f8e6e4801..965d4f0c18a6 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -178,6 +178,14 @@ config REGULATOR_ATC260X
ATC260x PMICs. This will enable support for all the software
controllable DCDC/LDO regulators.
+config REGULATOR_AW37503
+ tristate "Awinic AW37503 Dual Output Power regulators"
+ depends on I2C && GPIOLIB
+ select REGMAP_I2C
+ help
+ This driver supports AW37503 single inductor - dual output
+ power supply specifically designed for display panels.
+
config REGULATOR_AXP20X
tristate "X-POWERS AXP20X PMIC Regulators"
depends on MFD_AXP20X
@@ -546,11 +554,11 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
-config REGULATOR_MAX597X
- tristate "Maxim 597x power switch and monitor"
+config REGULATOR_MAX5970
+ tristate "Maxim 5970/5978 power switch and monitor"
depends on I2C
depends on OF
- depends on MFD_MAX597X
+ depends on MFD_MAX5970
help
This driver controls a Maxim 5970/5978 switch via I2C bus.
The MAX5970/5978 is a smart switch with no output regulation, but
@@ -584,6 +592,16 @@ config REGULATOR_MAX77650
Semiconductor. This device has a SIMO with three independent
power rails and an LDO.
+config REGULATOR_MAX77857
+ tristate "ADI MAX77857/MAX77831 regulator support"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver controls a ADI MAX77857 and MAX77831 regulators.
+ via I2C bus. MAX77857 and MAX77831 are high efficiency buck-boost
+ converters with input voltage range (2.5V to 16V). Say Y here to
+ enable the regulator driver
+
config REGULATOR_MAX8649
tristate "Maxim 8649 voltage regulator"
depends on I2C
@@ -989,6 +1007,18 @@ config REGULATOR_PWM
This driver supports PWM controlled voltage regulators. PWM
duty cycle can increase or decrease the voltage.
+config REGULATOR_QCOM_REFGEN
+ tristate "Qualcomm REFGEN regulator driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on REGMAP
+ help
+ This driver supports the MMIO-mapped reference voltage regulator,
+ used internally by some PHYs on many Qualcomm SoCs.
+
+ Say M here if you want to include support for this regulator as
+ a module. The module will be named "qcom-refgen-regulator".
+
config REGULATOR_QCOM_RPM
tristate "Qualcomm RPM regulator driver"
depends on MFD_QCOM_RPM
@@ -1050,7 +1080,11 @@ config REGULATOR_RAA215300
depends on COMMON_CLK
depends on I2C
help
- Support for the Renesas RAA215300 PMIC.
+ If you say yes to this option, support will be included for the
+ Renesas RAA215300 PMIC.
+
+ Say M here if you want to include support for Renesas RAA215300 PMIC
+ as a module. The module will be named "raa215300".
config REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
tristate "Raspberry Pi 7-inch touchscreen panel ATTINY regulator"
@@ -1232,6 +1266,17 @@ config REGULATOR_RTQ6752
synchronous boost converters for PAVDD, and one synchronous NAVDD
buck-boost. This device is suitable for automotive TFT-LCD panel.
+config REGULATOR_RTQ2208
+ tristate "Richtek RTQ2208 SubPMIC Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver adds support for RTQ2208 SubPMIC regulators.
+ The RTQ2208 is a multi-phase, programmable power management IC that
+ integrate with dual multi-configurable, synchronous buck converters
+ and two ldos. It features wide output voltage range from 0.4V to 2.05V
+ and the capability to configure the corresponding power stages.
+
config REGULATOR_S2MPA01
tristate "Samsung S2MPA01 voltage regulator"
depends on MFD_SEC_CORE || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 15e0d614ff66..23074714a81a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_ARM_SCMI) += scmi-regulator.o
obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
+obj-$(CONFIG_REGULATOR_AW37503) += aw37503-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_BD71815) += bd71815-regulator.o
@@ -67,7 +68,7 @@ obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
-obj-$(CONFIG_REGULATOR_MAX597X) += max597x-regulator.o
+obj-$(CONFIG_REGULATOR_MAX5970) += max5970-regulator.o
obj-$(CONFIG_REGULATOR_MAX77541) += max77541-regulator.o
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o
@@ -86,6 +87,7 @@ obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
obj-$(CONFIG_REGULATOR_MAX77826) += max77826-regulator.o
+obj-$(CONFIG_REGULATOR_MAX77857) += max77857-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
@@ -108,6 +110,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
@@ -145,6 +148,7 @@ obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o
obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o
obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o
obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o
+obj-$(CONFIG_REGULATOR_RTQ2208) += rtq2208-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c
index e26264529b74..24cbdd833863 100644
--- a/drivers/regulator/act8945a-regulator.c
+++ b/drivers/regulator/act8945a-regulator.c
@@ -8,7 +8,7 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/atc260x-regulator.c b/drivers/regulator/atc260x-regulator.c
index 87e237d740bc..3e9f8fd54fca 100644
--- a/drivers/regulator/atc260x-regulator.c
+++ b/drivers/regulator/atc260x-regulator.c
@@ -7,7 +7,8 @@
#include <linux/mfd/atc260x/core.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
@@ -37,7 +38,7 @@ static const struct linear_range atc2609a_ldo_voltage_ranges1[] = {
};
static const unsigned int atc260x_ldo_voltage_range_sel[] = {
- 0x0, 0x20,
+ 0x0, 0x1,
};
static int atc260x_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,
@@ -427,7 +428,7 @@ enum atc2609a_reg_ids {
.vsel_mask = GENMASK(4, 1), \
.vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.vsel_range_mask = BIT(5), \
- .linear_range_selectors = atc260x_ldo_voltage_range_sel, \
+ .linear_range_selectors_bitfield = atc260x_ldo_voltage_range_sel, \
.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.enable_mask = BIT(0), \
.enable_time = 2000, \
diff --git a/drivers/regulator/aw37503-regulator.c b/drivers/regulator/aw37503-regulator.c
new file mode 100644
index 000000000000..a5ff6dfd29b5
--- /dev/null
+++ b/drivers/regulator/aw37503-regulator.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// AWINIC AW37503 Regulator Driver
+//
+// Copyright (C) 2023 awinic. All Rights Reserved
+//
+// Author: <like@awinic.com>
+
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define AW37503_REG_VPOS 0x00
+#define AW37503_REG_VNEG 0x01
+#define AW37503_REG_APPS 0x03
+#define AW37503_REG_CONTROL 0x04
+#define AW37503_REG_WPRTEN 0x21
+
+#define AW37503_VOUT_MASK 0x1F
+#define AW37503_VOUT_N_VOLTAGE 0x15
+#define AW37503_VOUT_VMIN 4000000
+#define AW37503_VOUT_VMAX 6000000
+#define AW37503_VOUT_STEP 100000
+
+#define AW37503_REG_APPS_DIS_VPOS BIT(1)
+#define AW37503_REG_APPS_DIS_VNEG BIT(0)
+
+#define AW37503_REGULATOR_ID_VPOS 0
+#define AW37503_REGULATOR_ID_VNEG 1
+#define AW37503_MAX_REGULATORS 2
+
+struct aw37503_reg_pdata {
+ struct gpio_desc *en_gpiod;
+ int ena_gpio_state;
+};
+
+struct aw37503_regulator {
+ struct device *dev;
+ struct aw37503_reg_pdata reg_pdata[AW37503_MAX_REGULATORS];
+};
+
+static int aw37503_regulator_enable(struct regulator_dev *rdev)
+{
+ struct aw37503_regulator *chip = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id];
+ int ret;
+
+ if (!IS_ERR(rpdata->en_gpiod)) {
+ gpiod_set_value_cansleep(rpdata->en_gpiod, 1);
+ rpdata->ena_gpio_state = 1;
+ }
+
+ /* Hardware automatically enable discharge bit in enable */
+ if (rdev->constraints->active_discharge ==
+ REGULATOR_ACTIVE_DISCHARGE_DISABLE) {
+ ret = regulator_set_active_discharge_regmap(rdev, false);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to disable active discharge: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int aw37503_regulator_disable(struct regulator_dev *rdev)
+{
+ struct aw37503_regulator *chip = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id];
+
+ if (!IS_ERR(rpdata->en_gpiod)) {
+ gpiod_set_value_cansleep(rpdata->en_gpiod, 0);
+ rpdata->ena_gpio_state = 0;
+ }
+
+ return 0;
+}
+
+static int aw37503_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct aw37503_regulator *chip = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id];
+
+ if (!IS_ERR(rpdata->en_gpiod))
+ return rpdata->ena_gpio_state;
+
+ return 1;
+}
+
+static const struct regulator_ops aw37503_regulator_ops = {
+ .enable = aw37503_regulator_enable,
+ .disable = aw37503_regulator_disable,
+ .is_enabled = aw37503_regulator_is_enabled,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+static int aw37503_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct aw37503_regulator *chip = config->driver_data;
+ struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[desc->id];
+ int ret;
+
+ rpdata->en_gpiod = devm_fwnode_gpiod_get(chip->dev, of_fwnode_handle(np),
+ "enable", GPIOD_OUT_LOW,
+ "enable");
+
+ if (IS_ERR(rpdata->en_gpiod)) {
+ ret = PTR_ERR(rpdata->en_gpiod);
+
+ /* Ignore the error other than probe defer */
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ return 0;
+ }
+
+ return 0;
+}
+
+#define AW37503_REGULATOR_DESC(_id, _name) \
+ [AW37503_REGULATOR_ID_##_id] = { \
+ .name = "aw37503-"#_name, \
+ .supply_name = "vin", \
+ .id = AW37503_REGULATOR_ID_##_id, \
+ .of_match = of_match_ptr(#_name), \
+ .of_parse_cb = aw37503_of_parse_cb, \
+ .ops = &aw37503_regulator_ops, \
+ .n_voltages = AW37503_VOUT_N_VOLTAGE, \
+ .min_uV = AW37503_VOUT_VMIN, \
+ .uV_step = AW37503_VOUT_STEP, \
+ .enable_time = 500, \
+ .vsel_mask = AW37503_VOUT_MASK, \
+ .vsel_reg = AW37503_REG_##_id, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = AW37503_REG_APPS_DIS_##_id, \
+ .active_discharge_mask = AW37503_REG_APPS_DIS_##_id, \
+ .active_discharge_reg = AW37503_REG_APPS, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+static const struct regulator_desc aw_regs_desc[AW37503_MAX_REGULATORS] = {
+ AW37503_REGULATOR_DESC(VPOS, outp),
+ AW37503_REGULATOR_DESC(VNEG, outn),
+};
+
+static const struct regmap_range aw37503_no_reg_ranges[] = {
+ regmap_reg_range(AW37503_REG_CONTROL + 1,
+ AW37503_REG_WPRTEN - 1),
+};
+
+static const struct regmap_access_table aw37503_no_reg_table = {
+ .no_ranges = aw37503_no_reg_ranges,
+ .n_no_ranges = ARRAY_SIZE(aw37503_no_reg_ranges),
+};
+
+static const struct regmap_config aw37503_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AW37503_REG_WPRTEN,
+ .rd_table = &aw37503_no_reg_table,
+ .wr_table = &aw37503_no_reg_table,
+};
+
+static int aw37503_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct aw37503_regulator *chip;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ struct regulator_config config = { };
+ int id;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &aw37503_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to init regmap\n");
+
+ i2c_set_clientdata(client, chip);
+ chip->dev = dev;
+
+ config.regmap = regmap;
+ config.dev = dev;
+ config.driver_data = chip;
+
+ for (id = 0; id < AW37503_MAX_REGULATORS; ++id) {
+ rdev = devm_regulator_register(dev, &aw_regs_desc[id],
+ &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "Failed to register regulator %s\n",
+ aw_regs_desc[id].name);
+ }
+ return 0;
+}
+
+static const struct i2c_device_id aw37503_id[] = {
+ {.name = "aw37503",},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, aw37503_id);
+
+static const struct of_device_id aw37503_of_match[] = {
+ {.compatible = "awinic,aw37503",},
+ { /* Sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, aw37503_of_match);
+
+static struct i2c_driver aw37503_i2c_driver = {
+ .driver = {
+ .name = "aw37503",
+ .of_match_table = aw37503_of_match,
+ },
+ .probe = aw37503_probe,
+ .id_table = aw37503_id,
+};
+
+module_i2c_driver(aw37503_i2c_driver);
+
+MODULE_DESCRIPTION("aw37503 regulator driver");
+MODULE_AUTHOR("Alec Li <like@awinic.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 810f90f3e2a1..c657820b0bbb 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -20,7 +20,6 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c
index 475b1e0110e7..26192d55a685 100644
--- a/drivers/regulator/bd71815-regulator.c
+++ b/drivers/regulator/bd71815-regulator.c
@@ -18,7 +18,6 @@
#include <linux/regulator/driver.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index f3205dc9d4fc..08d4ee369287 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -5,7 +5,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71828.h>
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index b0b9938c20a1..c3fb05dce40c 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -289,7 +289,7 @@ static const struct linear_range bd71837_buck5_volts[] = {
* and 0x1 for last 3 ranges.
*/
static const unsigned int bd71837_buck5_volt_range_sel[] = {
- 0x0, 0x0, 0x0, 0x80, 0x80, 0x80
+ 0x0, 0x0, 0x0, 0x1, 0x1, 0x1
};
/*
@@ -309,7 +309,7 @@ static const struct linear_range bd71847_buck3_volts[] = {
};
static const unsigned int bd71847_buck3_volt_range_sel[] = {
- 0x0, 0x0, 0x0, 0x40, 0x80, 0x80, 0x80
+ 0x0, 0x0, 0x0, 0x1, 0x2, 0x2, 0x2
};
static const struct linear_range bd71847_buck4_volts[] = {
@@ -317,7 +317,7 @@ static const struct linear_range bd71847_buck4_volts[] = {
REGULATOR_LINEAR_RANGE(2600000, 0x00, 0x03, 100000),
};
-static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x40 };
+static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x1 };
/*
* BUCK6
@@ -360,7 +360,7 @@ static const struct linear_range bd718xx_ldo1_volts[] = {
REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
};
-static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x20 };
+static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x1 };
/*
* LDO2
@@ -403,7 +403,7 @@ static const struct linear_range bd71847_ldo5_volts[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x0F, 100000),
};
-static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x20 };
+static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x1 };
/*
* LDO6
@@ -817,7 +817,7 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.vsel_mask = BD718XX_1ST_NODVS_BUCK_MASK,
.vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
.vsel_range_mask = BD71847_BUCK3_RANGE_MASK,
- .linear_range_selectors = bd71847_buck3_volt_range_sel,
+ .linear_range_selectors_bitfield = bd71847_buck3_volt_range_sel,
.enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71847_BUCK3_STARTUP_TIME,
@@ -845,7 +845,7 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.vsel_mask = BD71847_BUCK4_MASK,
.vsel_range_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
.vsel_range_mask = BD71847_BUCK4_RANGE_MASK,
- .linear_range_selectors = bd71847_buck4_volt_range_sel,
+ .linear_range_selectors_bitfield = bd71847_buck4_volt_range_sel,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71847_BUCK4_STARTUP_TIME,
.owner = THIS_MODULE,
@@ -916,7 +916,7 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.vsel_mask = BD718XX_LDO1_MASK,
.vsel_range_reg = BD718XX_REG_LDO1_VOLT,
.vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
- .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .linear_range_selectors_bitfield = bd718xx_ldo1_volt_range_sel,
.enable_reg = BD718XX_REG_LDO1_VOLT,
.enable_mask = BD718XX_LDO_EN,
.enable_time = BD71847_LDO1_STARTUP_TIME,
@@ -1010,7 +1010,7 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.vsel_mask = BD71847_LDO5_MASK,
.vsel_range_reg = BD718XX_REG_LDO5_VOLT,
.vsel_range_mask = BD71847_LDO5_RANGE_MASK,
- .linear_range_selectors = bd71847_ldo5_volt_range_sel,
+ .linear_range_selectors_bitfield = bd71847_ldo5_volt_range_sel,
.enable_reg = BD718XX_REG_LDO5_VOLT,
.enable_mask = BD718XX_LDO_EN,
.enable_time = BD71847_LDO5_STARTUP_TIME,
@@ -1232,7 +1232,7 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.vsel_mask = BD71837_BUCK5_MASK,
.vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
.vsel_range_mask = BD71837_BUCK5_RANGE_MASK,
- .linear_range_selectors = bd71837_buck5_volt_range_sel,
+ .linear_range_selectors_bitfield = bd71837_buck5_volt_range_sel,
.enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71837_BUCK5_STARTUP_TIME,
@@ -1328,7 +1328,7 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.vsel_mask = BD718XX_LDO1_MASK,
.vsel_range_reg = BD718XX_REG_LDO1_VOLT,
.vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
- .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .linear_range_selectors_bitfield = bd718xx_ldo1_volt_range_sel,
.enable_reg = BD718XX_REG_LDO1_VOLT,
.enable_mask = BD718XX_LDO_EN,
.enable_time = BD71837_LDO1_STARTUP_TIME,
diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c
index 1fd79fb17303..6958d154442b 100644
--- a/drivers/regulator/cpcap-regulator.c
+++ b/drivers/regulator/cpcap-regulator.c
@@ -12,7 +12,7 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c
index c28b061eef02..1d354db0c1bd 100644
--- a/drivers/regulator/da9062-regulator.c
+++ b/drivers/regulator/da9062-regulator.c
@@ -924,7 +924,7 @@ static int da9062_regulator_probe(struct platform_device *pdev)
struct da9062_regulator *regl;
struct regulator_config config = { };
const struct da9062_regulator_info *rinfo;
- int irq, n, ret;
+ int n, ret;
int max_regulators;
switch (chip->chip_type) {
@@ -1012,12 +1012,11 @@ static int da9062_regulator_probe(struct platform_device *pdev)
}
/* LDOs overcurrent event support */
- irq = platform_get_irq_byname(pdev, "LDO_LIM");
- if (irq < 0)
- return irq;
- regulators->irq_ldo_lim = irq;
+ regulators->irq_ldo_lim = platform_get_irq_byname_optional(pdev, "LDO_LIM");
+ if (regulators->irq_ldo_lim < 0)
+ return 0;
- ret = devm_request_threaded_irq(&pdev->dev, irq,
+ ret = devm_request_threaded_irq(&pdev->dev, regulators->irq_ldo_lim,
NULL, da9062_ldo_lim_event,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"LDO_LIM", regulators);
diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index 122124944749..80098035bb13 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -440,7 +440,7 @@ static const struct regulator_desc da9121_reg = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -465,7 +465,7 @@ static const struct regulator_desc da9220_reg[2] = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -484,7 +484,7 @@ static const struct regulator_desc da9220_reg[2] = {
.of_match = "buck2",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -506,7 +506,7 @@ static const struct regulator_desc da9122_reg[2] = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -525,7 +525,7 @@ static const struct regulator_desc da9122_reg[2] = {
.of_match = "buck2",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -546,7 +546,7 @@ static const struct regulator_desc da9217_reg = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -573,7 +573,7 @@ static const struct regulator_desc da9141_reg = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -593,7 +593,7 @@ static const struct regulator_desc da9142_reg = {
.of_match = "buck1",
.of_parse_cb = da9121_of_parse_cb,
.owner = THIS_MODULE,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.of_map_mode = da9121_map_mode,
.ops = &da9121_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -1195,7 +1195,7 @@ static struct i2c_driver da9121_regulator_driver = {
.driver = {
.name = "da9121",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(da9121_dt_ids),
+ .of_match_table = da9121_dt_ids,
},
.probe = da9121_i2c_probe,
.remove = da9121_i2c_remove,
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 289c06e09f47..48f312167e53 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -12,7 +12,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/param.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 364d1a2683b7..55130efae9b8 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -25,7 +25,6 @@
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
#include <linux/clk.h>
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index e6c999ba3fa2..5ad5f3b3a6b5 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -5,13 +5,14 @@
// Copyright 2007, 2008 Wolfson Microelectronics PLC.
// Copyright 2008 SlimLogic Ltd.
-#include <linux/kernel.h>
-#include <linux/err.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
-#include <linux/module.h>
#include "internal.h"
@@ -104,13 +105,14 @@ static int regulator_range_selector_to_index(struct regulator_dev *rdev,
{
int i;
- if (!rdev->desc->linear_range_selectors)
+ if (!rdev->desc->linear_range_selectors_bitfield)
return -EINVAL;
rval &= rdev->desc->vsel_range_mask;
+ rval >>= ffs(rdev->desc->vsel_range_mask) - 1;
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
- if (rdev->desc->linear_range_selectors[i] == rval)
+ if (rdev->desc->linear_range_selectors_bitfield[i] == rval)
return i;
}
return -EINVAL;
@@ -194,7 +196,8 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
sel <<= ffs(rdev->desc->vsel_mask) - 1;
sel += rdev->desc->linear_ranges[i].min_sel;
- range = rdev->desc->linear_range_selectors[i];
+ range = rdev->desc->linear_range_selectors_bitfield[i];
+ range <<= ffs(rdev->desc->vsel_mask) - 1;
if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
ret = regmap_update_bits(rdev->regmap,
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
index 1b52423598d3..82e9e364d4d4 100644
--- a/drivers/regulator/hi6421-regulator.c
+++ b/drivers/regulator/hi6421-regulator.c
@@ -131,8 +131,8 @@ static const struct regulator_ops hi6421_buck345_ops;
[HI6421_##_id] = { \
.desc = { \
.name = #_id, \
- .of_match = of_match_ptr(#_match), \
- .regulators_node = of_match_ptr("regulators"), \
+ .of_match = #_match, \
+ .regulators_node = "regulators", \
.ops = &hi6421_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.id = HI6421_##_id, \
@@ -170,8 +170,8 @@ static const struct regulator_ops hi6421_buck345_ops;
[HI6421_##_id] = { \
.desc = { \
.name = #_id, \
- .of_match = of_match_ptr(#_match), \
- .regulators_node = of_match_ptr("regulators"), \
+ .of_match = #_match, \
+ .regulators_node = "regulators", \
.ops = &hi6421_ldo_linear_ops, \
.type = REGULATOR_VOLTAGE, \
.id = HI6421_##_id, \
@@ -210,8 +210,8 @@ static const struct regulator_ops hi6421_buck345_ops;
[HI6421_##_id] = { \
.desc = { \
.name = #_id, \
- .of_match = of_match_ptr(#_match), \
- .regulators_node = of_match_ptr("regulators"), \
+ .of_match = #_match, \
+ .regulators_node = "regulators", \
.ops = &hi6421_ldo_linear_range_ops, \
.type = REGULATOR_VOLTAGE, \
.id = HI6421_##_id, \
@@ -247,8 +247,8 @@ static const struct regulator_ops hi6421_buck345_ops;
[HI6421_##_id] = { \
.desc = { \
.name = #_id, \
- .of_match = of_match_ptr(#_match), \
- .regulators_node = of_match_ptr("regulators"), \
+ .of_match = #_match, \
+ .regulators_node = "regulators", \
.ops = &hi6421_buck012_ops, \
.type = REGULATOR_VOLTAGE, \
.id = HI6421_##_id, \
@@ -284,8 +284,8 @@ static const struct regulator_ops hi6421_buck345_ops;
[HI6421_##_id] = { \
.desc = { \
.name = #_id, \
- .of_match = of_match_ptr(#_match), \
- .regulators_node = of_match_ptr("regulators"), \
+ .of_match = #_match, \
+ .regulators_node = "regulators", \
.ops = &hi6421_buck345_ops, \
.type = REGULATOR_VOLTAGE, \
.id = HI6421_##_id, \
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 63aa227b1813..942f37082cb1 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -864,7 +864,7 @@ static struct lp872x_platform_data
for (i = 0; i < num_matches; i++) {
pdata->regulator_data[i].id =
- (enum lp872x_regulator_id)match[i].driver_data;
+ (uintptr_t)match[i].driver_data;
pdata->regulator_data[i].init_data = match[i].init_data;
}
out:
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
index 4bc310f972ed..8d01e18046f3 100644
--- a/drivers/regulator/lp8755.c
+++ b/drivers/regulator/lp8755.c
@@ -13,7 +13,6 @@
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/uaccess.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c
index bdb60d8a7f3d..61ee5cf3f241 100644
--- a/drivers/regulator/lp87565-regulator.c
+++ b/drivers/regulator/lp87565-regulator.c
@@ -29,8 +29,8 @@ enum LP87565_regulator_id {
.name = _name, \
.supply_name = _of "-in", \
.id = _id, \
- .of_match = of_match_ptr(_of), \
- .regulators_node = of_match_ptr("regulators"),\
+ .of_match = _of, \
+ .regulators_node = "regulators", \
.ops = &_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index e9751c206d95..d892c2a5df7b 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
@@ -392,8 +391,7 @@ static int ltc3589_probe(struct i2c_client *client)
i2c_set_clientdata(client, ltc3589);
if (client->dev.of_node)
- ltc3589->variant = (enum ltc3589_variant)
- of_device_get_match_data(&client->dev);
+ ltc3589->variant = (uintptr_t)of_device_get_match_data(&client->dev);
else
ltc3589->variant = id->driver_data;
ltc3589->dev = dev;
diff --git a/drivers/regulator/max20086-regulator.c b/drivers/regulator/max20086-regulator.c
index fad31f5f435e..32f47b896fd1 100644
--- a/drivers/regulator/max20086-regulator.c
+++ b/drivers/regulator/max20086-regulator.c
@@ -6,7 +6,6 @@
// Copyright (C) 2018 Avnet, Inc.
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
diff --git a/drivers/regulator/max597x-regulator.c b/drivers/regulator/max5970-regulator.c
index 7873a5267555..b56a174cde3d 100644
--- a/drivers/regulator/max597x-regulator.c
+++ b/drivers/regulator/max5970-regulator.c
@@ -20,9 +20,9 @@
#include <linux/regulator/of_regulator.h>
#include <linux/platform_device.h>
-#include <linux/mfd/max597x.h>
+#include <linux/mfd/max5970.h>
-struct max597x_regulator {
+struct max5970_regulator {
int num_switches, mon_rng, irng, shunt_micro_ohms, lim_uA;
struct regmap *regmap;
};
@@ -58,7 +58,7 @@ static int max597x_set_vp(struct regulator_dev *rdev, int lim_uV, int severity,
bool enable, bool overvoltage)
{
int off_h, off_l, reg, ret;
- struct max597x_regulator *data = rdev_get_drvdata(rdev);
+ struct max5970_regulator *data = rdev_get_drvdata(rdev);
int channel = rdev_get_id(rdev);
if (overvoltage) {
@@ -140,7 +140,7 @@ static int max597x_set_ocp(struct regulator_dev *rdev, int lim_uA,
int val, reg;
unsigned int vthst, vthfst;
- struct max597x_regulator *data = rdev_get_drvdata(rdev);
+ struct max5970_regulator *data = rdev_get_drvdata(rdev);
int rdev_id = rdev_get_id(rdev);
/*
* MAX5970 doesn't has enable control for ocp.
@@ -222,7 +222,7 @@ static int max597x_dt_parse(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
- struct max597x_regulator *data = cfg->driver_data;
+ struct max5970_regulator *data = cfg->driver_data;
int ret = 0;
ret =
@@ -274,7 +274,7 @@ static int max597x_irq_handler(int irq, struct regulator_irq_data *rid,
unsigned long *dev_mask)
{
struct regulator_err_state *stat;
- struct max597x_regulator *d = (struct max597x_regulator *)rid->data;
+ struct max5970_regulator *d = (struct max5970_regulator *)rid->data;
int val, ret, i;
ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT0, &val);
@@ -394,7 +394,7 @@ static int max597x_adc_range(struct regmap *regmap, const int ch,
static int max597x_setup_irq(struct device *dev,
int irq,
struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES],
- int num_switches, struct max597x_regulator *data)
+ int num_switches, struct max5970_regulator *data)
{
struct regulator_irq_desc max597x_notif = {
.name = "max597x-irq",
@@ -425,9 +425,9 @@ static int max597x_setup_irq(struct device *dev,
static int max597x_regulator_probe(struct platform_device *pdev)
{
- struct max597x_data *max597x;
+ struct max5970_data *max597x;
struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
- struct max597x_regulator *data;
+ struct max5970_regulator *data;
struct i2c_client *i2c = to_i2c_client(pdev->dev.parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
@@ -438,16 +438,16 @@ static int max597x_regulator_probe(struct platform_device *pdev)
if (!regmap)
return -EPROBE_DEFER;
- max597x = devm_kzalloc(&i2c->dev, sizeof(struct max597x_data), GFP_KERNEL);
+ max597x = devm_kzalloc(&i2c->dev, sizeof(struct max5970_data), GFP_KERNEL);
if (!max597x)
return -ENOMEM;
i2c_set_clientdata(i2c, max597x);
if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5978"))
- max597x->num_switches = MAX597x_TYPE_MAX5978;
+ max597x->num_switches = MAX5978_NUM_SWITCHES;
else if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5970"))
- max597x->num_switches = MAX597x_TYPE_MAX5970;
+ max597x->num_switches = MAX5970_NUM_SWITCHES;
else
return -ENODEV;
@@ -456,7 +456,7 @@ static int max597x_regulator_probe(struct platform_device *pdev)
for (i = 0; i < num_switches; i++) {
data =
- devm_kzalloc(&i2c->dev, sizeof(struct max597x_regulator),
+ devm_kzalloc(&i2c->dev, sizeof(struct max5970_regulator),
GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -500,7 +500,7 @@ static int max597x_regulator_probe(struct platform_device *pdev)
static struct platform_driver max597x_regulator_driver = {
.driver = {
- .name = "max597x-regulator",
+ .name = "max5970-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = max597x_regulator_probe,
diff --git a/drivers/regulator/max77541-regulator.c b/drivers/regulator/max77541-regulator.c
index 2976f9cb3e26..e6b3d9147c37 100644
--- a/drivers/regulator/max77541-regulator.c
+++ b/drivers/regulator/max77541-regulator.c
@@ -44,7 +44,7 @@ static const struct linear_range max77541_buck_ranges[] = {
};
static const unsigned int max77541_buck_volt_range_sel[] = {
- 0x00, 0x00, 0x40, 0x40, 0x80, 0x80,
+ 0x0, 0x0, 0x1, 0x1, 0x2, 0x2,
};
enum max77541_regulators {
@@ -67,7 +67,7 @@ enum max77541_regulators {
.vsel_mask = MAX77541_BITS_MX_VOUT, \
.vsel_range_reg = MAX77541_REG_M ## _id ## _CFG1, \
.vsel_range_mask = MAX77541_BITS_MX_CFG1_RNG, \
- .linear_range_selectors = max77541_buck_volt_range_sel, \
+ .linear_range_selectors_bitfield = max77541_buck_volt_range_sel, \
.owner = THIS_MODULE, \
}
@@ -86,7 +86,7 @@ enum max77541_regulators {
.vsel_mask = MAX77541_BITS_MX_VOUT, \
.vsel_range_reg = MAX77541_REG_M ## _id ## _CFG1, \
.vsel_range_mask = MAX77541_BITS_MX_CFG1_RNG, \
- .linear_range_selectors = max77541_buck_volt_range_sel, \
+ .linear_range_selectors_bitfield = max77541_buck_volt_range_sel, \
.owner = THIS_MODULE, \
}
diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c
index f6539b945037..94abfbb2bc1e 100644
--- a/drivers/regulator/max77650-regulator.c
+++ b/drivers/regulator/max77650-regulator.c
@@ -239,7 +239,7 @@ static struct max77650_regulator_desc max77651_SBB1_desc = {
.supply_name = "in-sbb1",
.id = MAX77650_REGULATOR_ID_SBB1,
.ops = &max77651_SBB1_regulator_ops,
- .linear_range_selectors = max77651_sbb1_volt_range_sel,
+ .linear_range_selectors_bitfield = max77651_sbb1_volt_range_sel,
.linear_ranges = max77651_sbb1_volt_ranges,
.n_linear_ranges = ARRAY_SIZE(max77651_sbb1_volt_ranges),
.n_voltages = 58,
diff --git a/drivers/regulator/max77826-regulator.c b/drivers/regulator/max77826-regulator.c
index 3855f5e686d8..5590cdf615b7 100644
--- a/drivers/regulator/max77826-regulator.c
+++ b/drivers/regulator/max77826-regulator.c
@@ -9,7 +9,6 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/max77857-regulator.c b/drivers/regulator/max77857-regulator.c
new file mode 100644
index 000000000000..145ad0281857
--- /dev/null
+++ b/drivers/regulator/max77857-regulator.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Analog Devices, Inc.
+ * ADI Regulator driver for the MAX77857
+ * MAX77859 and MAX77831.
+ */
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/util_macros.h>
+
+#define MAX77857_REG_INT_SRC 0x10
+#define MAX77857_REG_INT_MASK 0x11
+#define MAX77857_REG_CONT1 0x12
+#define MAX77857_REG_CONT2 0x13
+#define MAX77857_REG_CONT3 0x14
+
+#define MAX77857_INT_SRC_OCP BIT(0)
+#define MAX77857_INT_SRC_THS BIT(1)
+#define MAX77857_INT_SRC_HARDSHORT BIT(2)
+#define MAX77857_INT_SRC_OVP BIT(3)
+#define MAX77857_INT_SRC_POK BIT(4)
+
+#define MAX77857_ILIM_MASK GENMASK(2, 0)
+#define MAX77857_CONT1_FREQ GENMASK(4, 3)
+#define MAX77857_CONT3_FPWM BIT(5)
+
+#define MAX77859_REG_INT_SRC 0x11
+#define MAX77859_REG_CONT1 0x13
+#define MAX77859_REG_CONT2 0x14
+#define MAX77859_REG_CONT3 0x15
+#define MAX77859_REG_CONT5 0x17
+#define MAX77859_CONT2_FPWM BIT(2)
+#define MAX77859_CONT2_INTB BIT(3)
+#define MAX77859_CONT3_DVS_START BIT(2)
+#define MAX77859_VOLTAGE_SEL_MASK GENMASK(9, 0)
+
+#define MAX77859_CURRENT_MIN 1000000
+#define MAX77859_CURRENT_MAX 5000000
+#define MAX77859_CURRENT_STEP 50000
+
+enum max77857_id {
+ ID_MAX77831 = 1,
+ ID_MAX77857,
+ ID_MAX77859,
+ ID_MAX77859A,
+};
+
+static bool max77857_volatile_reg(struct device *dev, unsigned int reg)
+{
+ enum max77857_id id = (uintptr_t)dev_get_drvdata(dev);
+
+ switch (id) {
+ case ID_MAX77831:
+ case ID_MAX77857:
+ return reg == MAX77857_REG_INT_SRC;
+ case ID_MAX77859:
+ case ID_MAX77859A:
+ return reg == MAX77859_REG_INT_SRC;
+ default:
+ return true;
+ }
+}
+
+static struct regmap_config max77857_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = max77857_volatile_reg,
+};
+
+static int max77857_get_status(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(MAX77857_INT_SRC_POK, val))
+ return REGULATOR_STATUS_ON;
+
+ return REGULATOR_STATUS_ERROR;
+}
+
+static unsigned int max77857_get_mode(struct regulator_dev *rdev)
+{
+ enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
+ unsigned int regval;
+ int ret;
+
+ switch (id) {
+ case ID_MAX77831:
+ case ID_MAX77857:
+ ret = regmap_read(rdev->regmap, MAX77857_REG_CONT3, &regval);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(MAX77857_CONT3_FPWM, regval))
+ return REGULATOR_MODE_FAST;
+
+ break;
+ case ID_MAX77859:
+ case ID_MAX77859A:
+ ret = regmap_read(rdev->regmap, MAX77859_REG_CONT2, &regval);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(MAX77859_CONT2_FPWM, regval))
+ return REGULATOR_MODE_FAST;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int max77857_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev);
+ unsigned int reg, val;
+
+ switch (id) {
+ case ID_MAX77831:
+ case ID_MAX77857:
+ reg = MAX77857_REG_CONT3;
+ val = MAX77857_CONT3_FPWM;
+ break;
+ case ID_MAX77859:
+ case ID_MAX77859A:
+ reg = MAX77859_REG_CONT2;
+ val = MAX77859_CONT2_FPWM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ return regmap_set_bits(rdev->regmap, reg, val);
+ case REGULATOR_MODE_NORMAL:
+ return regmap_clear_bits(rdev->regmap, reg, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max77857_get_error_flags(struct regulator_dev *rdev,
+ unsigned int *flags)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, MAX77857_REG_INT_SRC, &val);
+ if (ret)
+ return ret;
+
+ *flags = 0;
+
+ if (FIELD_GET(MAX77857_INT_SRC_OVP, val))
+ *flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN;
+
+ if (FIELD_GET(MAX77857_INT_SRC_OCP, val) ||
+ FIELD_GET(MAX77857_INT_SRC_HARDSHORT, val))
+ *flags |= REGULATOR_ERROR_OVER_CURRENT;
+
+ if (FIELD_GET(MAX77857_INT_SRC_THS, val))
+ *flags |= REGULATOR_ERROR_OVER_TEMP;
+
+ if (!FIELD_GET(MAX77857_INT_SRC_POK, val))
+ *flags |= REGULATOR_ERROR_FAIL;
+
+ return 0;
+}
+
+static struct linear_range max77859_lin_ranges[] = {
+ REGULATOR_LINEAR_RANGE(3200000, 0x0A0, 0x320, 20000)
+};
+
+static const unsigned int max77859_ramp_table[4] = {
+ 1000, 500, 250, 125
+};
+
+static int max77859_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ __be16 reg;
+ int ret;
+
+ reg = cpu_to_be16(sel);
+
+ ret = regmap_bulk_write(rdev->regmap, MAX77859_REG_CONT3, &reg, 2);
+ if (ret)
+ return ret;
+
+ /* actually apply new voltage */
+ return regmap_set_bits(rdev->regmap, MAX77859_REG_CONT3,
+ MAX77859_CONT3_DVS_START);
+}
+
+static int max77859_get_voltage_sel(struct regulator_dev *rdev)
+{
+ __be16 reg;
+ int ret;
+
+ ret = regmap_bulk_read(rdev->regmap, MAX77859_REG_CONT3, &reg, 2);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(MAX77859_VOLTAGE_SEL_MASK, __be16_to_cpu(reg));
+}
+
+static int max77859_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
+{
+ u32 selector;
+
+ if (max_uA < MAX77859_CURRENT_MIN)
+ return -EINVAL;
+
+ selector = 0x12 + (max_uA - MAX77859_CURRENT_MIN) / MAX77859_CURRENT_STEP;
+
+ selector = clamp_val(selector, 0x00, 0x7F);
+
+ return regmap_write(rdev->regmap, MAX77859_REG_CONT5, selector);
+}
+
+static int max77859_get_current_limit(struct regulator_dev *rdev)
+{
+ u32 selector;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, MAX77859_REG_CONT5, &selector);
+ if (ret)
+ return ret;
+
+ if (selector <= 0x12)
+ return MAX77859_CURRENT_MIN;
+
+ if (selector >= 0x64)
+ return MAX77859_CURRENT_MAX;
+
+ return MAX77859_CURRENT_MIN + (selector - 0x12) * MAX77859_CURRENT_STEP;
+}
+
+static const struct regulator_ops max77859_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = max77859_set_voltage_sel,
+ .get_voltage_sel = max77859_get_voltage_sel,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .get_status = max77857_get_status,
+ .set_mode = max77857_set_mode,
+ .get_mode = max77857_get_mode,
+ .get_error_flags = max77857_get_error_flags,
+};
+
+static const struct regulator_ops max77859a_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = max77859_set_voltage_sel,
+ .get_voltage_sel = max77859_get_voltage_sel,
+ .set_current_limit = max77859_set_current_limit,
+ .get_current_limit = max77859_get_current_limit,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .get_status = max77857_get_status,
+ .set_mode = max77857_set_mode,
+ .get_mode = max77857_get_mode,
+ .get_error_flags = max77857_get_error_flags,
+};
+
+static const struct regulator_ops max77857_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+ .get_status = max77857_get_status,
+ .set_mode = max77857_set_mode,
+ .get_mode = max77857_get_mode,
+ .get_error_flags = max77857_get_error_flags,
+};
+
+static struct linear_range max77857_lin_ranges[] = {
+ REGULATOR_LINEAR_RANGE(4485000, 0x3D, 0xCC, 73500)
+};
+
+static const unsigned int max77857_switch_freq[] = {
+ 1200000, 1500000, 1800000, 2100000
+};
+
+#define RAMAP_DELAY_INIT_VAL 1333
+
+static const unsigned int max77857_ramp_table[2][4] = {
+ { RAMAP_DELAY_INIT_VAL, 667, 333, 227 }, /* when switch freq is 1.8MHz or 2.1MHz */
+ { 1166, 667, 333, 167 }, /* when switch freq is 1.2MHz or 1.5MHz */
+};
+
+static struct regulator_desc max77857_regulator_desc = {
+ .ops = &max77857_regulator_ops,
+ .name = "max77857",
+ .linear_ranges = max77857_lin_ranges,
+ .n_linear_ranges = ARRAY_SIZE(max77857_lin_ranges),
+ .vsel_mask = 0xFF,
+ .vsel_reg = MAX77857_REG_CONT2,
+ .ramp_delay_table = max77857_ramp_table[0],
+ .n_ramp_values = ARRAY_SIZE(max77857_ramp_table[0]),
+ .ramp_reg = MAX77857_REG_CONT3,
+ .ramp_mask = GENMASK(1, 0),
+ .ramp_delay = RAMAP_DELAY_INIT_VAL,
+ .owner = THIS_MODULE,
+};
+
+static void max77857_calc_range(struct device *dev, enum max77857_id id)
+{
+ struct linear_range *range;
+ unsigned long vref_step;
+ u32 rtop = 0;
+ u32 rbot = 0;
+
+ device_property_read_u32(dev, "adi,rtop-ohms", &rtop);
+ device_property_read_u32(dev, "adi,rbot-ohms", &rbot);
+
+ if (!rbot || !rtop)
+ return;
+
+ switch (id) {
+ case ID_MAX77831:
+ case ID_MAX77857:
+ range = max77857_lin_ranges;
+ vref_step = 4900UL;
+ break;
+ case ID_MAX77859:
+ case ID_MAX77859A:
+ range = max77859_lin_ranges;
+ vref_step = 1250UL;
+ break;
+ }
+
+ range->step = DIV_ROUND_CLOSEST(vref_step * (rbot + rtop), rbot);
+ range->min = range->step * range->min_sel;
+}
+
+static int max77857_probe(struct i2c_client *client)
+{
+ const struct i2c_device_id *i2c_id;
+ struct device *dev = &client->dev;
+ struct regulator_config cfg = { };
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ enum max77857_id id;
+ u32 switch_freq = 0;
+ int ret;
+
+ i2c_id = i2c_client_get_device_id(client);
+ if (!i2c_id)
+ return -EINVAL;
+
+ id = i2c_id->driver_data;
+
+ dev_set_drvdata(dev, (void *)id);
+
+ if (id == ID_MAX77859 || id == ID_MAX77859A) {
+ max77857_regulator_desc.ops = &max77859_regulator_ops;
+ max77857_regulator_desc.linear_ranges = max77859_lin_ranges;
+ max77857_regulator_desc.ramp_delay_table = max77859_ramp_table;
+ max77857_regulator_desc.ramp_delay = max77859_ramp_table[0];
+ }
+
+ if (id == ID_MAX77859A)
+ max77857_regulator_desc.ops = &max77859a_regulator_ops;
+
+ max77857_calc_range(dev, id);
+
+ regmap = devm_regmap_init_i2c(client, &max77857_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "cannot initialize regmap\n");
+
+ device_property_read_u32(dev, "adi,switch-frequency-hz", &switch_freq);
+ if (switch_freq) {
+ switch_freq = find_closest(switch_freq, max77857_switch_freq,
+ ARRAY_SIZE(max77857_switch_freq));
+
+ if (id == ID_MAX77831 && switch_freq == 3)
+ switch_freq = 2;
+
+ switch (id) {
+ case ID_MAX77831:
+ case ID_MAX77857:
+ ret = regmap_update_bits(regmap, MAX77857_REG_CONT1,
+ MAX77857_CONT1_FREQ, switch_freq);
+
+ if (switch_freq >= 2)
+ break;
+
+ max77857_regulator_desc.ramp_delay_table = max77857_ramp_table[1];
+ max77857_regulator_desc.ramp_delay = max77857_ramp_table[1][0];
+ break;
+ case ID_MAX77859:
+ case ID_MAX77859A:
+ ret = regmap_update_bits(regmap, MAX77859_REG_CONT1,
+ MAX77857_CONT1_FREQ, switch_freq);
+ break;
+ }
+ if (ret)
+ return ret;
+ }
+
+ cfg.dev = dev;
+ cfg.driver_data = (void *)id;
+ cfg.regmap = regmap;
+ cfg.init_data = of_get_regulator_init_data(dev, dev->of_node,
+ &max77857_regulator_desc);
+ if (!cfg.init_data)
+ return -ENOMEM;
+
+ rdev = devm_regulator_register(dev, &max77857_regulator_desc, &cfg);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "cannot register regulator\n");
+
+ return 0;
+}
+
+const struct i2c_device_id max77857_id[] = {
+ { "max77831", ID_MAX77831 },
+ { "max77857", ID_MAX77857 },
+ { "max77859", ID_MAX77859 },
+ { "max77859a", ID_MAX77859A },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max77857_id);
+
+static const struct of_device_id max77857_of_id[] = {
+ { .compatible = "adi,max77831", .data = (void *)ID_MAX77831 },
+ { .compatible = "adi,max77857", .data = (void *)ID_MAX77857 },
+ { .compatible = "adi,max77859", .data = (void *)ID_MAX77859 },
+ { .compatible = "adi,max77859a", .data = (void *)ID_MAX77859A },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max77857_of_id);
+
+static struct i2c_driver max77857_driver = {
+ .driver = {
+ .name = "max77857",
+ .of_match_table = max77857_of_id,
+ },
+ .id_table = max77857_id,
+ .probe = max77857_probe,
+};
+module_i2c_driver(max77857_driver);
+
+MODULE_DESCRIPTION("Analog Devices MAX77857 Buck-Boost Converter Driver");
+MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
+MODULE_AUTHOR("Okan Sahin <Okan.Sahin@analog.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max8893.c b/drivers/regulator/max8893.c
index cb0e72948dd4..30592425e193 100644
--- a/drivers/regulator/max8893.c
+++ b/drivers/regulator/max8893.c
@@ -125,7 +125,7 @@ static const struct regmap_config max8893_regmap = {
.val_bits = 8,
};
-static int max8893_probe_new(struct i2c_client *i2c)
+static int max8893_probe(struct i2c_client *i2c)
{
int id, ret;
struct regulator_config config = {.dev = &i2c->dev};
@@ -168,7 +168,7 @@ static const struct i2c_device_id max8893_ids[] = {
MODULE_DEVICE_TABLE(i2c, max8893_ids);
static struct i2c_driver max8893_driver = {
- .probe = max8893_probe_new,
+ .probe = max8893_probe,
.driver = {
.name = "max8893",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c
index 6c6f5a21362b..0c15a19fe83a 100644
--- a/drivers/regulator/mcp16502.c
+++ b/drivers/regulator/mcp16502.c
@@ -8,7 +8,6 @@
//
// Inspired from tps65086-regulator.c
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -111,7 +110,7 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
#define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table) \
[_id] = { \
.name = _name, \
- .regulators_node = of_match_ptr("regulators"), \
+ .regulators_node = "regulators", \
.id = _id, \
.ops = &(_ops), \
.type = REGULATOR_VOLTAGE, \
@@ -120,7 +119,7 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode)
.linear_ranges = _ranges, \
.linear_min_sel = VDD_LOW_SEL, \
.n_linear_ranges = ARRAY_SIZE(_ranges), \
- .of_match = of_match_ptr(_name), \
+ .of_match = _name, \
.of_map_mode = mcp16502_of_map_mode, \
.vsel_reg = (((_id) + 1) << 4), \
.vsel_mask = MCP16502_VSEL, \
@@ -588,7 +587,7 @@ static struct i2c_driver mcp16502_drv = {
.driver = {
.name = "mcp16502-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(mcp16502_ids),
+ .of_match_table = mcp16502_ids,
#ifdef CONFIG_PM
.pm = &mcp16502_pm_ops,
#endif
diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c
index 3886b252fbe7..d068ac93d373 100644
--- a/drivers/regulator/mp5416.c
+++ b/drivers/regulator/mp5416.c
@@ -10,7 +10,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c
index ede1b1e58002..9911be2e6bac 100644
--- a/drivers/regulator/mp886x.c
+++ b/drivers/regulator/mp886x.c
@@ -9,7 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/mpq7920.c b/drivers/regulator/mpq7920.c
index bf677c535edc..a670e09891e7 100644
--- a/drivers/regulator/mpq7920.c
+++ b/drivers/regulator/mpq7920.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
@@ -319,7 +318,7 @@ static struct i2c_driver mpq7920_regulator_driver = {
.driver = {
.name = "mpq7920",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(mpq7920_of_match),
+ .of_match_table = mpq7920_of_match,
},
.probe = mpq7920_i2c_probe,
.id_table = mpq7920_id,
diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c
index b0771770cc26..63a51485f2cc 100644
--- a/drivers/regulator/mt6311-regulator.c
+++ b/drivers/regulator/mt6311-regulator.c
@@ -4,7 +4,6 @@
// Author: Henry Chen <henryc.chen@mediatek.com>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/regulator/mt6315-regulator.c b/drivers/regulator/mt6315-regulator.c
index 8047081ea2f7..2608a6652d77 100644
--- a/drivers/regulator/mt6315-regulator.c
+++ b/drivers/regulator/mt6315-regulator.c
@@ -3,7 +3,7 @@
// Copyright (c) 2021 MediaTek Inc.
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
index 3eb86ec21d08..c8a788858824 100644
--- a/drivers/regulator/mt6359-regulator.c
+++ b/drivers/regulator/mt6359-regulator.c
@@ -7,7 +7,7 @@
#include <linux/mfd/mt6359p/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
diff --git a/drivers/regulator/mtk-dvfsrc-regulator.c b/drivers/regulator/mtk-dvfsrc-regulator.c
index efca67207a5a..f1280d45265d 100644
--- a/drivers/regulator/mtk-dvfsrc-regulator.c
+++ b/drivers/regulator/mtk-dvfsrc-regulator.c
@@ -6,8 +6,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of_.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/soc/mediatek/mtk_dvfsrc.h>
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
index 0c9873e9abdc..cd5a0d7e4455 100644
--- a/drivers/regulator/pbias-regulator.c
+++ b/drivers/regulator/pbias-regulator.c
@@ -25,7 +25,6 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
struct pbias_reg_info {
u32 enable;
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index 91bfb7e026c9..2ab365d2749f 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 8d7e6c323324..46854602b3ea 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -699,8 +699,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client)
return -ENOMEM;
if (client->dev.of_node) {
- match = of_match_device(of_match_ptr(pfuze_dt_ids),
- &client->dev);
+ match = of_match_device(pfuze_dt_ids, &client->dev);
if (!match) {
dev_err(&client->dev, "Error: No device match found\n");
return -ENODEV;
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index b64d99695b84..2aff6db748e2 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -10,11 +10,11 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pwm.h>
#include <linux/gpio/consumer.h>
diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c
new file mode 100644
index 000000000000..656fe330d38f
--- /dev/null
+++ b/drivers/regulator/qcom-refgen-regulator.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2017, 2019-2020, The Linux Foundation. All rights reserved.
+// Copyright (c) 2023, Linaro Limited
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define REFGEN_REG_BIAS_EN 0x08
+#define REFGEN_BIAS_EN_MASK GENMASK(2, 0)
+ #define REFGEN_BIAS_EN_ENABLE 0x7
+ #define REFGEN_BIAS_EN_DISABLE 0x6
+
+#define REFGEN_REG_BG_CTRL 0x14
+#define REFGEN_BG_CTRL_MASK GENMASK(2, 1)
+ #define REFGEN_BG_CTRL_ENABLE 0x3
+ #define REFGEN_BG_CTRL_DISABLE 0x2
+
+#define REFGEN_REG_PWRDWN_CTRL5 0x80
+#define REFGEN_PWRDWN_CTRL5_MASK BIT(0)
+ #define REFGEN_PWRDWN_CTRL5_ENABLE 0x1
+
+static int qcom_sdm845_refgen_enable(struct regulator_dev *rdev)
+{
+ regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
+ FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_ENABLE));
+
+ regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
+ FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_ENABLE));
+
+ return 0;
+}
+
+static int qcom_sdm845_refgen_disable(struct regulator_dev *rdev)
+{
+ regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
+ FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_DISABLE));
+
+ regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
+ FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_DISABLE));
+
+ return 0;
+}
+
+static int qcom_sdm845_refgen_is_enabled(struct regulator_dev *rdev)
+{
+ u32 val;
+
+ regmap_read(rdev->regmap, REFGEN_REG_BG_CTRL, &val);
+ if (FIELD_GET(REFGEN_BG_CTRL_MASK, val) != REFGEN_BG_CTRL_ENABLE)
+ return 0;
+
+ regmap_read(rdev->regmap, REFGEN_REG_BIAS_EN, &val);
+ if (FIELD_GET(REFGEN_BIAS_EN_MASK, val) != REFGEN_BIAS_EN_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+static struct regulator_desc sdm845_refgen_desc = {
+ .enable_time = 5,
+ .name = "refgen",
+ .owner = THIS_MODULE,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &(const struct regulator_ops) {
+ .enable = qcom_sdm845_refgen_enable,
+ .disable = qcom_sdm845_refgen_disable,
+ .is_enabled = qcom_sdm845_refgen_is_enabled,
+ },
+};
+
+static struct regulator_desc sm8250_refgen_desc = {
+ .enable_reg = REFGEN_REG_PWRDWN_CTRL5,
+ .enable_mask = REFGEN_PWRDWN_CTRL5_MASK,
+ .enable_val = REFGEN_PWRDWN_CTRL5_ENABLE,
+ .disable_val = 0,
+ .enable_time = 5,
+ .name = "refgen",
+ .owner = THIS_MODULE,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &(const struct regulator_ops) {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ },
+};
+
+static const struct regmap_config qcom_refgen_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+};
+
+static int qcom_refgen_probe(struct platform_device *pdev)
+{
+ struct regulator_init_data *init_data;
+ struct regulator_config config = {};
+ const struct regulator_desc *rdesc;
+ struct device *dev = &pdev->dev;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+ void __iomem *base;
+
+ rdesc = of_device_get_match_data(dev);
+ if (!rdesc)
+ return -ENODATA;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &qcom_refgen_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ init_data = of_get_regulator_init_data(dev, dev->of_node, rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ config.dev = dev;
+ config.init_data = init_data;
+ config.of_node = dev->of_node;
+ config.regmap = regmap;
+
+ rdev = devm_regulator_register(dev, rdesc, &config);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ return 0;
+}
+
+static const struct of_device_id qcom_refgen_match_table[] = {
+ { .compatible = "qcom,sdm845-refgen-regulator", .data = &sdm845_refgen_desc },
+ { .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc },
+ { }
+};
+
+static struct platform_driver qcom_refgen_driver = {
+ .probe = qcom_refgen_probe,
+ .driver = {
+ .name = "qcom-refgen-regulator",
+ .of_match_table = qcom_refgen_match_table,
+ },
+};
+module_platform_driver(qcom_refgen_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm REFGEN regulator driver");
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index cd077b7c4aff..d990ba19c50e 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -1273,6 +1272,40 @@ static const struct rpmh_vreg_init_data pmx65_vreg_data[] = {
{}
};
+static const struct rpmh_vreg_init_data pmx75_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo515, "vdd-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo515, "vdd-l17"),
+ /* ldo18 not configured */
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo515, "vdd-l19"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo515, "vdd-l20-l21"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo515, "vdd-l20-l21"),
+};
+
static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
@@ -1495,6 +1528,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.data = pmx65_vreg_data,
},
{
+ .compatible = "qcom,pmx75-rpmh-regulators",
+ .data = pmx75_vreg_data,
+ },
+ {
.compatible = "qcom,pm7325-rpmh-regulators",
.data = pm7325_vreg_data,
},
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
index f95bc9208c13..9366488f0383 100644
--- a/drivers/regulator/qcom_rpm-regulator.c
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -956,11 +956,10 @@ static int rpm_reg_probe(struct platform_device *pdev)
}
for (reg = match->data; reg->name; reg++) {
- vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
+ vreg = devm_kmemdup(&pdev->dev, reg->template, sizeof(*vreg), GFP_KERNEL);
if (!vreg)
return -ENOMEM;
- memcpy(vreg, reg->template, sizeof(*vreg));
mutex_init(&vreg->lock);
vreg->dev = &pdev->dev;
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index 18189f35db68..f53ada076252 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/qcom_usb_vbus-regulator.c b/drivers/regulator/qcom_usb_vbus-regulator.c
index 57ec613f4a0a..cd94ed67621f 100644
--- a/drivers/regulator/qcom_usb_vbus-regulator.c
+++ b/drivers/regulator/qcom_usb_vbus-regulator.c
@@ -8,7 +8,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/raa215300.c b/drivers/regulator/raa215300.c
index 24a1c89f5dbc..6982565c8aa4 100644
--- a/drivers/regulator/raa215300.c
+++ b/drivers/regulator/raa215300.c
@@ -38,10 +38,6 @@
#define RAA215300_REG_BLOCK_EN_RTC_EN BIT(6)
#define RAA215300_RTC_DEFAULT_ADDR 0x6f
-const char *clkin_name = "clkin";
-const char *xin_name = "xin";
-static struct clk *clk;
-
static const struct regmap_config raa215300_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -51,10 +47,6 @@ static const struct regmap_config raa215300_regmap_config = {
static void raa215300_rtc_unregister_device(void *data)
{
i2c_unregister_device(data);
- if (!clk) {
- clk_unregister_fixed_rate(clk);
- clk = NULL;
- }
}
static int raa215300_clk_present(struct i2c_client *client, const char *name)
@@ -71,8 +63,10 @@ static int raa215300_clk_present(struct i2c_client *client, const char *name)
static int raa215300_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- const char *clk_name = xin_name;
+ const char *clkin_name = "clkin";
unsigned int pmic_version, val;
+ const char *xin_name = "xin";
+ const char *clk_name = NULL;
struct regmap *regmap;
int ret;
@@ -92,7 +86,7 @@ static int raa215300_i2c_probe(struct i2c_client *client)
val &= RAA215300_REG_BLOCK_EN_RTC_EN;
regmap_write(regmap, RAA215300_REG_BLOCK_EN, val);
- /*Clear the latched registers */
+ /* Clear the latched registers */
regmap_read(regmap, RAA215300_FAULT_LATCHED_STATUS_1, &val);
regmap_write(regmap, RAA215300_FAULT_LATCHED_STATUS_1, val);
regmap_read(regmap, RAA215300_FAULT_LATCHED_STATUS_2, &val);
@@ -114,24 +108,32 @@ static int raa215300_i2c_probe(struct i2c_client *client)
ret = raa215300_clk_present(client, xin_name);
if (ret < 0) {
return ret;
- } else if (!ret) {
+ } else if (ret) {
+ clk_name = xin_name;
+ } else {
ret = raa215300_clk_present(client, clkin_name);
if (ret < 0)
return ret;
-
- clk_name = clkin_name;
+ if (ret)
+ clk_name = clkin_name;
}
- if (ret) {
- char *name = pmic_version >= 0x12 ? "isl1208" : "raa215300_a0";
+ if (clk_name) {
+ const char *name = pmic_version >= 0x12 ? "isl1208" : "raa215300_a0";
struct device_node *np = client->dev.of_node;
u32 addr = RAA215300_RTC_DEFAULT_ADDR;
struct i2c_board_info info = {};
struct i2c_client *rtc_client;
+ struct clk_hw *hw;
ssize_t size;
- clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 32000);
- clk_register_clkdev(clk, clk_name, NULL);
+ hw = devm_clk_hw_register_fixed_rate(dev, clk_name, NULL, 0, 32768);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ ret = devm_clk_hw_register_clkdev(dev, hw, clk_name, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to initialize clkdev\n");
if (np) {
int i;
@@ -180,7 +182,7 @@ static struct i2c_driver raa215300_i2c_driver = {
.name = "raa215300",
.of_match_table = raa215300_dt_match,
},
- .probe_new = raa215300_i2c_probe,
+ .probe = raa215300_i2c_probe,
};
module_i2c_driver(raa215300_i2c_driver);
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
index a5afca73715d..a25a141e86c4 100644
--- a/drivers/regulator/rc5t583-regulator.c
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/gpio.h>
#include <linux/mfd/rc5t583.h>
struct rc5t583_regulator_info {
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 460525ed006c..867a2cf243f6 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -17,9 +17,10 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mfd/rk808.h>
+#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/gpio/consumer.h>
diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c
index f97a9a51ee76..0e2418ed957c 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -36,7 +36,7 @@ static int set_dvs_level(const struct regulator_desc *desc,
}
for (i = 0; i < desc->n_voltages; i++) {
/* NOTE to next hacker - Does not support pickable ranges */
- if (desc->linear_range_selectors)
+ if (desc->linear_range_selectors_bitfield)
return -EINVAL;
if (desc->n_linear_ranges)
ret = regulator_desc_list_voltage_linear_range(desc, i);
diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c
index e9719a378a0b..f52c3d47ecea 100644
--- a/drivers/regulator/rpi-panel-attiny-regulator.c
+++ b/drivers/regulator/rpi-panel-attiny-regulator.c
@@ -7,7 +7,6 @@
#include <linux/backlight.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -397,7 +396,7 @@ static struct i2c_driver attiny_regulator_driver = {
.driver = {
.name = "rpi_touchscreen_attiny",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(attiny_dt_ids),
+ .of_match_table = attiny_dt_ids,
},
.probe = attiny_i2c_probe,
.remove = attiny_i2c_remove,
diff --git a/drivers/regulator/rt5739.c b/drivers/regulator/rt5739.c
index 0ce6a1666752..91412c905ce6 100644
--- a/drivers/regulator/rt5739.c
+++ b/drivers/regulator/rt5739.c
@@ -31,10 +31,17 @@
#define RT5739_MODEVSEL1_MASK BIT(1)
#define RT5739_MODEVSEL0_MASK BIT(0)
#define RT5739_VID_MASK GENMASK(7, 5)
+#define RT5739_DID_MASK GENMASK(3, 0)
#define RT5739_ACTD_MASK BIT(7)
#define RT5739_ENVSEL1_MASK BIT(1)
#define RT5739_ENVSEL0_MASK BIT(0)
+#define RT5733_CHIPDIE_ID 0x1
+#define RT5733_VOLT_MINUV 270000
+#define RT5733_VOLT_MAXUV 1401250
+#define RT5733_VOLT_STPUV 6250
+#define RT5733_N_VOLTS 182
+
#define RT5739_VOLT_MINUV 300000
#define RT5739_VOLT_MAXUV 1300000
#define RT5739_VOLT_STPUV 5000
@@ -93,8 +100,11 @@ static int rt5739_set_suspend_voltage(struct regulator_dev *rdev, int uV)
const struct regulator_desc *desc = rdev->desc;
struct regmap *regmap = rdev_get_regmap(rdev);
unsigned int reg, vsel;
+ int max_uV;
+
+ max_uV = desc->min_uV + desc->uV_step * (desc->n_voltages - 1);
- if (uV < RT5739_VOLT_MINUV || uV > RT5739_VOLT_MAXUV)
+ if (uV < desc->min_uV || uV > max_uV)
return -EINVAL;
if (desc->vsel_reg == RT5739_REG_NSEL0)
@@ -102,7 +112,7 @@ static int rt5739_set_suspend_voltage(struct regulator_dev *rdev, int uV)
else
reg = RT5739_REG_NSEL0;
- vsel = (uV - RT5739_VOLT_MINUV) / RT5739_VOLT_STPUV;
+ vsel = (uV - desc->min_uV) / desc->uV_step;
return regmap_write(regmap, reg, vsel);
}
@@ -189,15 +199,12 @@ static unsigned int rt5739_of_map_mode(unsigned int mode)
}
static void rt5739_init_regulator_desc(struct regulator_desc *desc,
- bool vsel_active_high)
+ bool vsel_active_high, u8 did)
{
/* Fixed */
desc->name = "rt5739-regulator";
desc->owner = THIS_MODULE;
desc->ops = &rt5739_regulator_ops;
- desc->n_voltages = RT5739_N_VOLTS;
- desc->min_uV = RT5739_VOLT_MINUV;
- desc->uV_step = RT5739_VOLT_STPUV;
desc->vsel_mask = RT5739_VSEL_MASK;
desc->enable_reg = RT5739_REG_CNTL2;
desc->active_discharge_reg = RT5739_REG_CNTL1;
@@ -213,6 +220,20 @@ static void rt5739_init_regulator_desc(struct regulator_desc *desc,
desc->vsel_reg = RT5739_REG_NSEL0;
desc->enable_mask = RT5739_ENVSEL0_MASK;
}
+
+ /* Assigned by CHIPDIE ID */
+ switch (did) {
+ case RT5733_CHIPDIE_ID:
+ desc->n_voltages = RT5733_N_VOLTS;
+ desc->min_uV = RT5733_VOLT_MINUV;
+ desc->uV_step = RT5733_VOLT_STPUV;
+ break;
+ default:
+ desc->n_voltages = RT5739_N_VOLTS;
+ desc->min_uV = RT5739_VOLT_MINUV;
+ desc->uV_step = RT5739_VOLT_STPUV;
+ break;
+ }
}
static const struct regmap_config rt5739_regmap_config = {
@@ -258,7 +279,7 @@ static int rt5739_probe(struct i2c_client *i2c)
vsel_acth = device_property_read_bool(dev, "richtek,vsel-active-high");
- rt5739_init_regulator_desc(desc, vsel_acth);
+ rt5739_init_regulator_desc(desc, vsel_acth, vid & RT5739_DID_MASK);
cfg.dev = dev;
cfg.of_node = dev_of_node(dev);
@@ -271,6 +292,7 @@ static int rt5739_probe(struct i2c_client *i2c)
}
static const struct of_device_id rt5739_device_table[] = {
+ { .compatible = "richtek,rt5733" },
{ .compatible = "richtek,rt5739" },
{ /* sentinel */ }
};
diff --git a/drivers/regulator/rt5759-regulator.c b/drivers/regulator/rt5759-regulator.c
index 90555a9ef1b0..c2553dcee050 100644
--- a/drivers/regulator/rt5759-regulator.c
+++ b/drivers/regulator/rt5759-regulator.c
@@ -4,7 +4,7 @@
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/rtq2208-regulator.c b/drivers/regulator/rtq2208-regulator.c
new file mode 100644
index 000000000000..2d54844c4226
--- /dev/null
+++ b/drivers/regulator/rtq2208-regulator.c
@@ -0,0 +1,583 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/util_macros.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mod_devicetable.h>
+
+/* Register */
+#define RTQ2208_REG_GLOBAL_INT1 0x12
+#define RTQ2208_REG_FLT_RECORDBUCK_CB 0x18
+#define RTQ2208_REG_GLOBAL_INT1_MASK 0x1D
+#define RTQ2208_REG_FLT_MASKBUCK_CB 0x1F
+#define RTQ2208_REG_BUCK_C_CFG0 0x32
+#define RTQ2208_REG_BUCK_B_CFG0 0x42
+#define RTQ2208_REG_BUCK_A_CFG0 0x52
+#define RTQ2208_REG_BUCK_D_CFG0 0x62
+#define RTQ2208_REG_BUCK_G_CFG0 0x72
+#define RTQ2208_REG_BUCK_F_CFG0 0x82
+#define RTQ2208_REG_BUCK_E_CFG0 0x92
+#define RTQ2208_REG_BUCK_H_CFG0 0xA2
+#define RTQ2208_REG_LDO1_CFG 0xB1
+#define RTQ2208_REG_LDO2_CFG 0xC1
+
+/* Mask */
+#define RTQ2208_BUCK_NR_MTP_SEL_MASK GENMASK(7, 0)
+#define RTQ2208_BUCK_EN_NR_MTP_SEL0_MASK BIT(0)
+#define RTQ2208_BUCK_EN_NR_MTP_SEL1_MASK BIT(1)
+#define RTQ2208_BUCK_RSPUP_MASK GENMASK(6, 4)
+#define RTQ2208_BUCK_RSPDN_MASK GENMASK(2, 0)
+#define RTQ2208_BUCK_NRMODE_MASK BIT(5)
+#define RTQ2208_BUCK_STRMODE_MASK BIT(5)
+#define RTQ2208_BUCK_EN_STR_MASK BIT(0)
+#define RTQ2208_LDO_EN_STR_MASK BIT(7)
+#define RTQ2208_EN_DIS_MASK BIT(0)
+#define RTQ2208_BUCK_RAMP_SEL_MASK GENMASK(2, 0)
+#define RTQ2208_HD_INT_MASK BIT(0)
+
+/* Size */
+#define RTQ2208_VOUT_MAXNUM 256
+#define RTQ2208_BUCK_NUM_IRQ_REGS 5
+#define RTQ2208_STS_NUM_IRQ_REGS 2
+
+/* Value */
+#define RTQ2208_RAMP_VALUE_MIN_uV 500
+#define RTQ2208_RAMP_VALUE_MAX_uV 64000
+
+#define RTQ2208_BUCK_MASK(uv_irq, ov_irq) (1 << ((uv_irq) % 8) | 1 << ((ov_irq) % 8))
+
+enum {
+ RTQ2208_BUCK_B = 0,
+ RTQ2208_BUCK_C,
+ RTQ2208_BUCK_D,
+ RTQ2208_BUCK_A,
+ RTQ2208_BUCK_F,
+ RTQ2208_BUCK_G,
+ RTQ2208_BUCK_H,
+ RTQ2208_BUCK_E,
+ RTQ2208_LDO2,
+ RTQ2208_LDO1,
+ RTQ2208_LDO_MAX,
+};
+
+enum {
+ RTQ2208_AUTO_MODE = 0,
+ RTQ2208_FCCM,
+};
+
+struct rtq2208_regulator_desc {
+ struct regulator_desc desc;
+ unsigned int mtp_sel_reg;
+ unsigned int mtp_sel_mask;
+ unsigned int mode_reg;
+ unsigned int mode_mask;
+ unsigned int suspend_config_reg;
+ unsigned int suspend_enable_mask;
+ unsigned int suspend_mode_mask;
+};
+
+struct rtq2208_rdev_map {
+ struct regulator_dev *rdev[RTQ2208_LDO_MAX];
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+/* set Normal Auto/FCCM mode */
+static int rtq2208_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ const struct rtq2208_regulator_desc *rdesc =
+ (const struct rtq2208_regulator_desc *)rdev->desc;
+ unsigned int val, shift;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = RTQ2208_AUTO_MODE;
+ break;
+ case REGULATOR_MODE_FAST:
+ val = RTQ2208_FCCM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ shift = ffs(rdesc->mode_mask) - 1;
+ return regmap_update_bits(rdev->regmap, rdesc->mode_reg,
+ rdesc->mode_mask, val << shift);
+}
+
+static unsigned int rtq2208_get_mode(struct regulator_dev *rdev)
+{
+ const struct rtq2208_regulator_desc *rdesc =
+ (const struct rtq2208_regulator_desc *)rdev->desc;
+ unsigned int mode_val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdesc->mode_reg, &mode_val);
+ if (ret)
+ return REGULATOR_MODE_INVALID;
+
+ return (mode_val & rdesc->mode_mask) ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static int rtq2208_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ const struct regulator_desc *desc = rdev->desc;
+ unsigned int sel = 0, val;
+
+ ramp_delay = max(ramp_delay, RTQ2208_RAMP_VALUE_MIN_uV);
+ ramp_delay = min(ramp_delay, RTQ2208_RAMP_VALUE_MAX_uV);
+
+ ramp_delay /= RTQ2208_RAMP_VALUE_MIN_uV;
+
+ /*
+ * fls(ramp_delay) - 1: doing LSB shift, let it starts from 0
+ *
+ * RTQ2208_BUCK_RAMP_SEL_MASK - sel: doing descending order shifting.
+ * Because the relation of seleltion and value is like that
+ *
+ * seletion: value
+ * 000: 64mv
+ * 001: 32mv
+ * ...
+ * 111: 0.5mv
+ *
+ * For example, if I would like to select 64mv, the fls(ramp_delay) - 1 will be 0b111,
+ * and I need to use 0b111 - sel to do the shifting
+ */
+
+ sel = fls(ramp_delay) - 1;
+ sel = RTQ2208_BUCK_RAMP_SEL_MASK - sel;
+
+ val = FIELD_PREP(RTQ2208_BUCK_RSPUP_MASK, sel) | FIELD_PREP(RTQ2208_BUCK_RSPDN_MASK, sel);
+
+ return regmap_update_bits(rdev->regmap, desc->ramp_reg,
+ RTQ2208_BUCK_RSPUP_MASK | RTQ2208_BUCK_RSPDN_MASK, val);
+}
+
+static int rtq2208_set_suspend_enable(struct regulator_dev *rdev)
+{
+ const struct rtq2208_regulator_desc *rdesc =
+ (const struct rtq2208_regulator_desc *)rdev->desc;
+
+ return regmap_set_bits(rdev->regmap, rdesc->suspend_config_reg, rdesc->suspend_enable_mask);
+}
+
+static int rtq2208_set_suspend_disable(struct regulator_dev *rdev)
+{
+ const struct rtq2208_regulator_desc *rdesc =
+ (const struct rtq2208_regulator_desc *)rdev->desc;
+
+ return regmap_update_bits(rdev->regmap, rdesc->suspend_config_reg, rdesc->suspend_enable_mask, 0);
+}
+
+static int rtq2208_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ const struct rtq2208_regulator_desc *rdesc =
+ (const struct rtq2208_regulator_desc *)rdev->desc;
+ unsigned int val, shift;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = RTQ2208_AUTO_MODE;
+ break;
+ case REGULATOR_MODE_FAST:
+ val = RTQ2208_FCCM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ shift = ffs(rdesc->suspend_mode_mask) - 1;
+
+ return regmap_update_bits(rdev->regmap, rdesc->suspend_config_reg,
+ rdesc->suspend_mode_mask, val << shift);
+}
+
+static const struct regulator_ops rtq2208_regulator_buck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_mode = rtq2208_set_mode,
+ .get_mode = rtq2208_get_mode,
+ .set_ramp_delay = rtq2208_set_ramp_delay,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+ .set_suspend_enable = rtq2208_set_suspend_enable,
+ .set_suspend_disable = rtq2208_set_suspend_disable,
+ .set_suspend_mode = rtq2208_set_suspend_mode,
+};
+
+static const struct regulator_ops rtq2208_regulator_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+ .set_suspend_enable = rtq2208_set_suspend_enable,
+ .set_suspend_disable = rtq2208_set_suspend_disable,
+};
+
+static unsigned int rtq2208_of_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case RTQ2208_AUTO_MODE:
+ return REGULATOR_MODE_NORMAL;
+ case RTQ2208_FCCM:
+ return REGULATOR_MODE_FAST;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static int rtq2208_init_irq_mask(struct rtq2208_rdev_map *rdev_map, unsigned int *buck_masks)
+{
+ unsigned char buck_clr_masks[5] = {0x33, 0x33, 0x33, 0x33, 0x33},
+ sts_clr_masks[2] = {0xE7, 0xF7}, sts_masks[2] = {0xE6, 0xF6};
+ int ret;
+
+ /* write clear all buck irq once */
+ ret = regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_FLT_RECORDBUCK_CB, buck_clr_masks, 5);
+ if (ret)
+ return dev_err_probe(rdev_map->dev, ret, "Failed to clr buck irqs\n");
+
+ /* write clear general irq once */
+ ret = regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_GLOBAL_INT1, sts_clr_masks, 2);
+ if (ret)
+ return dev_err_probe(rdev_map->dev, ret, "Failed to clr general irqs\n");
+
+ /* unmask buck ov/uv irq */
+ ret = regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_FLT_MASKBUCK_CB, buck_masks, 5);
+ if (ret)
+ return dev_err_probe(rdev_map->dev, ret, "Failed to unmask buck irqs\n");
+
+ /* unmask needed general irq */
+ return regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_GLOBAL_INT1_MASK, sts_masks, 2);
+}
+
+static irqreturn_t rtq2208_irq_handler(int irqno, void *devid)
+{
+ unsigned char buck_flags[RTQ2208_BUCK_NUM_IRQ_REGS], sts_flags[RTQ2208_STS_NUM_IRQ_REGS];
+ int ret = 0, i, uv_bit, ov_bit;
+ struct rtq2208_rdev_map *rdev_map = devid;
+ struct regulator_dev *rdev;
+
+ if (!rdev_map)
+ return IRQ_NONE;
+
+ /* read irq event */
+ ret = regmap_bulk_read(rdev_map->regmap, RTQ2208_REG_FLT_RECORDBUCK_CB,
+ buck_flags, ARRAY_SIZE(buck_flags));
+ if (ret)
+ return IRQ_NONE;
+
+ ret = regmap_bulk_read(rdev_map->regmap, RTQ2208_REG_GLOBAL_INT1,
+ sts_flags, ARRAY_SIZE(sts_flags));
+ if (ret)
+ return IRQ_NONE;
+
+ /* clear irq event */
+ ret = regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_FLT_RECORDBUCK_CB,
+ buck_flags, ARRAY_SIZE(buck_flags));
+ if (ret)
+ return IRQ_NONE;
+
+ ret = regmap_bulk_write(rdev_map->regmap, RTQ2208_REG_GLOBAL_INT1,
+ sts_flags, ARRAY_SIZE(sts_flags));
+ if (ret)
+ return IRQ_NONE;
+
+ for (i = 0; i < RTQ2208_LDO_MAX; i++) {
+ if (!rdev_map->rdev[i])
+ continue;
+
+ rdev = rdev_map->rdev[i];
+ /* uv irq */
+ uv_bit = (i & 1) ? 4 : 0;
+ if (buck_flags[i >> 1] & (1 << uv_bit))
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_UNDER_VOLTAGE, NULL);
+ /* ov irq */
+ ov_bit = uv_bit + 1;
+ if (buck_flags[i >> 1] & (1 << ov_bit))
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_REGULATION_OUT, NULL);
+
+ /* hd irq */
+ if (sts_flags[1] & RTQ2208_HD_INT_MASK)
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_OVER_TEMP, NULL);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#define RTQ2208_REGULATOR_INFO(_name, _base) \
+{ \
+ .name = #_name, \
+ .base = _base, \
+}
+#define BUCK_RG_BASE(_id) RTQ2208_REG_BUCK_##_id##_CFG0
+#define BUCK_RG_SHIFT(_base, _shift) (_base + _shift)
+#define LDO_RG_BASE(_id) RTQ2208_REG_LDO##_id##_CFG
+#define LDO_RG_SHIFT(_base, _shift) (_base + _shift)
+#define VSEL_SHIFT(_sel) (_sel ? 3 : 1)
+#define MTP_SEL_MASK(_sel) RTQ2208_BUCK_EN_NR_MTP_SEL##_sel##_MASK
+
+static const struct linear_range rtq2208_vout_range[] = {
+ REGULATOR_LINEAR_RANGE(400000, 0, 180, 5000),
+ REGULATOR_LINEAR_RANGE(1310000, 181, 255, 10000),
+};
+
+static int rtq2208_of_get_fixed_voltage(struct device *dev,
+ struct of_regulator_match *rtq2208_ldo_match, int n_fixed)
+{
+ struct device_node *np;
+ struct of_regulator_match *match;
+ struct rtq2208_regulator_desc *rdesc;
+ struct regulator_init_data *init_data;
+ int ret, i;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ np = of_get_child_by_name(dev->of_node, "regulators");
+ if (!np)
+ np = dev->of_node;
+
+ ret = of_regulator_match(dev, np, rtq2208_ldo_match, n_fixed);
+
+ of_node_put(np);
+
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < n_fixed; i++) {
+ match = rtq2208_ldo_match + i;
+ init_data = match->init_data;
+ rdesc = (struct rtq2208_regulator_desc *)match->driver_data;
+
+ if (!init_data || !rdesc)
+ continue;
+
+ if (init_data->constraints.min_uV == init_data->constraints.max_uV)
+ rdesc->desc.fixed_uV = init_data->constraints.min_uV;
+ }
+
+ return 0;
+}
+
+static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel,
+ int idx, struct of_regulator_match *rtq2208_ldo_match, int *ldo_idx)
+{
+ struct regulator_desc *desc;
+ static const struct {
+ char *name;
+ int base;
+ } regulator_info[] = {
+ RTQ2208_REGULATOR_INFO(buck-b, BUCK_RG_BASE(B)),
+ RTQ2208_REGULATOR_INFO(buck-c, BUCK_RG_BASE(C)),
+ RTQ2208_REGULATOR_INFO(buck-d, BUCK_RG_BASE(D)),
+ RTQ2208_REGULATOR_INFO(buck-a, BUCK_RG_BASE(A)),
+ RTQ2208_REGULATOR_INFO(buck-f, BUCK_RG_BASE(F)),
+ RTQ2208_REGULATOR_INFO(buck-g, BUCK_RG_BASE(G)),
+ RTQ2208_REGULATOR_INFO(buck-h, BUCK_RG_BASE(H)),
+ RTQ2208_REGULATOR_INFO(buck-e, BUCK_RG_BASE(E)),
+ RTQ2208_REGULATOR_INFO(ldo2, LDO_RG_BASE(2)),
+ RTQ2208_REGULATOR_INFO(ldo1, LDO_RG_BASE(1)),
+ }, *curr_info;
+
+ curr_info = regulator_info + idx;
+ desc = &rdesc->desc;
+ desc->name = curr_info->name;
+ desc->of_match = of_match_ptr(curr_info->name);
+ desc->regulators_node = of_match_ptr("regulators");
+ desc->id = idx;
+ desc->owner = THIS_MODULE;
+ desc->type = REGULATOR_VOLTAGE;
+ desc->enable_mask = mtp_sel ? MTP_SEL_MASK(1) : MTP_SEL_MASK(0);
+ desc->active_discharge_on = RTQ2208_EN_DIS_MASK;
+ desc->active_discharge_off = 0;
+ desc->active_discharge_mask = RTQ2208_EN_DIS_MASK;
+
+ rdesc->mode_mask = RTQ2208_BUCK_NRMODE_MASK;
+
+ if (idx >= RTQ2208_BUCK_B && idx <= RTQ2208_BUCK_E) {
+ /* init buck desc */
+ desc->enable_reg = BUCK_RG_SHIFT(curr_info->base, 2);
+ desc->ops = &rtq2208_regulator_buck_ops;
+ desc->vsel_reg = curr_info->base + VSEL_SHIFT(mtp_sel);
+ desc->vsel_mask = RTQ2208_BUCK_NR_MTP_SEL_MASK;
+ desc->n_voltages = RTQ2208_VOUT_MAXNUM;
+ desc->linear_ranges = rtq2208_vout_range;
+ desc->n_linear_ranges = ARRAY_SIZE(rtq2208_vout_range);
+ desc->ramp_reg = BUCK_RG_SHIFT(curr_info->base, 5);
+ desc->active_discharge_reg = curr_info->base;
+ desc->of_map_mode = rtq2208_of_map_mode;
+
+ rdesc->mode_reg = BUCK_RG_SHIFT(curr_info->base, 2);
+ rdesc->suspend_config_reg = BUCK_RG_SHIFT(curr_info->base, 4);
+ rdesc->suspend_enable_mask = RTQ2208_BUCK_EN_STR_MASK;
+ rdesc->suspend_mode_mask = RTQ2208_BUCK_STRMODE_MASK;
+ } else {
+ /* init ldo desc */
+ desc->enable_reg = curr_info->base;
+ desc->ops = &rtq2208_regulator_ldo_ops;
+ desc->n_voltages = 1;
+ desc->active_discharge_reg = LDO_RG_SHIFT(curr_info->base, 2);
+
+ rtq2208_ldo_match[*ldo_idx].name = desc->name;
+ rtq2208_ldo_match[*ldo_idx].driver_data = rdesc;
+ rtq2208_ldo_match[(*ldo_idx)++].desc = desc;
+
+ rdesc->suspend_config_reg = curr_info->base;
+ rdesc->suspend_enable_mask = RTQ2208_LDO_EN_STR_MASK;
+ }
+}
+
+static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *regulator_idx_table,
+ struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev)
+{
+ struct of_regulator_match rtq2208_ldo_match[2];
+ int mtp_sel, ret, i, idx, ldo_idx = 0;
+
+ /* get mtp_sel0 or mtp_sel1 */
+ mtp_sel = device_property_read_bool(dev, "richtek,mtp-sel-high");
+
+ for (i = 0; i < n_regulator; i++) {
+ idx = regulator_idx_table[i];
+
+ rdesc[i] = devm_kcalloc(dev, 1, sizeof(*rdesc[0]), GFP_KERNEL);
+ if (!rdesc[i])
+ return -ENOMEM;
+
+ rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx, rtq2208_ldo_match, &ldo_idx);
+ }
+
+ /* init ldo fixed_uV */
+ ret = rtq2208_of_get_fixed_voltage(dev, rtq2208_ldo_match, ldo_idx);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get ldo fixed_uV\n");
+
+ return 0;
+
+}
+
+/** different slave address corresponds different used bucks
+ * slave address 0x10: BUCK[BCA FGE]
+ * slave address 0x20: BUCK[BC FGHE]
+ * slave address 0x40: BUCK[C G]
+ */
+static int rtq2208_regulator_check(int slave_addr, int *num,
+ int *regulator_idx_table, unsigned int *buck_masks)
+{
+ static bool rtq2208_used_table[3][RTQ2208_LDO_MAX] = {
+ /* BUCK[BCA FGE], LDO[12] */
+ {1, 1, 0, 1, 1, 1, 0, 1, 1, 1},
+ /* BUCK[BC FGHE], LDO[12]*/
+ {1, 1, 0, 0, 1, 1, 1, 1, 1, 1},
+ /* BUCK[C G], LDO[12] */
+ {0, 1, 0, 0, 0, 1, 0, 0, 1, 1},
+ };
+ int i, idx = ffs(slave_addr >> 4) - 1;
+ u8 mask;
+
+ for (i = 0; i < RTQ2208_LDO_MAX; i++) {
+ if (!rtq2208_used_table[idx][i])
+ continue;
+
+ regulator_idx_table[(*num)++] = i;
+
+ mask = RTQ2208_BUCK_MASK(4 * i, 4 * i + 1);
+ buck_masks[i >> 1] &= ~mask;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config rtq2208_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xEF,
+};
+
+static int rtq2208_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct regmap *regmap;
+ struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX];
+ struct regulator_dev *rdev;
+ 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],
+ buck_masks[RTQ2208_BUCK_NUM_IRQ_REGS] = {0x33, 0x33, 0x33, 0x33, 0x33};
+
+ rdev_map = devm_kzalloc(dev, sizeof(struct rtq2208_rdev_map), GFP_KERNEL);
+ if (!rdev_map)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(i2c, &rtq2208_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate regmap\n");
+
+ /* get needed regulator */
+ ret = rtq2208_regulator_check(i2c->addr, &n_regulator, regulator_idx_table, buck_masks);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to check used regulators\n");
+
+ rdev_map->regmap = regmap;
+ rdev_map->dev = dev;
+
+ cfg.dev = dev;
+
+ /* init regulator desc */
+ ret = rtq2208_parse_regulator_dt_data(n_regulator, regulator_idx_table, rdesc, dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < n_regulator; i++) {
+ idx = regulator_idx_table[i];
+
+ /* register regulator */
+ rdev = devm_regulator_register(dev, &rdesc[i]->desc, &cfg);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ rdev_map->rdev[idx] = rdev;
+ }
+
+ /* init interrupt mask */
+ ret = rtq2208_init_irq_mask(rdev_map, buck_masks);
+ if (ret)
+ return ret;
+
+ /* register interrupt */
+ return devm_request_threaded_irq(dev, i2c->irq, NULL, rtq2208_irq_handler,
+ IRQF_ONESHOT, dev_name(dev), rdev_map);
+}
+
+static const struct of_device_id rtq2208_device_tables[] = {
+ { .compatible = "richtek,rtq2208" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtq2208_device_tables);
+
+static struct i2c_driver rtq2208_driver = {
+ .driver = {
+ .name = "rtq2208",
+ .of_match_table = rtq2208_device_tables,
+ },
+ .probe = rtq2208_probe,
+};
+module_i2c_driver(rtq2208_driver);
+
+MODULE_AUTHOR("Alina Yu <alina_yu@richtek.com>");
+MODULE_DESCRIPTION("Richtek RTQ2208 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index b147ff6a16b1..c22fdde67f9c 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -5,7 +5,6 @@
#include <linux/bug.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c
index 4c60eddad60d..85b0102fb9b1 100644
--- a/drivers/regulator/stm32-pwr.c
+++ b/drivers/regulator/stm32-pwr.c
@@ -6,8 +6,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
index f5ccc7dd309a..717144cbe0f9 100644
--- a/drivers/regulator/stm32-vrefbuf.c
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -10,7 +10,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c
index d0703105c439..d49c0cba09fb 100644
--- a/drivers/regulator/sy8824x.c
+++ b/drivers/regulator/sy8824x.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/sy8827n.c b/drivers/regulator/sy8827n.c
index 433959b43549..f11ff38b36c9 100644
--- a/drivers/regulator/sy8827n.c
+++ b/drivers/regulator/sy8827n.c
@@ -9,7 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/i2c.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/tps6286x-regulator.c b/drivers/regulator/tps6286x-regulator.c
index b1c4b5120745..758c70269653 100644
--- a/drivers/regulator/tps6286x-regulator.c
+++ b/drivers/regulator/tps6286x-regulator.c
@@ -4,7 +4,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
@@ -84,11 +84,11 @@ static unsigned int tps6286x_of_map_mode(unsigned int mode)
static const struct regulator_desc tps6286x_reg = {
.name = "tps6286x",
- .of_match = of_match_ptr("SW"),
+ .of_match = "SW",
.owner = THIS_MODULE,
.ops = &tps6286x_regulator_ops,
.of_map_mode = tps6286x_of_map_mode,
- .regulators_node = of_match_ptr("regulators"),
+ .regulators_node = "regulators",
.type = REGULATOR_VOLTAGE,
.n_voltages = ((TPS6286X_MAX_MV - TPS6286X_MIN_MV) / TPS6286X_STEP_MV) + 1,
.min_uV = TPS6286X_MIN_MV * 1000,
@@ -148,7 +148,7 @@ static struct i2c_driver tps6286x_regulator_driver = {
.driver = {
.name = "tps6286x",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(tps6286x_dt_ids),
+ .of_match_table = tps6286x_dt_ids,
},
.probe = tps6286x_i2c_probe,
.id_table = tps6286x_i2c_id,
diff --git a/drivers/regulator/tps6287x-regulator.c b/drivers/regulator/tps6287x-regulator.c
index b1c0963586ac..d022184a8e7d 100644
--- a/drivers/regulator/tps6287x-regulator.c
+++ b/drivers/regulator/tps6287x-regulator.c
@@ -8,8 +8,8 @@
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
@@ -41,7 +41,7 @@ static const struct linear_range tps6287x_voltage_ranges[] = {
};
static const unsigned int tps6287x_voltage_range_sel[] = {
- 0x0, 0x4, 0x8, 0xC
+ 0x0, 0x1, 0x2, 0x3
};
static const unsigned int tps6287x_ramp_table[] = {
@@ -122,7 +122,7 @@ static struct regulator_desc tps6287x_reg = {
.n_voltages = 256,
.linear_ranges = tps6287x_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(tps6287x_voltage_ranges),
- .linear_range_selectors = tps6287x_voltage_range_sel,
+ .linear_range_selectors_bitfield = tps6287x_voltage_range_sel,
};
static int tps6287x_i2c_probe(struct i2c_client *i2c)
diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c
index 663789198ba5..2d284c64eeb7 100644
--- a/drivers/regulator/tps65086-regulator.c
+++ b/drivers/regulator/tps65086-regulator.c
@@ -15,7 +15,15 @@
#include <linux/mfd/tps65086.h>
enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
- LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
+ LDOA2, LDOA3, VTT, SWA1, SWB1, SWB2 };
+
+/* Selector for regulator configuration regarding PMIC chip ID. */
+enum tps65086_ids {
+ TPS6508640 = 0,
+ TPS65086401,
+ TPS6508641,
+ TPS65086470,
+};
#define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm) \
[_id] = { \
@@ -57,12 +65,24 @@ enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
}, \
}
+
+#define TPS65086_REGULATOR_CONFIG(_chip_id, _config) \
+ [_chip_id] = { \
+ .config = _config, \
+ .num_elems = ARRAY_SIZE(_config), \
+ }
+
struct tps65086_regulator {
struct regulator_desc desc;
unsigned int decay_reg;
unsigned int decay_mask;
};
+struct tps65086_regulator_config {
+ struct tps65086_regulator * const config;
+ const unsigned int num_elems;
+};
+
static const struct linear_range tps65086_10mv_ranges[] = {
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
@@ -114,7 +134,125 @@ static int tps65086_of_parse_cb(struct device_node *dev,
const struct regulator_desc *desc,
struct regulator_config *config);
-static struct tps65086_regulator regulators[] = {
+static struct tps65086_regulator tps6508640_regulator_config[] = {
+ TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK1CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
+ tps65086_10mv_ranges, TPS65086_BUCK2CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
+ tps65086_10mv_ranges, TPS65086_BUCK3DECAY,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
+ BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK4VID,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
+ BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK5CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
+ BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK6CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
+ VDOA1_VID_MASK, TPS65086_SWVTT_EN, BIT(7),
+ tps65086_ldoa1_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
+ VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
+ VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+ TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
+ TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+ TPS65086_SWITCH("SWB2", "swb2", SWB2, TPS65086_LDOA1CTRL, BIT(0)),
+};
+
+static struct tps65086_regulator tps65086401_regulator_config[] = {
+ TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK1CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
+ tps65086_10mv_ranges, TPS65086_BUCK2CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
+ tps65086_10mv_ranges, TPS65086_BUCK3DECAY,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
+ BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK4VID,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
+ BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK5CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
+ BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK6CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
+ VDOA1_VID_MASK, TPS65086_SWVTT_EN, BIT(7),
+ tps65086_ldoa1_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
+ VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
+ VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+ TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
+ TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+};
+
+static struct tps65086_regulator tps6508641_regulator_config[] = {
+ TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK1CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
+ tps65086_10mv_ranges, TPS65086_BUCK2CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
+ BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
+ tps65086_10mv_ranges, TPS65086_BUCK3DECAY,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
+ BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK4VID,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
+ BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK5CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
+ BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
+ tps65086_10mv_ranges, TPS65086_BUCK6CTRL,
+ BIT(0)),
+ TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
+ VDOA1_VID_MASK, TPS65086_SWVTT_EN, BIT(7),
+ tps65086_ldoa1_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
+ VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
+ VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
+ tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+ TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
+ TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+};
+
+static struct tps65086_regulator tps65086470_regulator_config[] = {
TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
tps65086_10mv_ranges, TPS65086_BUCK1CTRL,
@@ -148,16 +286,25 @@ static struct tps65086_regulator regulators[] = {
TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
tps65086_ldoa23_ranges, 0, 0),
+ TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
TPS65086_SWITCH("SWB2", "swb2", SWB2, TPS65086_SWVTT_EN, BIT(7)),
- TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
+};
+
+static const struct tps65086_regulator_config regulator_configs[] = {
+ TPS65086_REGULATOR_CONFIG(TPS6508640, tps6508640_regulator_config),
+ TPS65086_REGULATOR_CONFIG(TPS65086401, tps65086401_regulator_config),
+ TPS65086_REGULATOR_CONFIG(TPS6508641, tps6508641_regulator_config),
+ TPS65086_REGULATOR_CONFIG(TPS65086470, tps65086470_regulator_config)
};
static int tps65086_of_parse_cb(struct device_node *node,
const struct regulator_desc *desc,
struct regulator_config *config)
{
+ struct tps65086 * const tps = dev_get_drvdata(config->dev);
+ struct tps65086_regulator *regulators = tps->reg_config->config;
int ret;
/* Check for 25mV step mode */
@@ -203,9 +350,30 @@ static int tps65086_regulator_probe(struct platform_device *pdev)
{
struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
+ unsigned int selector_reg_config;
struct regulator_dev *rdev;
int i;
+ /* Select regulator configuration for used PMIC device */
+ switch (tps->chip_id) {
+ case TPS6508640_ID:
+ selector_reg_config = TPS6508640;
+ break;
+ case TPS65086401_ID:
+ selector_reg_config = TPS65086401;
+ break;
+ case TPS6508641_ID:
+ selector_reg_config = TPS6508641;
+ break;
+ case TPS65086470_ID:
+ selector_reg_config = TPS65086470;
+ break;
+ default:
+ dev_err(tps->dev, "Unknown device ID. Cannot determine regulator config.\n");
+ return -ENODEV;
+ }
+ tps->reg_config = &regulator_configs[selector_reg_config];
+
platform_set_drvdata(pdev, tps);
config.dev = &pdev->dev;
@@ -213,12 +381,16 @@ static int tps65086_regulator_probe(struct platform_device *pdev)
config.driver_data = tps;
config.regmap = tps->regmap;
- for (i = 0; i < ARRAY_SIZE(regulators); i++) {
- rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
- &config);
+ for (i = 0; i < tps->reg_config->num_elems; ++i) {
+ struct regulator_desc * const desc_ptr = &tps->reg_config->config[i].desc;
+
+ dev_dbg(tps->dev, "Index: %u; Regulator name: \"%s\"; Regulator ID: %d\n",
+ i, desc_ptr->name, desc_ptr->id);
+
+ rdev = devm_regulator_register(&pdev->dev, desc_ptr, &config);
if (IS_ERR(rdev)) {
- dev_err(tps->dev, "failed to register %s regulator\n",
- pdev->name);
+ dev_err(tps->dev, "failed to register %d \"%s\" regulator\n",
+ i, desc_ptr->name);
return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index 13985883e5f0..f44b5767099c 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -8,12 +8,12 @@
*/
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c
index 8971b507a79a..b4065356392f 100644
--- a/drivers/regulator/tps65219-regulator.c
+++ b/drivers/regulator/tps65219-regulator.c
@@ -15,8 +15,8 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 2a0965ba1570..3a3027e0b94e 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -17,7 +17,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/mfd/tps65910.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c
index d5a574ec6d12..25ef102c8270 100644
--- a/drivers/regulator/tps6594-regulator.c
+++ b/drivers/regulator/tps6594-regulator.c
@@ -9,7 +9,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 3e724f5345de..5bacfcebf59a 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -12,7 +12,6 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c
index f9c695f9bde8..6eed0f6e0adb 100644
--- a/drivers/regulator/twl6030-regulator.c
+++ b/drivers/regulator/twl6030-regulator.c
@@ -13,7 +13,6 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c
index 7e2785e10dc6..1d8304b88bd6 100644
--- a/drivers/regulator/uniphier-regulator.c
+++ b/drivers/regulator/uniphier-regulator.c
@@ -7,7 +7,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
diff --git a/drivers/regulator/vctrl-regulator.c b/drivers/regulator/vctrl-regulator.c
index 85dca90233f6..2796580a3a3c 100644
--- a/drivers/regulator/vctrl-regulator.c
+++ b/drivers/regulator/vctrl-regulator.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/regulator/vexpress-regulator.c b/drivers/regulator/vexpress-regulator.c
index b545dbc70a4d..6687077e9a97 100644
--- a/drivers/regulator/vexpress-regulator.c
+++ b/drivers/regulator/vexpress-regulator.c
@@ -8,7 +8,8 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 0f707be0eb87..04dbf35cf3b7 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -1432,7 +1432,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
unreachable();
}
}
-EXPORT_SYMBOL(ds1685_rtc_poweroff);
+EXPORT_SYMBOL_GPL(ds1685_rtc_poweroff);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 50a5ff70814a..215597f73be4 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3636,11 +3636,8 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
* so sync bdev first and then wait for our queues to become
* empty
*/
- if (device->block) {
- rc = fsync_bdev(device->block->bdev);
- if (rc != 0)
- goto interrupted;
- }
+ if (device->block)
+ bdev_mark_dead(device->block->bdev, false);
dasd_schedule_device_bh(device);
rc = wait_event_interruptible(shutdown_waitq,
_wait_for_empty_queues(device));
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 09acf3853a77..06bcb6c78909 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -412,6 +412,7 @@ removeseg:
}
list_del(&dev_info->lh);
+ dax_remove_host(dev_info->gd);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
@@ -707,9 +708,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
goto out;
out_dax_host:
+ put_device(&dev_info->dev);
dax_remove_host(dev_info->gd);
out_dax:
- put_device(&dev_info->dev);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
put_dev:
@@ -789,6 +790,7 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch
}
list_del(&dev_info->lh);
+ dax_remove_host(dev_info->gd);
kill_dax(dev_info->dax_dev);
put_dax(dev_info->dax_dev);
del_gendisk(dev_info->gd);
@@ -860,7 +862,7 @@ dcssblk_submit_bio(struct bio *bio)
struct bio_vec bvec;
struct bvec_iter iter;
unsigned long index;
- unsigned long page_addr;
+ void *page_addr;
unsigned long source_addr;
unsigned long bytes_done;
@@ -868,8 +870,8 @@ dcssblk_submit_bio(struct bio *bio)
dev_info = bio->bi_bdev->bd_disk->private_data;
if (dev_info == NULL)
goto fail;
- if ((bio->bi_iter.bi_sector & 7) != 0 ||
- (bio->bi_iter.bi_size & 4095) != 0)
+ if (!IS_ALIGNED(bio->bi_iter.bi_sector, 8) ||
+ !IS_ALIGNED(bio->bi_iter.bi_size, PAGE_SIZE))
/* Request is not page-aligned. */
goto fail;
/* verify data transfer direction */
@@ -889,18 +891,16 @@ dcssblk_submit_bio(struct bio *bio)
index = (bio->bi_iter.bi_sector >> 3);
bio_for_each_segment(bvec, bio, iter) {
- page_addr = (unsigned long)bvec_virt(&bvec);
+ page_addr = bvec_virt(&bvec);
source_addr = dev_info->start + (index<<12) + bytes_done;
- if (unlikely((page_addr & 4095) != 0) || (bvec.bv_len & 4095) != 0)
+ if (unlikely(!IS_ALIGNED((unsigned long)page_addr, PAGE_SIZE) ||
+ !IS_ALIGNED(bvec.bv_len, PAGE_SIZE)))
// More paranoia.
goto fail;
- if (bio_data_dir(bio) == READ) {
- memcpy((void*)page_addr, (void*)source_addr,
- bvec.bv_len);
- } else {
- memcpy((void*)source_addr, (void*)page_addr,
- bvec.bv_len);
- }
+ if (bio_data_dir(bio) == READ)
+ memcpy(page_addr, __va(source_addr), bvec.bv_len);
+ else
+ memcpy(__va(source_addr), page_addr, bvec.bv_len);
bytes_done += bvec.bv_len;
}
bio_endio(bio);
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
index 0c1df1d5f1ac..3a9cc8a4a230 100644
--- a/drivers/s390/block/scm_blk.c
+++ b/drivers/s390/block/scm_blk.c
@@ -134,7 +134,7 @@ static void scm_request_done(struct scm_request *scmrq)
if ((msb->flags & MSB_FLAG_IDA) && aidaw &&
IS_ALIGNED(aidaw, PAGE_SIZE))
- mempool_free(virt_to_page(aidaw), aidaw_pool);
+ mempool_free(virt_to_page((void *)aidaw), aidaw_pool);
}
spin_lock_irqsave(&list_lock, flags);
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 3c87057436d5..8b4575a0db9f 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -392,10 +392,6 @@ static void __init add_memory_merged(u16 rn)
goto skip_add;
start = rn2addr(first_rn);
size = (unsigned long long) num * sclp.rzm;
- if (start >= VMEM_MAX_PHYS)
- goto skip_add;
- if (start + size > VMEM_MAX_PHYS)
- size = VMEM_MAX_PHYS - start;
if (start >= ident_map_size)
goto skip_add;
if (start + size > ident_map_size)
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index f480d6c7fd39..fdc8668f3fba 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -55,6 +55,7 @@ static void __init sclp_early_facilities_detect(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST;
if (sccb->cpuoff > 134) {
sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
+ sclp.has_diag320 = !!(sccb->byte_134 & 0x04);
sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
}
if (sccb->cpuoff > 137) {
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 4cebfaaa22b4..eb0520a9d4af 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -89,7 +89,7 @@ static void vmcp_response_free(struct vmcp_session *session)
order = get_order(session->bufsize);
nr_pages = ALIGN(session->bufsize, PAGE_SIZE) >> PAGE_SHIFT;
if (session->cma_alloc) {
- page = virt_to_page((unsigned long)session->response);
+ page = virt_to_page(session->response);
cma_release(vmcp_cma, page, nr_pages);
session->cma_alloc = 0;
} else {
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 942c73a11ca3..bc3be0330f1d 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -3,7 +3,7 @@
* zcore module to export memory content and register sets for creating system
* dumps on SCSI/NVMe disks (zfcp/nvme dump).
*
- * For more information please refer to Documentation/s390/zfcpdump.rst
+ * For more information please refer to Documentation/arch/s390/zfcpdump.rst
*
* Copyright IBM Corp. 2003, 2008
* Author(s): Michael Holzheu
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index 22d2db690cd3..0edacd101c12 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -11,7 +11,7 @@ zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
zcrypt-objs += zcrypt_ccamisc.o zcrypt_ep11misc.o
obj-$(CONFIG_ZCRYPT) += zcrypt.o
# adapter drivers depend on ap.o and zcrypt.o
-obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_cex4.o
# pkey kernel module
pkey-objs := pkey_api.o
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 420120be300f..339812efe822 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright IBM Corp. 2006, 2021
+ * Copyright IBM Corp. 2006, 2023
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -219,6 +219,15 @@ int ap_sb_available(void)
}
/*
+ * ap_is_se_guest(): Check for SE guest with AP pass-through support.
+ */
+bool ap_is_se_guest(void)
+{
+ return is_prot_virt_guest() && ap_sb_available();
+}
+EXPORT_SYMBOL(ap_is_se_guest);
+
+/*
* ap_fetch_qci_info(): Fetch cryptographic config info
*
* Returns the ap configuration info fetched via PQAP(QCI).
@@ -387,23 +396,6 @@ static int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac,
*q_ml = tapq_info.ml;
*q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED;
*q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED;
- switch (*q_type) {
- /* For CEX2 and CEX3 the available functions
- * are not reflected by the facilities bits.
- * Instead it is coded into the type. So here
- * modify the function bits based on the type.
- */
- case AP_DEVICE_TYPE_CEX2A:
- case AP_DEVICE_TYPE_CEX3A:
- *q_fac |= 0x08000000;
- break;
- case AP_DEVICE_TYPE_CEX2C:
- case AP_DEVICE_TYPE_CEX3C:
- *q_fac |= 0x10000000;
- break;
- default:
- break;
- }
return 1;
default:
/*
@@ -1678,8 +1670,8 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
{
int comp_type = 0;
- /* < CEX2A is not supported */
- if (rawtype < AP_DEVICE_TYPE_CEX2A) {
+ /* < CEX4 is not supported */
+ if (rawtype < AP_DEVICE_TYPE_CEX4) {
AP_DBF_WARN("%s queue=%02x.%04x unsupported type %d\n",
__func__, AP_QID_CARD(qid),
AP_QID_QUEUE(qid), rawtype);
@@ -1701,7 +1693,7 @@ static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func)
apinfo.cat = AP_DEVICE_TYPE_CEX8;
status = ap_qact(qid, 0, &apinfo);
if (status.response_code == AP_RESPONSE_NORMAL &&
- apinfo.cat >= AP_DEVICE_TYPE_CEX2A &&
+ apinfo.cat >= AP_DEVICE_TYPE_CEX4 &&
apinfo.cat <= AP_DEVICE_TYPE_CEX8)
comp_type = apinfo.cat;
}
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 0d7b7eb374ad..be54b070c031 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright IBM Corp. 2006, 2019
+ * Copyright IBM Corp. 2006, 2023
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -67,15 +67,8 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
#define AP_RESPONSE_INVALID_DOMAIN 0x42
/*
- * Known device types
+ * Supported AP device types
*/
-#define AP_DEVICE_TYPE_PCICC 3
-#define AP_DEVICE_TYPE_PCICA 4
-#define AP_DEVICE_TYPE_PCIXCC 5
-#define AP_DEVICE_TYPE_CEX2A 6
-#define AP_DEVICE_TYPE_CEX2C 7
-#define AP_DEVICE_TYPE_CEX3A 8
-#define AP_DEVICE_TYPE_CEX3C 9
#define AP_DEVICE_TYPE_CEX4 10
#define AP_DEVICE_TYPE_CEX5 11
#define AP_DEVICE_TYPE_CEX6 12
@@ -272,14 +265,6 @@ static inline void ap_release_message(struct ap_message *ap_msg)
kfree_sensitive(ap_msg->private);
}
-/*
- * Note: don't use ap_send/ap_recv after using ap_queue_message
- * for the first time. Otherwise the ap message queue will get
- * confused.
- */
-int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen);
-int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen);
-
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event);
@@ -289,6 +274,7 @@ void ap_flush_queue(struct ap_queue *aq);
void *ap_airq_ptr(void);
int ap_sb_available(void);
+bool ap_is_se_guest(void);
void ap_wait(enum ap_sm_wait wait);
void ap_request_timeout(struct timer_list *t);
void ap_bus_force_rescan(void);
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index 30df83735adf..1336e632adc4 100644
--- a/drivers/s390/crypto/ap_queue.c
+++ b/drivers/s390/crypto/ap_queue.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright IBM Corp. 2016
+ * Copyright IBM Corp. 2016, 2023
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* Adjunct processor bus, queue related code.
@@ -93,51 +93,6 @@ __ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen,
return ap_nqap(qid, psmid, msg, msglen);
}
-int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen)
-{
- struct ap_queue_status status;
-
- status = __ap_send(qid, psmid, msg, msglen, 0);
- if (status.async)
- return -EPERM;
- switch (status.response_code) {
- case AP_RESPONSE_NORMAL:
- return 0;
- case AP_RESPONSE_Q_FULL:
- case AP_RESPONSE_RESET_IN_PROGRESS:
- return -EBUSY;
- case AP_RESPONSE_REQ_FAC_NOT_INST:
- return -EINVAL;
- default: /* Device is gone. */
- return -ENODEV;
- }
-}
-EXPORT_SYMBOL(ap_send);
-
-int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen)
-{
- struct ap_queue_status status;
-
- if (!msg)
- return -EINVAL;
- status = ap_dqap(qid, psmid, msg, msglen, NULL, NULL, NULL);
- if (status.async)
- return -EPERM;
- switch (status.response_code) {
- case AP_RESPONSE_NORMAL:
- return 0;
- case AP_RESPONSE_NO_PENDING_REPLY:
- if (status.queue_empty)
- return -ENOENT;
- return -EBUSY;
- case AP_RESPONSE_RESET_IN_PROGRESS:
- return -EBUSY;
- default:
- return -ENODEV;
- }
-}
-EXPORT_SYMBOL(ap_recv);
-
/* State machine definitions and helpers */
static enum ap_sm_wait ap_sm_nop(struct ap_queue *aq)
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index e58bfd225323..6cfb6b2340c9 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -263,7 +263,9 @@ static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
/* build a list of apqns suitable for ep11 keys with cpacf support */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7, EP11_API_V, NULL);
+ ZCRYPT_CEX7,
+ ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
+ NULL);
if (rc)
goto out;
@@ -272,7 +274,8 @@ static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen,
card = apqns[i] >> 16;
dom = apqns[i] & 0xFFFF;
rc = ep11_clr2keyblob(card, dom, clrkeylen * 8,
- 0, clrkey, keybuf, keybuflen);
+ 0, clrkey, keybuf, keybuflen,
+ PKEY_TYPE_EP11);
if (rc == 0)
break;
}
@@ -287,10 +290,9 @@ out:
/*
* Find card and transform EP11 secure key into protected key.
*/
-static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
- u32 *protkeylen, u32 *protkeytype)
+static int pkey_ep11key2pkey(const u8 *key, size_t keylen,
+ u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- struct ep11keyblob *kb = (struct ep11keyblob *)key;
u32 nr_apqns, *apqns = NULL;
u16 card, dom;
int i, rc;
@@ -299,7 +301,9 @@ static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
/* build a list of apqns suitable for this key */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
+ ZCRYPT_CEX7,
+ ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
+ ep11_kb_wkvp(key, keylen));
if (rc)
goto out;
@@ -307,7 +311,7 @@ static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
for (rc = -ENODEV, i = 0; i < nr_apqns; i++) {
card = apqns[i] >> 16;
dom = apqns[i] & 0xFFFF;
- rc = ep11_kblob2protkey(card, dom, key, kb->head.len,
+ rc = ep11_kblob2protkey(card, dom, key, keylen,
protkey, protkeylen, protkeytype);
if (rc == 0)
break;
@@ -495,7 +499,7 @@ try_via_ep11:
tmpbuf, &tmpbuflen);
if (rc)
goto failure;
- rc = pkey_ep11key2pkey(tmpbuf,
+ rc = pkey_ep11key2pkey(tmpbuf, tmpbuflen,
protkey, protkeylen, protkeytype);
if (!rc)
goto out;
@@ -611,7 +615,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1);
if (rc)
goto out;
- rc = pkey_ep11key2pkey(key,
+ rc = pkey_ep11key2pkey(key, keylen,
protkey, protkeylen, protkeytype);
break;
}
@@ -620,7 +624,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
rc = ep11_check_aes_key_with_hdr(debug_info, 3, key, keylen, 1);
if (rc)
goto out;
- rc = pkey_ep11key2pkey(key + sizeof(struct ep11kblob_header),
+ rc = pkey_ep11key2pkey(key, keylen,
protkey, protkeylen, protkeytype);
break;
default:
@@ -713,6 +717,11 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
if (*keybufsize < MINEP11AESKEYBLOBSIZE)
return -EINVAL;
break;
+ case PKEY_TYPE_EP11_AES:
+ if (*keybufsize < (sizeof(struct ep11kblob_header) +
+ MINEP11AESKEYBLOBSIZE))
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -729,9 +738,10 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
dom = apqns[i].domain;
- if (ktype == PKEY_TYPE_EP11) {
+ if (ktype == PKEY_TYPE_EP11 ||
+ ktype == PKEY_TYPE_EP11_AES) {
rc = ep11_genaeskey(card, dom, ksize, kflags,
- keybuf, keybufsize);
+ keybuf, keybufsize, ktype);
} else if (ktype == PKEY_TYPE_CCA_DATA) {
rc = cca_genseckey(card, dom, ksize, keybuf);
*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
@@ -769,6 +779,11 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
if (*keybufsize < MINEP11AESKEYBLOBSIZE)
return -EINVAL;
break;
+ case PKEY_TYPE_EP11_AES:
+ if (*keybufsize < (sizeof(struct ep11kblob_header) +
+ MINEP11AESKEYBLOBSIZE))
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -787,9 +802,11 @@ static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
dom = apqns[i].domain;
- if (ktype == PKEY_TYPE_EP11) {
+ if (ktype == PKEY_TYPE_EP11 ||
+ ktype == PKEY_TYPE_EP11_AES) {
rc = ep11_clr2keyblob(card, dom, ksize, kflags,
- clrkey, keybuf, keybufsize);
+ clrkey, keybuf, keybufsize,
+ ktype);
} else if (ktype == PKEY_TYPE_CCA_DATA) {
rc = cca_clr2seckey(card, dom, ksize,
clrkey, keybuf);
@@ -888,6 +905,7 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
} else if (hdr->type == TOKTYPE_NON_CCA &&
hdr->version == TOKVER_EP11_AES) {
struct ep11keyblob *kb = (struct ep11keyblob *)key;
+ int api;
rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1);
if (rc)
@@ -895,10 +913,12 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
if (ktype)
*ktype = PKEY_TYPE_EP11;
if (ksize)
- *ksize = kb->head.keybitlen;
+ *ksize = kb->head.bitlen;
+ api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
rc = ep11_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
- ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
+ ZCRYPT_CEX7, api,
+ ep11_kb_wkvp(key, keylen));
if (rc)
goto out;
@@ -908,6 +928,32 @@ static int pkey_verifykey2(const u8 *key, size_t keylen,
*cardnr = ((struct pkey_apqn *)_apqns)->card;
*domain = ((struct pkey_apqn *)_apqns)->domain;
+ } else if (hdr->type == TOKTYPE_NON_CCA &&
+ hdr->version == TOKVER_EP11_AES_WITH_HEADER) {
+ struct ep11kblob_header *kh = (struct ep11kblob_header *)key;
+ int api;
+
+ rc = ep11_check_aes_key_with_hdr(debug_info, 3,
+ key, keylen, 1);
+ if (rc)
+ goto out;
+ if (ktype)
+ *ktype = PKEY_TYPE_EP11_AES;
+ if (ksize)
+ *ksize = kh->bitlen;
+
+ api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
+ rc = ep11_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
+ ZCRYPT_CEX7, api,
+ ep11_kb_wkvp(key, keylen));
+ if (rc)
+ goto out;
+
+ if (flags)
+ *flags = PKEY_FLAGS_MATCH_CUR_MKVP;
+
+ *cardnr = ((struct pkey_apqn *)_apqns)->card;
+ *domain = ((struct pkey_apqn *)_apqns)->domain;
} else {
rc = -EINVAL;
}
@@ -949,10 +995,12 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
}
} else if (hdr->type == TOKTYPE_NON_CCA) {
if (hdr->version == TOKVER_EP11_AES) {
- if (keylen < sizeof(struct ep11keyblob))
- return -EINVAL;
if (ep11_check_aes_key(debug_info, 3, key, keylen, 1))
return -EINVAL;
+ } else if (hdr->version == TOKVER_EP11_AES_WITH_HEADER) {
+ if (ep11_check_aes_key_with_hdr(debug_info, 3,
+ key, keylen, 1))
+ return -EINVAL;
} else {
return pkey_nonccatok2pkey(key, keylen,
protkey, protkeylen,
@@ -980,10 +1028,7 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
protkey, protkeylen,
protkeytype);
} else {
- /* EP11 AES secure key blob */
- struct ep11keyblob *kb = (struct ep11keyblob *)key;
-
- rc = ep11_kblob2protkey(card, dom, key, kb->head.len,
+ rc = ep11_kblob2protkey(card, dom, key, keylen,
protkey, protkeylen,
protkeytype);
}
@@ -1018,7 +1063,7 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
return -EINVAL;
if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) {
minhwtype = ZCRYPT_CEX7;
- api = EP11_API_V;
+ api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
}
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
minhwtype, api, kb->wkvp);
@@ -1034,7 +1079,7 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
return -EINVAL;
if (kb->attr & EP11_BLOB_PKEY_EXTRACTABLE) {
minhwtype = ZCRYPT_CEX7;
- api = EP11_API_V;
+ api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
}
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
minhwtype, api, kb->wkvp);
@@ -1144,11 +1189,13 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype,
ktype == PKEY_TYPE_EP11_AES ||
ktype == PKEY_TYPE_EP11_ECC) {
u8 *wkvp = NULL;
+ int api;
if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
wkvp = cur_mkvp;
+ api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7, EP11_API_V, wkvp);
+ ZCRYPT_CEX7, api, wkvp);
if (rc)
goto out;
@@ -1243,12 +1290,14 @@ static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns,
hdr->version == TOKVER_EP11_ECC_WITH_HEADER) &&
is_ep11_keyblob(key + sizeof(struct ep11kblob_header)))
rc = ep11_kblob2protkey(card, dom, key, hdr->len,
- protkey, protkeylen, protkeytype);
+ protkey, protkeylen,
+ protkeytype);
else if (hdr->type == TOKTYPE_NON_CCA &&
hdr->version == TOKVER_EP11_AES &&
is_ep11_keyblob(key))
rc = ep11_kblob2protkey(card, dom, key, hdr->len,
- protkey, protkeylen, protkeytype);
+ protkey, protkeylen,
+ protkeytype);
else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
hdr->version == TOKVER_CCA_AES)
rc = cca_sec2protkey(card, dom, key, protkey,
@@ -1466,7 +1515,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries);
if (IS_ERR(apqns))
return PTR_ERR(apqns);
- kkey = kmalloc(klen, GFP_KERNEL);
+ kkey = kzalloc(klen, GFP_KERNEL);
if (!kkey) {
kfree(apqns);
return -ENOMEM;
@@ -1508,7 +1557,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries);
if (IS_ERR(apqns))
return PTR_ERR(apqns);
- kkey = kmalloc(klen, GFP_KERNEL);
+ kkey = kzalloc(klen, GFP_KERNEL);
if (!kkey) {
kfree(apqns);
return -ENOMEM;
@@ -2102,7 +2151,7 @@ static struct attribute_group ccacipher_attr_group = {
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
* This function and the sysfs attributes using it provide EP11 key blobs
* padded to the upper limit of MAXEP11AESKEYBLOBSIZE which is currently
- * 320 bytes.
+ * 336 bytes.
*/
static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
bool is_xts, char *buf, loff_t off,
@@ -2120,7 +2169,9 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
/* build a list of apqns able to generate an cipher key */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7, EP11_API_V, NULL);
+ ZCRYPT_CEX7,
+ ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4,
+ NULL);
if (rc)
return rc;
@@ -2130,7 +2181,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i] >> 16;
dom = apqns[i] & 0xFFFF;
- rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
+ rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize,
+ PKEY_TYPE_EP11_AES);
if (rc == 0)
break;
}
@@ -2140,7 +2192,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
if (is_xts) {
keysize = MAXEP11AESKEYBLOBSIZE;
buf += MAXEP11AESKEYBLOBSIZE;
- rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
+ rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize,
+ PKEY_TYPE_EP11_AES);
if (rc == 0)
return 2 * MAXEP11AESKEYBLOBSIZE;
}
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index b441745b0418..0509f80622cd 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -30,13 +30,12 @@
#define AP_QUEUE_UNASSIGNED "unassigned"
#define AP_QUEUE_IN_USE "in use"
-#define MAX_RESET_CHECK_WAIT 200 /* Sleep max 200ms for reset check */
#define AP_RESET_INTERVAL 20 /* Reset sleep interval (20ms) */
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
static const struct vfio_device_ops vfio_ap_matrix_dev_ops;
-static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
+static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
/**
* get_update_locks_for_kvm: Acquire the locks required to dynamically update a
@@ -360,6 +359,28 @@ static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, dma_addr_t *nib)
return 0;
}
+static int ensure_nib_shared(unsigned long addr, struct gmap *gmap)
+{
+ int ret;
+
+ /*
+ * The nib has to be located in shared storage since guest and
+ * host access it. vfio_pin_pages() will do a pin shared and
+ * if that fails (possibly because it's not a shared page) it
+ * calls export. We try to do a second pin shared here so that
+ * the UV gives us an error code if we try to pin a non-shared
+ * page.
+ *
+ * If the page is already pinned shared the UV will return a success.
+ */
+ ret = uv_pin_shared(addr);
+ if (ret) {
+ /* vfio_pin_pages() likely exported the page so let's re-import */
+ gmap_convert_to_secure(gmap, addr);
+ }
+ return ret;
+}
+
/**
* vfio_ap_irq_enable - Enable Interruption for a APQN
*
@@ -423,6 +444,14 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
h_nib = page_to_phys(h_page) | (nib & ~PAGE_MASK);
aqic_gisa.gisc = isc;
+ /* NIB in non-shared storage is a rc 6 for PV guests */
+ if (kvm_s390_pv_cpu_is_protected(vcpu) &&
+ ensure_nib_shared(h_nib & PAGE_MASK, kvm->arch.gmap)) {
+ vfio_unpin_pages(&q->matrix_mdev->vdev, nib, 1);
+ status.response_code = AP_RESPONSE_INVALID_ADDRESS;
+ return status;
+ }
+
nisc = kvm_s390_gisc_register(kvm, isc);
if (nisc < 0) {
VFIO_AP_DBF_WARN("%s: gisc registration failed: nisc=%d, isc=%d, apqn=%#04x\n",
@@ -675,7 +704,7 @@ static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
*/
apqn = AP_MKQID(apid, apqi);
q = vfio_ap_mdev_get_queue(matrix_mdev, apqn);
- if (!q || q->reset_rc) {
+ if (!q || q->reset_status.response_code) {
clear_bit_inv(apid,
matrix_mdev->shadow_apcb.apm);
break;
@@ -1608,19 +1637,21 @@ static int apq_status_check(int apqn, struct ap_queue_status *status)
{
switch (status->response_code) {
case AP_RESPONSE_NORMAL:
+ case AP_RESPONSE_DECONFIGURED:
+ return 0;
case AP_RESPONSE_RESET_IN_PROGRESS:
- if (status->queue_empty && !status->irq_enabled)
- return 0;
+ case AP_RESPONSE_BUSY:
return -EBUSY;
- case AP_RESPONSE_DECONFIGURED:
+ case AP_RESPONSE_ASSOC_SECRET_NOT_UNIQUE:
+ case AP_RESPONSE_ASSOC_FAILED:
/*
- * If the AP queue is deconfigured, any subsequent AP command
- * targeting the queue will fail with the same response code. On the
- * other hand, when an AP adapter is deconfigured, the associated
- * queues are reset, so let's return a value indicating the reset
- * for which we're waiting completed successfully.
+ * These asynchronous response codes indicate a PQAP(AAPQ)
+ * instruction to associate a secret with the guest failed. All
+ * subsequent AP instructions will end with the asynchronous
+ * response code until the AP queue is reset; so, let's return
+ * a value indicating a reset needs to be performed again.
*/
- return 0;
+ return -EAGAIN;
default:
WARN(true,
"failed to verify reset of queue %02x.%04x: TAPQ rc=%u\n",
@@ -1630,91 +1661,105 @@ static int apq_status_check(int apqn, struct ap_queue_status *status)
}
}
-static int apq_reset_check(struct vfio_ap_queue *q)
+#define WAIT_MSG "Waited %dms for reset of queue %02x.%04x (%u, %u, %u)"
+
+static void apq_reset_check(struct work_struct *reset_work)
{
- int ret;
- int iters = MAX_RESET_CHECK_WAIT / AP_RESET_INTERVAL;
+ int ret = -EBUSY, elapsed = 0;
struct ap_queue_status status;
+ struct vfio_ap_queue *q;
- for (; iters > 0; iters--) {
+ q = container_of(reset_work, struct vfio_ap_queue, reset_work);
+ memcpy(&status, &q->reset_status, sizeof(status));
+ while (true) {
msleep(AP_RESET_INTERVAL);
+ elapsed += AP_RESET_INTERVAL;
status = ap_tapq(q->apqn, NULL);
ret = apq_status_check(q->apqn, &status);
- if (ret != -EBUSY)
- return ret;
+ if (ret == -EIO)
+ return;
+ if (ret == -EBUSY) {
+ pr_notice_ratelimited(WAIT_MSG, elapsed,
+ AP_QID_CARD(q->apqn),
+ AP_QID_QUEUE(q->apqn),
+ status.response_code,
+ status.queue_empty,
+ status.irq_enabled);
+ } else {
+ if (q->reset_status.response_code == AP_RESPONSE_RESET_IN_PROGRESS ||
+ q->reset_status.response_code == AP_RESPONSE_BUSY ||
+ q->reset_status.response_code == AP_RESPONSE_STATE_CHANGE_IN_PROGRESS ||
+ ret == -EAGAIN) {
+ status = ap_zapq(q->apqn, 0);
+ memcpy(&q->reset_status, &status, sizeof(status));
+ continue;
+ }
+ /*
+ * When an AP adapter is deconfigured, the
+ * associated queues are reset, so let's set the
+ * status response code to 0 so the queue may be
+ * passed through (i.e., not filtered)
+ */
+ if (status.response_code == AP_RESPONSE_DECONFIGURED)
+ q->reset_status.response_code = 0;
+ if (q->saved_isc != VFIO_AP_ISC_INVALID)
+ vfio_ap_free_aqic_resources(q);
+ break;
+ }
}
- WARN_ONCE(iters <= 0,
- "timeout verifying reset of queue %02x.%04x (%u, %u, %u)",
- AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
- status.queue_empty, status.irq_enabled, status.response_code);
- return ret;
}
-static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
+static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
{
struct ap_queue_status status;
- int ret;
if (!q)
- return 0;
-retry_zapq:
+ return;
status = ap_zapq(q->apqn, 0);
- q->reset_rc = status.response_code;
+ memcpy(&q->reset_status, &status, sizeof(status));
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
- ret = 0;
- /* if the reset has not completed, wait for it to take effect */
- if (!status.queue_empty || status.irq_enabled)
- ret = apq_reset_check(q);
- break;
case AP_RESPONSE_RESET_IN_PROGRESS:
+ case AP_RESPONSE_BUSY:
+ case AP_RESPONSE_STATE_CHANGE_IN_PROGRESS:
/*
- * There is a reset issued by another process in progress. Let's wait
- * for that to complete. Since we have no idea whether it was a RAPQ or
- * ZAPQ, then if it completes successfully, let's issue the ZAPQ.
+ * Let's verify whether the ZAPQ completed successfully on a work queue.
*/
- ret = apq_reset_check(q);
- if (ret)
- break;
- goto retry_zapq;
+ queue_work(system_long_wq, &q->reset_work);
+ break;
case AP_RESPONSE_DECONFIGURED:
/*
* When an AP adapter is deconfigured, the associated
- * queues are reset, so let's return a value indicating the reset
- * completed successfully.
+ * queues are reset, so let's set the status response code to 0
+ * so the queue may be passed through (i.e., not filtered).
*/
- ret = 0;
+ q->reset_status.response_code = 0;
+ vfio_ap_free_aqic_resources(q);
break;
default:
WARN(true,
"PQAP/ZAPQ for %02x.%04x failed with invalid rc=%u\n",
AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
status.response_code);
- return -EIO;
}
-
- vfio_ap_free_aqic_resources(q);
-
- return ret;
}
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable)
{
- int ret, loop_cursor, rc = 0;
+ int ret = 0, loop_cursor;
struct vfio_ap_queue *q;
+ hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode)
+ vfio_ap_mdev_reset_queue(q);
+
hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
- ret = vfio_ap_mdev_reset_queue(q);
- /*
- * Regardless whether a queue turns out to be busy, or
- * is not operational, we need to continue resetting
- * the remaining queues.
- */
- if (ret)
- rc = ret;
+ flush_work(&q->reset_work);
+
+ if (q->reset_status.response_code)
+ ret = -EIO;
}
- return rc;
+ return ret;
}
static int vfio_ap_mdev_open_device(struct vfio_device *vdev)
@@ -2038,6 +2083,8 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
q->apqn = to_ap_queue(&apdev->device)->qid;
q->saved_isc = VFIO_AP_ISC_INVALID;
+ memset(&q->reset_status, 0, sizeof(q->reset_status));
+ INIT_WORK(&q->reset_work, apq_reset_check);
matrix_mdev = get_update_locks_by_apqn(q->apqn);
if (matrix_mdev) {
@@ -2087,6 +2134,7 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
}
vfio_ap_mdev_reset_queue(q);
+ flush_work(&q->reset_work);
dev_set_drvdata(&apdev->device, NULL);
kfree(q);
release_update_locks_for_mdev(matrix_mdev);
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index 4642bbdbd1b2..88aff8b81f2f 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -133,7 +133,8 @@ struct ap_matrix_mdev {
* @apqn: the APQN of the AP queue device
* @saved_isc: the guest ISC registered with the GIB interface
* @mdev_qnode: allows the vfio_ap_queue struct to be added to a hashtable
- * @reset_rc: the status response code from the last reset of the queue
+ * @reset_status: the status from the last reset of the queue
+ * @reset_work: work to wait for queue reset to complete
*/
struct vfio_ap_queue {
struct ap_matrix_mdev *matrix_mdev;
@@ -142,7 +143,8 @@ struct vfio_ap_queue {
#define VFIO_AP_ISC_INVALID 0xff
unsigned char saved_isc;
struct hlist_node mdev_qnode;
- unsigned int reset_rc;
+ struct ap_queue_status reset_status;
+ struct work_struct reset_work;
};
int vfio_ap_mdev_register(void);
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
index 83f692c9c197..e69de29bb2d1 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.c
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -1,227 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright IBM Corp. 2001, 2012
- * Author(s): Robert Burroughs
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
- * Ralph Wuerthner <rwuerthn@de.ibm.com>
- * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/atomic.h>
-#include <linux/uaccess.h>
-#include <linux/mod_devicetable.h>
-
-#include "ap_bus.h"
-#include "zcrypt_api.h"
-#include "zcrypt_error.h"
-#include "zcrypt_cex2a.h"
-#include "zcrypt_msgtype50.h"
-
-#define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */
-#define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */
-#define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE
-#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */
-
-#define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
-#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
-
-#define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus
- * (max outputdatalength) +
- * type80_hdr
- */
-#define CEX3A_MAX_MESSAGE_SIZE sizeof(struct type50_crb3_msg)
-
-#define CEX2A_CLEANUP_TIME (15 * HZ)
-#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
-
-MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \
- "Copyright IBM Corp. 2001, 2018");
-MODULE_LICENSE("GPL");
-
-static struct ap_device_id zcrypt_cex2a_card_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_CEX2A,
- .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
- { .dev_type = AP_DEVICE_TYPE_CEX3A,
- .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
- { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids);
-
-static struct ap_device_id zcrypt_cex2a_queue_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_CEX2A,
- .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
- { .dev_type = AP_DEVICE_TYPE_CEX3A,
- .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
- { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids);
-
-/*
- * Probe function for CEX2A card devices. It always accepts the AP device
- * since the bus_match already checked the card type.
- * @ap_dev: pointer to the AP device.
- */
-static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev)
-{
- /*
- * Normalized speed ratings per crypto adapter
- * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
- */
- static const int CEX2A_SPEED_IDX[] = {
- 800, 1000, 2000, 900, 1200, 2400, 0, 0};
- static const int CEX3A_SPEED_IDX[] = {
- 400, 500, 1000, 450, 550, 1200, 0, 0};
-
- struct ap_card *ac = to_ap_card(&ap_dev->device);
- struct zcrypt_card *zc;
- int rc = 0;
-
- zc = zcrypt_card_alloc();
- if (!zc)
- return -ENOMEM;
- zc->card = ac;
- dev_set_drvdata(&ap_dev->device, zc);
-
- if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) {
- zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
- zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
- zc->speed_rating = CEX2A_SPEED_IDX;
- zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
- zc->type_string = "CEX2A";
- zc->user_space_type = ZCRYPT_CEX2A;
- } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) {
- zc->min_mod_size = CEX2A_MIN_MOD_SIZE;
- zc->max_mod_size = CEX2A_MAX_MOD_SIZE;
- zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE;
- if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) &&
- ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) {
- zc->max_mod_size = CEX3A_MAX_MOD_SIZE;
- zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE;
- }
- zc->speed_rating = CEX3A_SPEED_IDX;
- zc->type_string = "CEX3A";
- zc->user_space_type = ZCRYPT_CEX3A;
- } else {
- zcrypt_card_free(zc);
- return -ENODEV;
- }
- zc->online = 1;
-
- rc = zcrypt_card_register(zc);
- if (rc)
- zcrypt_card_free(zc);
-
- return rc;
-}
-
-/*
- * This is called to remove the CEX2A card driver information
- * if an AP card device is removed.
- */
-static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev)
-{
- struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device);
-
- zcrypt_card_unregister(zc);
-}
-
-static struct ap_driver zcrypt_cex2a_card_driver = {
- .probe = zcrypt_cex2a_card_probe,
- .remove = zcrypt_cex2a_card_remove,
- .ids = zcrypt_cex2a_card_ids,
- .flags = AP_DRIVER_FLAG_DEFAULT,
-};
-
-/*
- * Probe function for CEX2A queue devices. It always accepts the AP device
- * since the bus_match already checked the queue type.
- * @ap_dev: pointer to the AP device.
- */
-static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev)
-{
- struct ap_queue *aq = to_ap_queue(&ap_dev->device);
- struct zcrypt_queue *zq = NULL;
- int rc;
-
- switch (ap_dev->device_type) {
- case AP_DEVICE_TYPE_CEX2A:
- zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE);
- if (!zq)
- return -ENOMEM;
- break;
- case AP_DEVICE_TYPE_CEX3A:
- zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE);
- if (!zq)
- return -ENOMEM;
- break;
- }
- if (!zq)
- return -ENODEV;
- zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT);
- zq->queue = aq;
- zq->online = 1;
- atomic_set(&zq->load, 0);
- ap_queue_init_state(aq);
- ap_queue_init_reply(aq, &zq->reply);
- aq->request_timeout = CEX2A_CLEANUP_TIME;
- dev_set_drvdata(&ap_dev->device, zq);
- rc = zcrypt_queue_register(zq);
- if (rc)
- zcrypt_queue_free(zq);
-
- return rc;
-}
-
-/*
- * This is called to remove the CEX2A queue driver information
- * if an AP queue device is removed.
- */
-static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev)
-{
- struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device);
-
- zcrypt_queue_unregister(zq);
-}
-
-static struct ap_driver zcrypt_cex2a_queue_driver = {
- .probe = zcrypt_cex2a_queue_probe,
- .remove = zcrypt_cex2a_queue_remove,
- .ids = zcrypt_cex2a_queue_ids,
- .flags = AP_DRIVER_FLAG_DEFAULT,
-};
-
-int __init zcrypt_cex2a_init(void)
-{
- int rc;
-
- rc = ap_driver_register(&zcrypt_cex2a_card_driver,
- THIS_MODULE, "cex2acard");
- if (rc)
- return rc;
-
- rc = ap_driver_register(&zcrypt_cex2a_queue_driver,
- THIS_MODULE, "cex2aqueue");
- if (rc)
- ap_driver_unregister(&zcrypt_cex2a_card_driver);
-
- return rc;
-}
-
-void __exit zcrypt_cex2a_exit(void)
-{
- ap_driver_unregister(&zcrypt_cex2a_queue_driver);
- ap_driver_unregister(&zcrypt_cex2a_card_driver);
-}
-
-module_init(zcrypt_cex2a_init);
-module_exit(zcrypt_cex2a_exit);
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
index 7842214d9d09..e69de29bb2d1 100644
--- a/drivers/s390/crypto/zcrypt_cex2a.h
+++ b/drivers/s390/crypto/zcrypt_cex2a.h
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright IBM Corp. 2001, 2006
- * Author(s): Robert Burroughs
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
- */
-
-#ifndef _ZCRYPT_CEX2A_H_
-#define _ZCRYPT_CEX2A_H_
-
-/**
- * The type 50 message family is associated with CEXxA cards.
- *
- * The four members of the family are described below.
- *
- * Note that all unsigned char arrays are right-justified and left-padded
- * with zeroes.
- *
- * Note that all reserved fields must be zeroes.
- */
-struct type50_hdr {
- unsigned char reserved1;
- unsigned char msg_type_code; /* 0x50 */
- unsigned short msg_len;
- unsigned char reserved2;
- unsigned char ignored;
- unsigned short reserved3;
-} __packed;
-
-#define TYPE50_TYPE_CODE 0x50
-
-#define TYPE50_MEB1_FMT 0x0001
-#define TYPE50_MEB2_FMT 0x0002
-#define TYPE50_MEB3_FMT 0x0003
-#define TYPE50_CRB1_FMT 0x0011
-#define TYPE50_CRB2_FMT 0x0012
-#define TYPE50_CRB3_FMT 0x0013
-
-/* Mod-Exp, with a small modulus */
-struct type50_meb1_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0001 */
- unsigned char reserved[6];
- unsigned char exponent[128];
- unsigned char modulus[128];
- unsigned char message[128];
-} __packed;
-
-/* Mod-Exp, with a large modulus */
-struct type50_meb2_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0002 */
- unsigned char reserved[6];
- unsigned char exponent[256];
- unsigned char modulus[256];
- unsigned char message[256];
-} __packed;
-
-/* Mod-Exp, with a larger modulus */
-struct type50_meb3_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0003 */
- unsigned char reserved[6];
- unsigned char exponent[512];
- unsigned char modulus[512];
- unsigned char message[512];
-} __packed;
-
-/* CRT, with a small modulus */
-struct type50_crb1_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0011 */
- unsigned char reserved[6];
- unsigned char p[64];
- unsigned char q[64];
- unsigned char dp[64];
- unsigned char dq[64];
- unsigned char u[64];
- unsigned char message[128];
-} __packed;
-
-/* CRT, with a large modulus */
-struct type50_crb2_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0012 */
- unsigned char reserved[6];
- unsigned char p[128];
- unsigned char q[128];
- unsigned char dp[128];
- unsigned char dq[128];
- unsigned char u[128];
- unsigned char message[256];
-} __packed;
-
-/* CRT, with a larger modulus */
-struct type50_crb3_msg {
- struct type50_hdr header;
- unsigned short keyblock_type; /* 0x0013 */
- unsigned char reserved[6];
- unsigned char p[256];
- unsigned char q[256];
- unsigned char dp[256];
- unsigned char dq[256];
- unsigned char u[256];
- unsigned char message[512];
-} __packed;
-
-/**
- * The type 80 response family is associated with a CEXxA cards.
- *
- * Note that all unsigned char arrays are right-justified and left-padded
- * with zeroes.
- *
- * Note that all reserved fields must be zeroes.
- */
-
-#define TYPE80_RSP_CODE 0x80
-
-struct type80_hdr {
- unsigned char reserved1;
- unsigned char type; /* 0x80 */
- unsigned short len;
- unsigned char code; /* 0x00 */
- unsigned char reserved2[3];
- unsigned char reserved3[8];
-} __packed;
-
-int zcrypt_cex2a_init(void);
-void zcrypt_cex2a_exit(void);
-
-#endif /* _ZCRYPT_CEX2A_H_ */
diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c
index 251b5bd3d19c..e69de29bb2d1 100644
--- a/drivers/s390/crypto/zcrypt_cex2c.c
+++ b/drivers/s390/crypto/zcrypt_cex2c.c
@@ -1,421 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright IBM Corp. 2001, 2018
- * Author(s): Robert Burroughs
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
- * Ralph Wuerthner <rwuerthn@de.ibm.com>
- * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/atomic.h>
-#include <linux/uaccess.h>
-#include <linux/mod_devicetable.h>
-
-#include "ap_bus.h"
-#include "zcrypt_api.h"
-#include "zcrypt_error.h"
-#include "zcrypt_msgtype6.h"
-#include "zcrypt_cex2c.h"
-#include "zcrypt_cca_key.h"
-#include "zcrypt_ccamisc.h"
-
-#define CEX2C_MIN_MOD_SIZE 16 /* 128 bits */
-#define CEX2C_MAX_MOD_SIZE 256 /* 2048 bits */
-#define CEX3C_MIN_MOD_SIZE 16 /* 128 bits */
-#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
-#define CEX2C_MAX_XCRB_MESSAGE_SIZE (12 * 1024)
-#define CEX2C_CLEANUP_TIME (15 * HZ)
-
-MODULE_AUTHOR("IBM Corporation");
-MODULE_DESCRIPTION("CEX2C/CEX3C Cryptographic Coprocessor device driver, " \
- "Copyright IBM Corp. 2001, 2018");
-MODULE_LICENSE("GPL");
-
-static struct ap_device_id zcrypt_cex2c_card_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_CEX2C,
- .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
- { .dev_type = AP_DEVICE_TYPE_CEX3C,
- .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
- { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_card_ids);
-
-static struct ap_device_id zcrypt_cex2c_queue_ids[] = {
- { .dev_type = AP_DEVICE_TYPE_CEX2C,
- .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
- { .dev_type = AP_DEVICE_TYPE_CEX3C,
- .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
- { /* end of list */ },
-};
-
-MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_queue_ids);
-
-/*
- * CCA card additional device attributes
- */
-static ssize_t cca_serialnr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct zcrypt_card *zc = dev_get_drvdata(dev);
- struct cca_info ci;
- struct ap_card *ac = to_ap_card(dev);
-
- memset(&ci, 0, sizeof(ci));
-
- if (ap_domain_index >= 0)
- cca_get_info(ac->id, ap_domain_index, &ci, zc->online);
-
- return sysfs_emit(buf, "%s\n", ci.serial);
-}
-
-static struct device_attribute dev_attr_cca_serialnr =
- __ATTR(serialnr, 0444, cca_serialnr_show, NULL);
-
-static struct attribute *cca_card_attrs[] = {
- &dev_attr_cca_serialnr.attr,
- NULL,
-};
-
-static const struct attribute_group cca_card_attr_grp = {
- .attrs = cca_card_attrs,
-};
-
- /*
- * CCA queue additional device attributes
- */
-static ssize_t cca_mkvps_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct zcrypt_queue *zq = dev_get_drvdata(dev);
- int n = 0;
- struct cca_info ci;
- static const char * const cao_state[] = { "invalid", "valid" };
- static const char * const new_state[] = { "empty", "partial", "full" };
-
- memset(&ci, 0, sizeof(ci));
-
- cca_get_info(AP_QID_CARD(zq->queue->qid),
- AP_QID_QUEUE(zq->queue->qid),
- &ci, zq->online);
-
- if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3')
- n = sysfs_emit(buf, "AES NEW: %s 0x%016llx\n",
- new_state[ci.new_aes_mk_state - '1'],
- ci.new_aes_mkvp);
- else
- n = sysfs_emit(buf, "AES NEW: - -\n");
-
- if (ci.cur_aes_mk_state >= '1' && ci.cur_aes_mk_state <= '2')
- n += sysfs_emit_at(buf, n, "AES CUR: %s 0x%016llx\n",
- cao_state[ci.cur_aes_mk_state - '1'],
- ci.cur_aes_mkvp);
- else
- n += sysfs_emit_at(buf, n, "AES CUR: - -\n");
-
- if (ci.old_aes_mk_state >= '1' && ci.old_aes_mk_state <= '2')
- n += sysfs_emit_at(buf, n, "AES OLD: %s 0x%016llx\n",
- cao_state[ci.old_aes_mk_state - '1'],
- ci.old_aes_mkvp);
- else
- n += sysfs_emit_at(buf, n, "AES OLD: - -\n");
-
- if (ci.new_apka_mk_state >= '1' && ci.new_apka_mk_state <= '3')
- n += sysfs_emit_at(buf, n, "APKA NEW: %s 0x%016llx\n",
- new_state[ci.new_apka_mk_state - '1'],
- ci.new_apka_mkvp);
- else
- n += sysfs_emit_at(buf, n, "APKA NEW: - -\n");
-
- if (ci.cur_apka_mk_state >= '1' && ci.cur_apka_mk_state <= '2')
- n += sysfs_emit_at(buf, n, "APKA CUR: %s 0x%016llx\n",
- cao_state[ci.cur_apka_mk_state - '1'],
- ci.cur_apka_mkvp);
- else
- n += sysfs_emit_at(buf, n, "APKA CUR: - -\n");
-
- if (ci.old_apka_mk_state >= '1' && ci.old_apka_mk_state <= '2')
- n += sysfs_emit_at(buf, n, "APKA OLD: %s 0x%016llx\n",
- cao_state[ci.old_apka_mk_state - '1'],
- ci.old_apka_mkvp);
- else
- n += sysfs_emit_at(buf, n, "APKA OLD: - -\n");
-
- return n;
-}
-
-static struct device_attribute dev_attr_cca_mkvps =
- __ATTR(mkvps, 0444, cca_mkvps_show, NULL);
-
-static struct attribute *cca_queue_attrs[] = {
- &dev_attr_cca_mkvps.attr,
- NULL,
-};
-
-static const struct attribute_group cca_queue_attr_grp = {
- .attrs = cca_queue_attrs,
-};
-
-/*
- * Large random number detection function. Its sends a message to a CEX2C/CEX3C
- * card to find out if large random numbers are supported.
- * @ap_dev: pointer to the AP device.
- *
- * Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
- */
-static int zcrypt_cex2c_rng_supported(struct ap_queue *aq)
-{
- struct ap_message ap_msg;
- unsigned long psmid;
- unsigned int domain;
- struct {
- struct type86_hdr hdr;
- struct type86_fmt2_ext fmt2;
- struct CPRBX cprbx;
- } __packed *reply;
- struct {
- struct type6_hdr hdr;
- struct CPRBX cprbx;
- char function_code[2];
- short int rule_length;
- char rule[8];
- short int verb_length;
- short int key_length;
- } __packed *msg;
- int rc, i;
-
- ap_init_message(&ap_msg);
- ap_msg.msg = (void *)get_zeroed_page(GFP_KERNEL);
- if (!ap_msg.msg)
- return -ENOMEM;
- ap_msg.bufsize = PAGE_SIZE;
-
- rng_type6cprb_msgx(&ap_msg, 4, &domain);
-
- msg = ap_msg.msg;
- msg->cprbx.domain = AP_QID_QUEUE(aq->qid);
-
- rc = ap_send(aq->qid, 0x0102030405060708UL, ap_msg.msg, ap_msg.len);
- if (rc)
- goto out_free;
-
- /* Wait for the test message to complete. */
- for (i = 0; i < 2 * HZ; i++) {
- msleep(1000 / HZ);
- rc = ap_recv(aq->qid, &psmid, ap_msg.msg, ap_msg.bufsize);
- if (rc == 0 && psmid == 0x0102030405060708UL)
- break;
- }
-
- if (i >= 2 * HZ) {
- /* Got no answer. */
- rc = -ENODEV;
- goto out_free;
- }
-
- reply = ap_msg.msg;
- if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0)
- rc = 1;
- else
- rc = 0;
-out_free:
- free_page((unsigned long)ap_msg.msg);
- return rc;
-}
-
-/*
- * Probe function for CEX2C/CEX3C card devices. It always accepts the
- * AP device since the bus_match already checked the hardware type.
- * @ap_dev: pointer to the AP card device.
- */
-static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
-{
- /*
- * Normalized speed ratings per crypto adapter
- * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY
- */
- static const int CEX2C_SPEED_IDX[] = {
- 1000, 1400, 2400, 1100, 1500, 2600, 100, 12};
- static const int CEX3C_SPEED_IDX[] = {
- 500, 700, 1400, 550, 800, 1500, 80, 10};
-
- struct ap_card *ac = to_ap_card(&ap_dev->device);
- struct zcrypt_card *zc;
- int rc = 0;
-
- zc = zcrypt_card_alloc();
- if (!zc)
- return -ENOMEM;
- zc->card = ac;
- dev_set_drvdata(&ap_dev->device, zc);
- switch (ac->ap_dev.device_type) {
- case AP_DEVICE_TYPE_CEX2C:
- zc->user_space_type = ZCRYPT_CEX2C;
- zc->type_string = "CEX2C";
- zc->speed_rating = CEX2C_SPEED_IDX;
- zc->min_mod_size = CEX2C_MIN_MOD_SIZE;
- zc->max_mod_size = CEX2C_MAX_MOD_SIZE;
- zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE;
- break;
- case AP_DEVICE_TYPE_CEX3C:
- zc->user_space_type = ZCRYPT_CEX3C;
- zc->type_string = "CEX3C";
- zc->speed_rating = CEX3C_SPEED_IDX;
- zc->min_mod_size = CEX3C_MIN_MOD_SIZE;
- zc->max_mod_size = CEX3C_MAX_MOD_SIZE;
- zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
- break;
- default:
- zcrypt_card_free(zc);
- return -ENODEV;
- }
- zc->online = 1;
-
- rc = zcrypt_card_register(zc);
- if (rc) {
- zcrypt_card_free(zc);
- return rc;
- }
-
- if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) {
- rc = sysfs_create_group(&ap_dev->device.kobj,
- &cca_card_attr_grp);
- if (rc) {
- zcrypt_card_unregister(zc);
- zcrypt_card_free(zc);
- }
- }
-
- return rc;
-}
-
-/*
- * This is called to remove the CEX2C/CEX3C card driver information
- * if an AP card device is removed.
- */
-static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev)
-{
- struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device);
- struct ap_card *ac = to_ap_card(&ap_dev->device);
-
- if (ap_test_bit(&ac->functions, AP_FUNC_COPRO))
- sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_grp);
-
- zcrypt_card_unregister(zc);
-}
-
-static struct ap_driver zcrypt_cex2c_card_driver = {
- .probe = zcrypt_cex2c_card_probe,
- .remove = zcrypt_cex2c_card_remove,
- .ids = zcrypt_cex2c_card_ids,
- .flags = AP_DRIVER_FLAG_DEFAULT,
-};
-
-/*
- * Probe function for CEX2C/CEX3C queue devices. It always accepts the
- * AP device since the bus_match already checked the hardware type.
- * @ap_dev: pointer to the AP card device.
- */
-static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev)
-{
- struct ap_queue *aq = to_ap_queue(&ap_dev->device);
- struct zcrypt_queue *zq;
- int rc;
-
- zq = zcrypt_queue_alloc(CEX2C_MAX_XCRB_MESSAGE_SIZE);
- if (!zq)
- return -ENOMEM;
- zq->queue = aq;
- zq->online = 1;
- atomic_set(&zq->load, 0);
- ap_rapq(aq->qid, 0);
- rc = zcrypt_cex2c_rng_supported(aq);
- if (rc < 0) {
- zcrypt_queue_free(zq);
- return rc;
- }
- if (rc)
- zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
- MSGTYPE06_VARIANT_DEFAULT);
- else
- zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
- MSGTYPE06_VARIANT_NORNG);
- ap_queue_init_state(aq);
- ap_queue_init_reply(aq, &zq->reply);
- aq->request_timeout = CEX2C_CLEANUP_TIME;
- dev_set_drvdata(&ap_dev->device, zq);
- rc = zcrypt_queue_register(zq);
- if (rc) {
- zcrypt_queue_free(zq);
- return rc;
- }
-
- if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
- rc = sysfs_create_group(&ap_dev->device.kobj,
- &cca_queue_attr_grp);
- if (rc) {
- zcrypt_queue_unregister(zq);
- zcrypt_queue_free(zq);
- }
- }
-
- return rc;
-}
-
-/*
- * This is called to remove the CEX2C/CEX3C queue driver information
- * if an AP queue device is removed.
- */
-static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev)
-{
- struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device);
- struct ap_queue *aq = to_ap_queue(&ap_dev->device);
-
- if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO))
- sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_grp);
-
- zcrypt_queue_unregister(zq);
-}
-
-static struct ap_driver zcrypt_cex2c_queue_driver = {
- .probe = zcrypt_cex2c_queue_probe,
- .remove = zcrypt_cex2c_queue_remove,
- .ids = zcrypt_cex2c_queue_ids,
- .flags = AP_DRIVER_FLAG_DEFAULT,
-};
-
-int __init zcrypt_cex2c_init(void)
-{
- int rc;
-
- rc = ap_driver_register(&zcrypt_cex2c_card_driver,
- THIS_MODULE, "cex2card");
- if (rc)
- return rc;
-
- rc = ap_driver_register(&zcrypt_cex2c_queue_driver,
- THIS_MODULE, "cex2cqueue");
- if (rc)
- ap_driver_unregister(&zcrypt_cex2c_card_driver);
-
- return rc;
-}
-
-void zcrypt_cex2c_exit(void)
-{
- ap_driver_unregister(&zcrypt_cex2c_queue_driver);
- ap_driver_unregister(&zcrypt_cex2c_card_driver);
-}
-
-module_init(zcrypt_cex2c_init);
-module_exit(zcrypt_cex2c_exit);
diff --git a/drivers/s390/crypto/zcrypt_cex2c.h b/drivers/s390/crypto/zcrypt_cex2c.h
index 6ec405c2bec2..e69de29bb2d1 100644
--- a/drivers/s390/crypto/zcrypt_cex2c.h
+++ b/drivers/s390/crypto/zcrypt_cex2c.h
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright IBM Corp. 2001, 2018
- * Author(s): Robert Burroughs
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
- * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
- */
-
-#ifndef _ZCRYPT_CEX2C_H_
-#define _ZCRYPT_CEX2C_H_
-
-int zcrypt_cex2c_init(void);
-void zcrypt_cex2c_exit(void);
-
-#endif /* _ZCRYPT_CEX2C_H_ */
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c
index 958f5ee47f1b..0a877f9792c2 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.c
+++ b/drivers/s390/crypto/zcrypt_ep11misc.c
@@ -29,6 +29,8 @@
#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__)
#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__)
+#define EP11_PINBLOB_V1_BYTES 56
+
/* default iv used here */
static const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
@@ -113,6 +115,109 @@ static void __exit card_cache_free(void)
spin_unlock_bh(&card_list_lock);
}
+static int ep11_kb_split(const u8 *kb, size_t kblen, u32 kbver,
+ struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
+ u8 **kbpl, size_t *kbplsize)
+{
+ struct ep11kblob_header *hdr = NULL;
+ size_t hdrsize, plsize = 0;
+ int rc = -EINVAL;
+ u8 *pl = NULL;
+
+ if (kblen < sizeof(struct ep11kblob_header))
+ goto out;
+ hdr = (struct ep11kblob_header *)kb;
+
+ switch (kbver) {
+ case TOKVER_EP11_AES:
+ /* header overlays the payload */
+ hdrsize = 0;
+ break;
+ case TOKVER_EP11_ECC_WITH_HEADER:
+ case TOKVER_EP11_AES_WITH_HEADER:
+ /* payload starts after the header */
+ hdrsize = sizeof(struct ep11kblob_header);
+ break;
+ default:
+ goto out;
+ }
+
+ plsize = kblen - hdrsize;
+ pl = (u8 *)kb + hdrsize;
+
+ if (kbhdr)
+ *kbhdr = hdr;
+ if (kbhdrsize)
+ *kbhdrsize = hdrsize;
+ if (kbpl)
+ *kbpl = pl;
+ if (kbplsize)
+ *kbplsize = plsize;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int ep11_kb_decode(const u8 *kb, size_t kblen,
+ struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
+ struct ep11keyblob **kbpl, size_t *kbplsize)
+{
+ struct ep11kblob_header *tmph, *hdr = NULL;
+ size_t hdrsize = 0, plsize = 0;
+ struct ep11keyblob *pl = NULL;
+ int rc = -EINVAL;
+ u8 *tmpp;
+
+ if (kblen < sizeof(struct ep11kblob_header))
+ goto out;
+ tmph = (struct ep11kblob_header *)kb;
+
+ if (tmph->type != TOKTYPE_NON_CCA &&
+ tmph->len > kblen)
+ goto out;
+
+ if (ep11_kb_split(kb, kblen, tmph->version,
+ &hdr, &hdrsize, &tmpp, &plsize))
+ goto out;
+
+ if (plsize < sizeof(struct ep11keyblob))
+ goto out;
+
+ if (!is_ep11_keyblob(tmpp))
+ goto out;
+
+ pl = (struct ep11keyblob *)tmpp;
+ plsize = hdr->len - hdrsize;
+
+ if (kbhdr)
+ *kbhdr = hdr;
+ if (kbhdrsize)
+ *kbhdrsize = hdrsize;
+ if (kbpl)
+ *kbpl = pl;
+ if (kbplsize)
+ *kbplsize = plsize;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+/*
+ * For valid ep11 keyblobs, returns a reference to the wrappingkey verification
+ * pattern. Otherwise NULL.
+ */
+const u8 *ep11_kb_wkvp(const u8 *keyblob, size_t keybloblen)
+{
+ struct ep11keyblob *kb;
+
+ if (ep11_kb_decode(keyblob, keybloblen, NULL, NULL, &kb, NULL))
+ return NULL;
+ return kb->wkvp;
+}
+EXPORT_SYMBOL(ep11_kb_wkvp);
+
/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
*/
@@ -489,7 +594,7 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
struct ep11_cprb *req = NULL, *rep = NULL;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
- int api = 1, rc = -ENOMEM;
+ int api = EP11_API_V1, rc = -ENOMEM;
/* request cprb and payload */
req = alloc_cprb(sizeof(struct ep11_info_req_pl));
@@ -664,8 +769,9 @@ EXPORT_SYMBOL(ep11_get_domain_info);
*/
#define KEY_ATTR_DEFAULTS 0x00200c00
-int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
- u8 *keybuf, size_t *keybufsize)
+static int _ep11_genaeskey(u16 card, u16 domain,
+ u32 keybitsize, u32 keygenflags,
+ u8 *keybuf, size_t *keybufsize)
{
struct keygen_req_pl {
struct pl_head head;
@@ -685,8 +791,7 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
u32 attr_bool_bits;
u32 attr_val_len_type;
u32 attr_val_len_value;
- u8 pin_tag;
- u8 pin_len;
+ /* followed by empty pin tag or empty pinblob tag */
} __packed * req_pl;
struct keygen_rep_pl {
struct pl_head head;
@@ -699,10 +804,11 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
u8 data[512];
} __packed * rep_pl;
struct ep11_cprb *req = NULL, *rep = NULL;
+ size_t req_pl_size, pinblob_size = 0;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
- struct ep11keyblob *kb;
int api, rc = -ENOMEM;
+ u8 *p;
switch (keybitsize) {
case 128:
@@ -718,12 +824,22 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
}
/* request cprb and payload */
- req = alloc_cprb(sizeof(struct keygen_req_pl));
+ api = (!keygenflags || keygenflags & 0x00200000) ?
+ EP11_API_V4 : EP11_API_V1;
+ if (ap_is_se_guest()) {
+ /*
+ * genkey within SE environment requires API ordinal 6
+ * with empty pinblob
+ */
+ api = EP11_API_V6;
+ pinblob_size = EP11_PINBLOB_V1_BYTES;
+ }
+ req_pl_size = sizeof(struct keygen_req_pl) + ASN1TAGLEN(pinblob_size);
+ req = alloc_cprb(req_pl_size);
if (!req)
goto out;
req_pl = (struct keygen_req_pl *)(((u8 *)req) + sizeof(*req));
- api = (!keygenflags || keygenflags & 0x00200000) ? 4 : 1;
- prep_head(&req_pl->head, sizeof(*req_pl), api, 21); /* GenerateKey */
+ prep_head(&req_pl->head, req_pl_size, api, 21); /* GenerateKey */
req_pl->var_tag = 0x04;
req_pl->var_len = sizeof(u32);
req_pl->keybytes_tag = 0x04;
@@ -739,7 +855,10 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
req_pl->attr_bool_bits = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS;
req_pl->attr_val_len_type = 0x00000161; /* CKA_VALUE_LEN */
req_pl->attr_val_len_value = keybitsize / 8;
- req_pl->pin_tag = 0x04;
+ p = ((u8 *)req_pl) + sizeof(*req_pl);
+ /* pin tag */
+ *p++ = 0x04;
+ *p++ = pinblob_size;
/* reply cprb and payload */
rep = alloc_cprb(sizeof(struct keygen_rep_pl));
@@ -754,7 +873,7 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
target.ap_id = card;
target.dom_id = domain;
prep_urb(urb, &target, 1,
- req, sizeof(*req) + sizeof(*req_pl),
+ req, sizeof(*req) + req_pl_size,
rep, sizeof(*rep) + sizeof(*rep_pl));
rc = zcrypt_send_ep11_cprb(urb);
@@ -780,14 +899,9 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
goto out;
}
- /* copy key blob and set header values */
+ /* copy key blob */
memcpy(keybuf, rep_pl->data, rep_pl->data_len);
*keybufsize = rep_pl->data_len;
- kb = (struct ep11keyblob *)keybuf;
- kb->head.type = TOKTYPE_NON_CCA;
- kb->head.len = rep_pl->data_len;
- kb->head.version = TOKVER_EP11_AES;
- kb->head.keybitlen = keybitsize;
out:
kfree(req);
@@ -795,6 +909,43 @@ out:
kfree(urb);
return rc;
}
+
+int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
+ u8 *keybuf, size_t *keybufsize, u32 keybufver)
+{
+ struct ep11kblob_header *hdr;
+ size_t hdr_size, pl_size;
+ u8 *pl;
+ int rc;
+
+ switch (keybufver) {
+ case TOKVER_EP11_AES:
+ case TOKVER_EP11_AES_WITH_HEADER:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = ep11_kb_split(keybuf, *keybufsize, keybufver,
+ &hdr, &hdr_size, &pl, &pl_size);
+ if (rc)
+ return rc;
+
+ rc = _ep11_genaeskey(card, domain, keybitsize, keygenflags,
+ pl, &pl_size);
+ if (rc)
+ return rc;
+
+ *keybufsize = hdr_size + pl_size;
+
+ /* update header information */
+ hdr->type = TOKTYPE_NON_CCA;
+ hdr->len = *keybufsize;
+ hdr->version = keybufver;
+ hdr->bitlen = keybitsize;
+
+ return 0;
+}
EXPORT_SYMBOL(ep11_genaeskey);
static int ep11_cryptsingle(u16 card, u16 domain,
@@ -830,7 +981,7 @@ static int ep11_cryptsingle(u16 card, u16 domain,
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
size_t req_pl_size, rep_pl_size;
- int n, api = 1, rc = -ENOMEM;
+ int n, api = EP11_API_V1, rc = -ENOMEM;
u8 *p;
/* the simple asn1 coding used has length limits */
@@ -924,12 +1075,12 @@ out:
return rc;
}
-static int ep11_unwrapkey(u16 card, u16 domain,
- const u8 *kek, size_t keksize,
- const u8 *enckey, size_t enckeysize,
- u32 mech, const u8 *iv,
- u32 keybitsize, u32 keygenflags,
- u8 *keybuf, size_t *keybufsize)
+static int _ep11_unwrapkey(u16 card, u16 domain,
+ const u8 *kek, size_t keksize,
+ const u8 *enckey, size_t enckeysize,
+ u32 mech, const u8 *iv,
+ u32 keybitsize, u32 keygenflags,
+ u8 *keybuf, size_t *keybufsize)
{
struct uw_req_pl {
struct pl_head head;
@@ -949,7 +1100,7 @@ static int ep11_unwrapkey(u16 card, u16 domain,
* maybe followed by iv data
* followed by kek tag + kek blob
* followed by empty mac tag
- * followed by empty pin tag
+ * followed by empty pin tag or empty pinblob tag
* followed by encryted key tag + bytes
*/
} __packed * req_pl;
@@ -964,21 +1115,30 @@ static int ep11_unwrapkey(u16 card, u16 domain,
u8 data[512];
} __packed * rep_pl;
struct ep11_cprb *req = NULL, *rep = NULL;
+ size_t req_pl_size, pinblob_size = 0;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
- struct ep11keyblob *kb;
- size_t req_pl_size;
int api, rc = -ENOMEM;
u8 *p;
/* request cprb and payload */
+ api = (!keygenflags || keygenflags & 0x00200000) ?
+ EP11_API_V4 : EP11_API_V1;
+ if (ap_is_se_guest()) {
+ /*
+ * unwrap within SE environment requires API ordinal 6
+ * with empty pinblob
+ */
+ api = EP11_API_V6;
+ pinblob_size = EP11_PINBLOB_V1_BYTES;
+ }
req_pl_size = sizeof(struct uw_req_pl) + (iv ? 16 : 0)
- + ASN1TAGLEN(keksize) + 4 + ASN1TAGLEN(enckeysize);
+ + ASN1TAGLEN(keksize) + ASN1TAGLEN(0)
+ + ASN1TAGLEN(pinblob_size) + ASN1TAGLEN(enckeysize);
req = alloc_cprb(req_pl_size);
if (!req)
goto out;
req_pl = (struct uw_req_pl *)(((u8 *)req) + sizeof(*req));
- api = (!keygenflags || keygenflags & 0x00200000) ? 4 : 1;
prep_head(&req_pl->head, req_pl_size, api, 34); /* UnwrapKey */
req_pl->attr_tag = 0x04;
req_pl->attr_len = 7 * sizeof(u32);
@@ -1003,9 +1163,10 @@ static int ep11_unwrapkey(u16 card, u16 domain,
/* empty mac key tag */
*p++ = 0x04;
*p++ = 0;
- /* empty pin tag */
+ /* pin tag */
*p++ = 0x04;
- *p++ = 0;
+ *p++ = pinblob_size;
+ p += pinblob_size;
/* encrypted key value tag and bytes */
p += asn1tag_write(p, 0x04, enckey, enckeysize);
@@ -1048,14 +1209,9 @@ static int ep11_unwrapkey(u16 card, u16 domain,
goto out;
}
- /* copy key blob and set header values */
+ /* copy key blob */
memcpy(keybuf, rep_pl->data, rep_pl->data_len);
*keybufsize = rep_pl->data_len;
- kb = (struct ep11keyblob *)keybuf;
- kb->head.type = TOKTYPE_NON_CCA;
- kb->head.len = rep_pl->data_len;
- kb->head.version = TOKVER_EP11_AES;
- kb->head.keybitlen = keybitsize;
out:
kfree(req);
@@ -1064,10 +1220,46 @@ out:
return rc;
}
-static int ep11_wrapkey(u16 card, u16 domain,
- const u8 *key, size_t keysize,
- u32 mech, const u8 *iv,
- u8 *databuf, size_t *datasize)
+static int ep11_unwrapkey(u16 card, u16 domain,
+ const u8 *kek, size_t keksize,
+ const u8 *enckey, size_t enckeysize,
+ u32 mech, const u8 *iv,
+ u32 keybitsize, u32 keygenflags,
+ u8 *keybuf, size_t *keybufsize,
+ u8 keybufver)
+{
+ struct ep11kblob_header *hdr;
+ size_t hdr_size, pl_size;
+ u8 *pl;
+ int rc;
+
+ rc = ep11_kb_split(keybuf, *keybufsize, keybufver,
+ &hdr, &hdr_size, &pl, &pl_size);
+ if (rc)
+ return rc;
+
+ rc = _ep11_unwrapkey(card, domain, kek, keksize, enckey, enckeysize,
+ mech, iv, keybitsize, keygenflags,
+ pl, &pl_size);
+ if (rc)
+ return rc;
+
+ *keybufsize = hdr_size + pl_size;
+
+ /* update header information */
+ hdr = (struct ep11kblob_header *)keybuf;
+ hdr->type = TOKTYPE_NON_CCA;
+ hdr->len = *keybufsize;
+ hdr->version = keybufver;
+ hdr->bitlen = keybitsize;
+
+ return 0;
+}
+
+static int _ep11_wrapkey(u16 card, u16 domain,
+ const u8 *key, size_t keysize,
+ u32 mech, const u8 *iv,
+ u8 *databuf, size_t *datasize)
{
struct wk_req_pl {
struct pl_head head;
@@ -1097,20 +1289,10 @@ static int ep11_wrapkey(u16 card, u16 domain,
struct ep11_cprb *req = NULL, *rep = NULL;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
- struct ep11keyblob *kb;
size_t req_pl_size;
int api, rc = -ENOMEM;
- bool has_header = false;
u8 *p;
- /* maybe the session field holds a header with key info */
- kb = (struct ep11keyblob *)key;
- if (kb->head.type == TOKTYPE_NON_CCA &&
- kb->head.version == TOKVER_EP11_AES) {
- has_header = true;
- keysize = min_t(size_t, kb->head.len, keysize);
- }
-
/* request cprb and payload */
req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0)
+ ASN1TAGLEN(keysize) + 4;
@@ -1120,7 +1302,8 @@ static int ep11_wrapkey(u16 card, u16 domain,
if (!mech || mech == 0x80060001)
req->flags |= 0x20; /* CPACF_WRAP needs special bit */
req_pl = (struct wk_req_pl *)(((u8 *)req) + sizeof(*req));
- api = (!mech || mech == 0x80060001) ? 4 : 1; /* CKM_IBM_CPACF_WRAP */
+ api = (!mech || mech == 0x80060001) ? /* CKM_IBM_CPACF_WRAP */
+ EP11_API_V4 : EP11_API_V1;
prep_head(&req_pl->head, req_pl_size, api, 33); /* WrapKey */
req_pl->var_tag = 0x04;
req_pl->var_len = sizeof(u32);
@@ -1135,11 +1318,6 @@ static int ep11_wrapkey(u16 card, u16 domain,
}
/* key blob */
p += asn1tag_write(p, 0x04, key, keysize);
- /* maybe the key argument needs the head data cleaned out */
- if (has_header) {
- kb = (struct ep11keyblob *)(p - keysize);
- memset(&kb->head, 0, sizeof(kb->head));
- }
/* empty kek tag */
*p++ = 0x04;
*p++ = 0;
@@ -1198,10 +1376,10 @@ out:
}
int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
- const u8 *clrkey, u8 *keybuf, size_t *keybufsize)
+ const u8 *clrkey, u8 *keybuf, size_t *keybufsize,
+ u32 keytype)
{
int rc;
- struct ep11keyblob *kb;
u8 encbuf[64], *kek = NULL;
size_t clrkeylen, keklen, encbuflen = sizeof(encbuf);
@@ -1223,17 +1401,15 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
}
/* Step 1: generate AES 256 bit random kek key */
- rc = ep11_genaeskey(card, domain, 256,
- 0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
- kek, &keklen);
+ rc = _ep11_genaeskey(card, domain, 256,
+ 0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
+ kek, &keklen);
if (rc) {
DEBUG_ERR(
"%s generate kek key failed, rc=%d\n",
__func__, rc);
goto out;
}
- kb = (struct ep11keyblob *)kek;
- memset(&kb->head, 0, sizeof(kb->head));
/* Step 2: encrypt clear key value with the kek key */
rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen,
@@ -1248,7 +1424,7 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
/* Step 3: import the encrypted key value as a new key */
rc = ep11_unwrapkey(card, domain, kek, keklen,
encbuf, encbuflen, 0, def_iv,
- keybitsize, 0, keybuf, keybufsize);
+ keybitsize, 0, keybuf, keybufsize, keytype);
if (rc) {
DEBUG_ERR(
"%s importing key value as new key failed,, rc=%d\n",
@@ -1262,11 +1438,12 @@ out:
}
EXPORT_SYMBOL(ep11_clr2keyblob);
-int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
+int ep11_kblob2protkey(u16 card, u16 dom,
+ const u8 *keyblob, size_t keybloblen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- int rc = -EIO;
- u8 *wkbuf = NULL;
+ struct ep11kblob_header *hdr;
+ struct ep11keyblob *key;
size_t wkbuflen, keylen;
struct wk_info {
u16 version;
@@ -1277,31 +1454,17 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
u8 res2[8];
u8 pkey[];
} __packed * wki;
- const u8 *key;
- struct ep11kblob_header *hdr;
+ u8 *wkbuf = NULL;
+ int rc = -EIO;
- /* key with or without header ? */
- hdr = (struct ep11kblob_header *)keyblob;
- if (hdr->type == TOKTYPE_NON_CCA &&
- (hdr->version == TOKVER_EP11_AES_WITH_HEADER ||
- hdr->version == TOKVER_EP11_ECC_WITH_HEADER) &&
- is_ep11_keyblob(keyblob + sizeof(struct ep11kblob_header))) {
- /* EP11 AES or ECC key with header */
- key = keyblob + sizeof(struct ep11kblob_header);
- keylen = hdr->len - sizeof(struct ep11kblob_header);
- } else if (hdr->type == TOKTYPE_NON_CCA &&
- hdr->version == TOKVER_EP11_AES &&
- is_ep11_keyblob(keyblob)) {
- /* EP11 AES key (old style) */
- key = keyblob;
- keylen = hdr->len;
- } else if (is_ep11_keyblob(keyblob)) {
- /* raw EP11 key blob */
- key = keyblob;
- keylen = keybloblen;
- } else {
+ if (ep11_kb_decode((u8 *)keyblob, keybloblen, &hdr, NULL, &key, &keylen))
return -EINVAL;
+
+ if (hdr->version == TOKVER_EP11_AES) {
+ /* wipe overlayed header */
+ memset(hdr, 0, sizeof(*hdr));
}
+ /* !!! hdr is no longer a valid header !!! */
/* alloc temp working buffer */
wkbuflen = (keylen + AES_BLOCK_SIZE) & (~(AES_BLOCK_SIZE - 1));
@@ -1310,8 +1473,8 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
return -ENOMEM;
/* ep11 secure key -> protected key + info */
- rc = ep11_wrapkey(card, dom, key, keylen,
- 0, def_iv, wkbuf, &wkbuflen);
+ rc = _ep11_wrapkey(card, dom, (u8 *)key, keylen,
+ 0, def_iv, wkbuf, &wkbuflen);
if (rc) {
DEBUG_ERR(
"%s rewrapping ep11 key to pkey failed, rc=%d\n",
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.h b/drivers/s390/crypto/zcrypt_ep11misc.h
index a3eddf51242d..9d17fd5228a7 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.h
+++ b/drivers/s390/crypto/zcrypt_ep11misc.h
@@ -12,7 +12,9 @@
#include <asm/zcrypt.h>
#include <asm/pkey.h>
-#define EP11_API_V 4 /* highest known and supported EP11 API version */
+#define EP11_API_V1 1 /* min EP11 API, default if no higher api required */
+#define EP11_API_V4 4 /* supported EP11 API for the ep11misc cprbs */
+#define EP11_API_V6 6 /* min EP11 API for some cprbs in SE environment */
#define EP11_STRUCT_MAGIC 0x1234
#define EP11_BLOB_PKEY_EXTRACTABLE 0x00200000
@@ -29,14 +31,7 @@ struct ep11keyblob {
union {
u8 session[32];
/* only used for PKEY_TYPE_EP11: */
- struct {
- u8 type; /* 0x00 (TOKTYPE_NON_CCA) */
- u8 res0; /* unused */
- u16 len; /* total length in bytes of this blob */
- u8 version; /* 0x03 (TOKVER_EP11_AES) */
- u8 res1; /* unused */
- u16 keybitlen; /* clear key bit len, 0 for unknown */
- } head;
+ struct ep11kblob_header head;
};
u8 wkvp[16]; /* wrapping key verification pattern */
u64 attr; /* boolean key attributes */
@@ -56,6 +51,12 @@ static inline bool is_ep11_keyblob(const u8 *key)
}
/*
+ * For valid ep11 keyblobs, returns a reference to the wrappingkey verification
+ * pattern. Otherwise NULL.
+ */
+const u8 *ep11_kb_wkvp(const u8 *kblob, size_t kbloblen);
+
+/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
* If checkcpacfexport is enabled, the key is also checked for the
* attributes needed to export this key for CPACF use.
@@ -114,13 +115,14 @@ int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info);
* Generate (random) EP11 AES secure key.
*/
int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
- u8 *keybuf, size_t *keybufsize);
+ u8 *keybuf, size_t *keybufsize, u32 keybufver);
/*
* Generate EP11 AES secure key with given clear key value.
*/
int ep11_clr2keyblob(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
- const u8 *clrkey, u8 *keybuf, size_t *keybufsize);
+ const u8 *clrkey, u8 *keybuf, size_t *keybufsize,
+ u32 keytype);
/*
* Build a list of ep11 apqns meeting the following constrains:
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index 51f8f7a463f7..2e155de8abe5 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2023
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@@ -28,15 +28,12 @@
/* >= CEX3A: 4096 bits */
#define CEX3A_MAX_MOD_SIZE 512
-/* CEX2A: max outputdatalength + type80_hdr */
-#define CEX2A_MAX_RESPONSE_SIZE 0x110
-
/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */
#define CEX3A_MAX_RESPONSE_SIZE 0x210
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
- "Copyright IBM Corp. 2001, 2012");
+ "Copyright IBM Corp. 2001, 2023");
MODULE_LICENSE("GPL");
/*
@@ -366,20 +363,17 @@ static int convert_type80(struct zcrypt_queue *zq,
ap_send_online_uevent(&zq->queue->ap_dev, zq->online);
return -EAGAIN;
}
- if (zq->zcard->user_space_type == ZCRYPT_CEX2A)
- BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
- else
- BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
+ BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE);
data = reply->msg + t80h->len - outputdatalength;
if (copy_to_user(outputdata, data, outputdatalength))
return -EFAULT;
return 0;
}
-static int convert_response_cex2a(struct zcrypt_queue *zq,
- struct ap_message *reply,
- char __user *outputdata,
- unsigned int outputdatalength)
+static int convert_response(struct zcrypt_queue *zq,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
{
/* Response type byte is the second byte in the response. */
unsigned char rtype = ((unsigned char *)reply->msg)[1];
@@ -414,9 +408,9 @@ static int convert_response_cex2a(struct zcrypt_queue *zq,
* @msg: pointer to the AP message
* @reply: pointer to the AP reply message
*/
-static void zcrypt_cex2a_receive(struct ap_queue *aq,
- struct ap_message *msg,
- struct ap_message *reply)
+static void zcrypt_msgtype50_receive(struct ap_queue *aq,
+ struct ap_message *msg,
+ struct ap_message *reply)
{
static struct error_hdr error_reply = {
.type = TYPE82_RSP_CODE,
@@ -456,19 +450,18 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
* CEXxA device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
-static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
- struct ica_rsa_modexpo *mex,
- struct ap_message *ap_msg)
+static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
+ struct ica_rsa_modexpo *mex,
+ struct ap_message *ap_msg)
{
struct completion work;
int rc;
- ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
- MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+ ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
- ap_msg->receive = zcrypt_cex2a_receive;
+ ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg->private = &work;
@@ -483,9 +476,9 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_cex2a(zq, ap_msg,
- mex->outputdata,
- mex->outputdatalength);
+ rc = convert_response(zq, ap_msg,
+ mex->outputdata,
+ mex->outputdatalength);
} else {
/* Signal pending. */
ap_cancel_message(zq->queue, ap_msg);
@@ -507,19 +500,18 @@ out:
* CEXxA device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
-static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
- struct ica_rsa_modexpo_crt *crt,
- struct ap_message *ap_msg)
+static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
+ struct ica_rsa_modexpo_crt *crt,
+ struct ap_message *ap_msg)
{
struct completion work;
int rc;
- ap_msg->bufsize = (zq->zcard->user_space_type == ZCRYPT_CEX2A) ?
- MSGTYPE50_CRB2_MAX_MSG_SIZE : MSGTYPE50_CRB3_MAX_MSG_SIZE;
+ ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
if (!ap_msg->msg)
return -ENOMEM;
- ap_msg->receive = zcrypt_cex2a_receive;
+ ap_msg->receive = zcrypt_msgtype50_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg->private = &work;
@@ -534,9 +526,9 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
if (rc == 0) {
rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_cex2a(zq, ap_msg,
- crt->outputdata,
- crt->outputdatalength);
+ rc = convert_response(zq, ap_msg,
+ crt->outputdata,
+ crt->outputdatalength);
} else {
/* Signal pending. */
ap_cancel_message(zq->queue, ap_msg);
@@ -555,8 +547,8 @@ out:
* The crypto operations for message type 50.
*/
static struct zcrypt_ops zcrypt_msgtype50_ops = {
- .rsa_modexpo = zcrypt_cex2a_modexpo,
- .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
+ .rsa_modexpo = zcrypt_msgtype50_modexpo,
+ .rsa_modexpo_crt = zcrypt_msgtype50_modexpo_crt,
.owner = THIS_MODULE,
.name = MSGTYPE50_NAME,
.variant = MSGTYPE50_VARIANT_DEFAULT,
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h
index eb49f06bed29..323e93b90b12 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.h
+++ b/drivers/s390/crypto/zcrypt_msgtype50.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright IBM Corp. 2001, 2012
+ * Copyright IBM Corp. 2001, 2023
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@@ -15,7 +15,6 @@
#define MSGTYPE50_NAME "zcrypt_msgtype50"
#define MSGTYPE50_VARIANT_DEFAULT 0
-#define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
#define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /* sizeof(struct type50_crb3_msg) */
#define MSGTYPE_ADJUSTMENT 0x08 /* type04 extension (not needed in type50) */
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index e668ff5eb384..3c53abbdc342 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright IBM Corp. 2001, 2022
+ * Copyright IBM Corp. 2001, 2023
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@@ -42,7 +42,7 @@ struct response_type {
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
- "Copyright IBM Corp. 2001, 2012");
+ "Copyright IBM Corp. 2001, 2023");
MODULE_LICENSE("GPL");
struct function_and_rules_block {
@@ -1348,14 +1348,6 @@ out:
/*
* The crypto operations for a CEXxC card.
*/
-static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
- .owner = THIS_MODULE,
- .name = MSGTYPE06_NAME,
- .variant = MSGTYPE06_VARIANT_NORNG,
- .rsa_modexpo = zcrypt_msgtype6_modexpo,
- .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
- .send_cprb = zcrypt_msgtype6_send_cprb,
-};
static struct zcrypt_ops zcrypt_msgtype6_ops = {
.owner = THIS_MODULE,
@@ -1378,14 +1370,12 @@ static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = {
void __init zcrypt_msgtype6_init(void)
{
- zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops);
zcrypt_msgtype_register(&zcrypt_msgtype6_ops);
zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops);
}
void __exit zcrypt_msgtype6_exit(void)
{
- zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops);
zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops);
zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops);
}
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 9c67b97faba2..74760c1a163b 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -5,12 +5,11 @@ menu "S/390 network device drivers"
config LCS
def_tristate m
prompt "Lan Channel Station Interface"
- depends on CCW && NETDEVICES && (ETHERNET || FDDI)
+ depends on CCW && NETDEVICES && ETHERNET
help
Select this option if you want to use LCS networking on IBM System z.
- This device driver supports FDDI (IEEE 802.7) and Ethernet.
To compile as a module, choose M. The module name is lcs.
- If you do not know what it is, it's safe to choose Y.
+ If you do not use LCS, choose N.
config CTCM
def_tristate m
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 9fd8e6f07a03..a1f2acd6fb8f 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -17,7 +17,6 @@
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/fddidevice.h>
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/igmp.h>
@@ -36,10 +35,6 @@
#include "lcs.h"
-#if !defined(CONFIG_ETHERNET) && !defined(CONFIG_FDDI)
-#error Cannot compile lcs.c without some net devices switched on.
-#endif
-
/*
* initialization string for output
*/
@@ -1601,19 +1596,11 @@ lcs_startlan_auto(struct lcs_card *card)
int rc;
LCS_DBF_TEXT(2, trace, "strtauto");
-#ifdef CONFIG_ETHERNET
card->lan_type = LCS_FRAME_TYPE_ENET;
rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);
if (rc == 0)
return 0;
-#endif
-#ifdef CONFIG_FDDI
- card->lan_type = LCS_FRAME_TYPE_FDDI;
- rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);
- if (rc == 0)
- return 0;
-#endif
return -EIO;
}
@@ -1806,22 +1793,16 @@ lcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
card->stats.rx_errors++;
return;
}
- /* What kind of frame is it? */
- if (lcs_hdr->type == LCS_FRAME_TYPE_CONTROL) {
- /* Control frame. */
+ if (lcs_hdr->type == LCS_FRAME_TYPE_CONTROL)
lcs_get_control(card, (struct lcs_cmd *) lcs_hdr);
- } else if (lcs_hdr->type == LCS_FRAME_TYPE_ENET ||
- lcs_hdr->type == LCS_FRAME_TYPE_TR ||
- lcs_hdr->type == LCS_FRAME_TYPE_FDDI) {
- /* Normal network packet. */
+ else if (lcs_hdr->type == LCS_FRAME_TYPE_ENET)
lcs_get_skb(card, (char *)(lcs_hdr + 1),
lcs_hdr->offset - offset -
sizeof(struct lcs_header));
- } else {
- /* Unknown frame type. */
- ; // FIXME: error message ?
- }
- /* Proceed to next frame. */
+ else
+ dev_info_once(&card->dev->dev,
+ "Unknown frame type %d\n",
+ lcs_hdr->type);
offset = lcs_hdr->offset;
lcs_hdr->offset = LCS_ILLEGAL_OFFSET;
lcs_hdr = (struct lcs_header *) (buffer->data + offset);
@@ -2140,18 +2121,10 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
goto netdev_out;
}
switch (card->lan_type) {
-#ifdef CONFIG_ETHERNET
case LCS_FRAME_TYPE_ENET:
card->lan_type_trans = eth_type_trans;
dev = alloc_etherdev(0);
break;
-#endif
-#ifdef CONFIG_FDDI
- case LCS_FRAME_TYPE_FDDI:
- card->lan_type_trans = fddi_type_trans;
- dev = alloc_fddidev(0);
- break;
-#endif
default:
LCS_DBF_TEXT(3, setup, "errinit");
pr_err(" Initialization failed\n");
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 711252e52d8e..95a86e0dfd77 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -209,54 +209,6 @@ raid_attr_ro_state(level);
raid_attr_ro_fn(resync);
raid_attr_ro_state_fn(state);
-static void raid_component_release(struct device *dev)
-{
- struct raid_component *rc =
- container_of(dev, struct raid_component, dev);
- dev_printk(KERN_ERR, rc->dev.parent, "COMPONENT RELEASE\n");
- put_device(rc->dev.parent);
- kfree(rc);
-}
-
-int raid_component_add(struct raid_template *r,struct device *raid_dev,
- struct device *component_dev)
-{
- struct device *cdev =
- attribute_container_find_class_device(&r->raid_attrs.ac,
- raid_dev);
- struct raid_component *rc;
- struct raid_data *rd = dev_get_drvdata(cdev);
- int err;
-
- rc = kzalloc(sizeof(*rc), GFP_KERNEL);
- if (!rc)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&rc->node);
- device_initialize(&rc->dev);
- rc->dev.release = raid_component_release;
- rc->dev.parent = get_device(component_dev);
- rc->num = rd->component_count++;
-
- dev_set_name(&rc->dev, "component-%d", rc->num);
- list_add_tail(&rc->node, &rd->component_list);
- rc->dev.class = &raid_class.class;
- err = device_add(&rc->dev);
- if (err)
- goto err_out;
-
- return 0;
-
-err_out:
- put_device(&rc->dev);
- list_del(&rc->node);
- rd->component_count--;
- put_device(component_dev);
- kfree(rc);
- return err;
-}
-EXPORT_SYMBOL(raid_component_add);
-
struct raid_template *
raid_class_attach(struct raid_function_template *ft)
{
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ad9afae49544..59176946ab56 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -300,11 +300,6 @@ void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd)
cmd->budget_token = -1;
}
-static void scsi_kick_queue(struct request_queue *q)
-{
- blk_mq_run_hw_queues(q, false);
-}
-
/*
* Kick the queue of SCSI device @sdev if @sdev != current_sdev. Called with
* interrupts disabled.
@@ -340,7 +335,8 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev)
* but in most cases, we will be first. Ideally, each LU on the
* target would get some limited time or requests on the target.
*/
- scsi_kick_queue(current_sdev->request_queue);
+ blk_mq_run_hw_queues(current_sdev->request_queue,
+ shost->queuecommand_may_block);
spin_lock_irqsave(shost->host_lock, flags);
if (!starget->starget_sdev_user)
@@ -427,7 +423,7 @@ static void scsi_starved_list_run(struct Scsi_Host *shost)
continue;
spin_unlock_irqrestore(shost->host_lock, flags);
- scsi_kick_queue(slq);
+ blk_mq_run_hw_queues(slq, false);
blk_put_queue(slq);
spin_lock_irqsave(shost->host_lock, flags);
@@ -452,8 +448,8 @@ static void scsi_run_queue(struct request_queue *q)
if (!list_empty(&sdev->host->starved_list))
scsi_starved_list_run(sdev->host);
+ /* Note: blk_mq_kick_requeue_list() runs the queue asynchronously. */
blk_mq_kick_requeue_list(q);
- blk_mq_run_hw_queues(q, false);
}
void scsi_requeue_run_queue(struct work_struct *work)
diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c
index e429ad23c396..4db3ba62fcd3 100644
--- a/drivers/scsi/snic/snic_disc.c
+++ b/drivers/scsi/snic/snic_disc.c
@@ -303,12 +303,11 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid)
"Snic Tgt: device_add, with err = %d\n",
ret);
- put_device(&tgt->dev);
put_device(&snic->shost->shost_gendev);
spin_lock_irqsave(snic->shost->host_lock, flags);
list_del(&tgt->list);
spin_unlock_irqrestore(snic->shost->host_lock, flags);
- kfree(tgt);
+ put_device(&tgt->dev);
tgt = NULL;
return tgt;
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index b3c226eb5292..58746e570d14 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -524,7 +524,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
* saved microcode information and put in the new.
*/
memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
- strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
+ strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes);
memcpy(qe_firmware_info.vtraps, firmware->vtraps,
sizeof(firmware->vtraps));
@@ -599,7 +599,7 @@ struct qe_firmware_info *qe_get_firmware_info(void)
/* Copy the data into qe_firmware_info*/
sprop = of_get_property(fw, "id", NULL);
if (sprop)
- strlcpy(qe_firmware_info.id, sprop,
+ strscpy(qe_firmware_info.id, sprop,
sizeof(qe_firmware_info.id));
of_property_read_u64(fw, "extended-modes",
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index cf78839b3f74..1cc2281cb370 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -3,6 +3,7 @@
#include <linux/acpi.h>
#include <linux/delay.h>
+#include <linux/irq.h>
#include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_registers.h>
@@ -25,6 +26,23 @@ static int sdw_get_id(struct sdw_bus *bus)
return 0;
}
+static int sdw_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct sdw_bus *bus = h->host_data;
+
+ irq_set_chip_data(virq, bus);
+ irq_set_chip(virq, &bus->irq_chip);
+ irq_set_nested_thread(virq, 1);
+ irq_set_noprobe(virq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops sdw_domain_ops = {
+ .map = sdw_irq_map,
+};
+
/**
* sdw_bus_master_add() - add a bus Master instance
* @bus: bus instance
@@ -151,6 +169,14 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
bus->params.curr_bank = SDW_BANK0;
bus->params.next_bank = SDW_BANK1;
+ bus->irq_chip.name = dev_name(bus->dev);
+ bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
+ &sdw_domain_ops, bus);
+ if (!bus->domain) {
+ dev_err(bus->dev, "Failed to add IRQ domain\n");
+ return -EINVAL;
+ }
+
return 0;
}
EXPORT_SYMBOL(sdw_bus_master_add);
@@ -187,6 +213,9 @@ static int sdw_delete_slave(struct device *dev, void *data)
void sdw_bus_master_delete(struct sdw_bus *bus)
{
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
+
+ irq_domain_remove(bus->domain);
+
sdw_master_device_del(bus);
sdw_bus_debugfs_exit(bus);
@@ -1725,6 +1754,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
struct device *dev = &slave->dev;
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
+ if (slave->prop.use_domain_irq && slave->irq)
+ handle_nested_irq(slave->irq);
+
if (drv->ops && drv->ops->interrupt_callback) {
slave_intr.sdca_cascade = sdca_cascade;
slave_intr.control_port = clear;
diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
index 1f43ee848eac..fafbc284e82d 100644
--- a/drivers/soundwire/bus_type.c
+++ b/drivers/soundwire/bus_type.c
@@ -122,6 +122,12 @@ static int sdw_drv_probe(struct device *dev)
if (drv->ops && drv->ops->read_prop)
drv->ops->read_prop(slave);
+ if (slave->prop.use_domain_irq) {
+ slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
+ if (!slave->irq)
+ dev_warn(dev, "Failed to map IRQ\n");
+ }
+
/* init the sysfs as we have properties now */
ret = sdw_slave_sysfs_init(slave);
if (ret < 0)
@@ -166,7 +172,13 @@ static int sdw_drv_remove(struct device *dev)
int ret = 0;
mutex_lock(&slave->sdw_dev_lock);
+
slave->probed = false;
+
+ if (slave->prop.use_domain_irq)
+ irq_dispose_mapping(irq_find_mapping(slave->bus->domain,
+ slave->dev_num));
+
mutex_unlock(&slave->sdw_dev_lock);
if (drv->remove)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8962b2557615..2c21d5b96fdc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -281,6 +281,13 @@ config SPI_COLDFIRE_QSPI
This enables support for the Coldfire QSPI controller in master
mode.
+config SPI_CS42L43
+ tristate "Cirrus Logic CS42L43 SPI controller"
+ depends on MFD_CS42L43 && PINCTRL_CS42L43
+ help
+ This enables support for the SPI controller inside the Cirrus Logic
+ CS42L43 audio codec.
+
config SPI_DAVINCI
tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
@@ -516,6 +523,32 @@ config SPI_LM70_LLP
which interfaces to an LM70 temperature sensor using
a parallel port.
+config SPI_LOONGSON_CORE
+ tristate
+ depends on LOONGARCH || COMPILE_TEST
+
+config SPI_LOONGSON_PCI
+ tristate "Loongson SPI Controller PCI Driver Support"
+ select SPI_LOONGSON_CORE
+ depends on PCI && (LOONGARCH || COMPILE_TEST)
+ help
+ This bus driver supports the Loongson SPI hardware controller in
+ the Loongson platforms and supports to use PCI framework to
+ register SPI device resources.
+ Say Y or M here if you want to use the SPI controller on
+ Loongson platform.
+
+config SPI_LOONGSON_PLATFORM
+ tristate "Loongson SPI Controller Platform Driver Support"
+ select SPI_LOONGSON_CORE
+ depends on OF && (LOONGARCH || COMPILE_TEST)
+ help
+ This bus driver supports the Loongson SPI hardware controller in
+ the Loongson platforms and supports to use DTS framework to
+ register SPI device resources.
+ Say Y or M here if you want to use the SPI controller on
+ Loongson platform.
+
config SPI_LP8841_RTC
tristate "ICP DAS LP-8841 SPI Controller for RTC"
depends on MACH_PXA27X_DT || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 080c2c1b3ec1..6af54842b9fa 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
+obj-$(CONFIG_SPI_CS42L43) += spi-cs42l43.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
obj-$(CONFIG_SPI_DLN2) += spi-dln2.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
@@ -71,6 +72,9 @@ obj-$(CONFIG_SPI_INTEL_PLATFORM) += spi-intel-platform.o
obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
+obj-$(CONFIG_SPI_LOONGSON_CORE) += spi-loongson-core.o
+obj-$(CONFIG_SPI_LOONGSON_PCI) += spi-loongson-pci.o
+obj-$(CONFIG_SPI_LOONGSON_PLATFORM) += spi-loongson-plat.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c
index fecead757a3c..5d9b246b6963 100644
--- a/drivers/spi/spi-amd.c
+++ b/drivers/spi/spi-amd.c
@@ -215,9 +215,9 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi)
}
}
-static int amd_spi_master_setup(struct spi_device *spi)
+static int amd_spi_host_setup(struct spi_device *spi)
{
- struct amd_spi *amd_spi = spi_master_get_devdata(spi->master);
+ struct amd_spi *amd_spi = spi_controller_get_devdata(spi->controller);
amd_spi_clear_fifo_ptr(amd_spi);
@@ -272,7 +272,7 @@ static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
}
static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
- struct spi_master *master,
+ struct spi_controller *host,
struct spi_message *message)
{
struct spi_transfer *xfer = NULL;
@@ -353,15 +353,15 @@ fin_msg:
return -ENODEV;
}
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return message->status;
}
-static int amd_spi_master_transfer(struct spi_master *master,
+static int amd_spi_host_transfer(struct spi_controller *host,
struct spi_message *msg)
{
- struct amd_spi *amd_spi = spi_master_get_devdata(master);
+ struct amd_spi *amd_spi = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
amd_spi_select_chip(amd_spi, spi_get_chipselect(spi, 0));
@@ -370,7 +370,7 @@ static int amd_spi_master_transfer(struct spi_master *master,
* Extract spi_transfers from the spi message and
* program the controller.
*/
- return amd_spi_fifo_xfer(amd_spi, master, msg);
+ return amd_spi_fifo_xfer(amd_spi, host, msg);
}
static size_t amd_spi_max_transfer_size(struct spi_device *spi)
@@ -381,16 +381,16 @@ static size_t amd_spi_max_transfer_size(struct spi_device *spi)
static int amd_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct amd_spi *amd_spi;
int err;
- /* Allocate storage for spi_master and driver private data */
- master = devm_spi_alloc_master(dev, sizeof(struct amd_spi));
- if (!master)
- return dev_err_probe(dev, -ENOMEM, "Error allocating SPI master\n");
+ /* Allocate storage for host and driver private data */
+ host = devm_spi_alloc_host(dev, sizeof(struct amd_spi));
+ if (!host)
+ return dev_err_probe(dev, -ENOMEM, "Error allocating SPI host\n");
- amd_spi = spi_master_get_devdata(master);
+ amd_spi = spi_controller_get_devdata(host);
amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(amd_spi->io_remap_addr))
return dev_err_probe(dev, PTR_ERR(amd_spi->io_remap_addr),
@@ -398,22 +398,22 @@ static int amd_spi_probe(struct platform_device *pdev)
dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
- amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev);
+ amd_spi->version = (uintptr_t) device_get_match_data(dev);
- /* Initialize the spi_master fields */
- master->bus_num = 0;
- master->num_chipselect = 4;
- master->mode_bits = 0;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->max_speed_hz = AMD_SPI_MAX_HZ;
- master->min_speed_hz = AMD_SPI_MIN_HZ;
- master->setup = amd_spi_master_setup;
- master->transfer_one_message = amd_spi_master_transfer;
- master->max_transfer_size = amd_spi_max_transfer_size;
- master->max_message_size = amd_spi_max_transfer_size;
+ /* Initialize the spi_controller fields */
+ host->bus_num = 0;
+ host->num_chipselect = 4;
+ host->mode_bits = 0;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->max_speed_hz = AMD_SPI_MAX_HZ;
+ host->min_speed_hz = AMD_SPI_MIN_HZ;
+ host->setup = amd_spi_host_setup;
+ host->transfer_one_message = amd_spi_host_transfer;
+ host->max_transfer_size = amd_spi_max_transfer_size;
+ host->max_message_size = amd_spi_max_transfer_size;
/* Register the controller with SPI framework */
- err = devm_spi_register_master(dev, master);
+ err = devm_spi_register_controller(dev, host);
if (err)
return dev_err_probe(dev, err, "error registering SPI controller\n");
diff --git a/drivers/spi/spi-amlogic-spifc-a1.c b/drivers/spi/spi-amlogic-spifc-a1.c
index 3c4224c38399..fadf6667cd51 100644
--- a/drivers/spi/spi-amlogic-spifc-a1.c
+++ b/drivers/spi/spi-amlogic-spifc-a1.c
@@ -72,7 +72,7 @@
#define SPIFC_A1_USER_DBUF_ADDR_REG 0x248
-#define SPIFC_A1_BUFFER_SIZE 512
+#define SPIFC_A1_BUFFER_SIZE 512U
#define SPIFC_A1_MAX_HZ 200000000
#define SPIFC_A1_MIN_HZ 1000000
@@ -107,6 +107,7 @@ struct amlogic_spifc_a1 {
struct clk *clk;
struct device *dev;
void __iomem *base;
+ u32 curr_speed_hz;
};
static int amlogic_spifc_a1_request(struct amlogic_spifc_a1 *spifc, bool read)
@@ -235,66 +236,68 @@ static int amlogic_spifc_a1_write(struct amlogic_spifc_a1 *spifc,
return amlogic_spifc_a1_request(spifc, false);
}
-static int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
- const struct spi_mem_op *op)
+static int amlogic_spifc_a1_set_freq(struct amlogic_spifc_a1 *spifc, u32 freq)
{
- struct amlogic_spifc_a1 *spifc =
- spi_controller_get_devdata(mem->spi->controller);
- size_t off, nbytes = op->data.nbytes;
- u32 cmd_cfg, addr_cfg, dummy_cfg, dmode;
int ret;
- amlogic_spifc_a1_user_init(spifc);
-
- cmd_cfg = SPIFC_A1_USER_CMD(op);
- amlogic_spifc_a1_set_cmd(spifc, cmd_cfg);
+ if (freq == spifc->curr_speed_hz)
+ return 0;
- if (op->addr.nbytes) {
- addr_cfg = SPIFC_A1_USER_ADDR(op);
- amlogic_spifc_a1_set_addr(spifc, op->addr.val, addr_cfg);
- }
+ ret = clk_set_rate(spifc->clk, freq);
+ if (ret)
+ return ret;
- if (op->dummy.nbytes) {
- dummy_cfg = SPIFC_A1_USER_DUMMY(op);
- amlogic_spifc_a1_set_dummy(spifc, dummy_cfg);
- }
+ spifc->curr_speed_hz = freq;
+ return 0;
+}
- if (!op->data.nbytes)
- return amlogic_spifc_a1_request(spifc, false);
+static int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct amlogic_spifc_a1 *spifc =
+ spi_controller_get_devdata(mem->spi->controller);
+ size_t data_size = op->data.nbytes;
+ int ret;
- dmode = ilog2(op->data.buswidth);
- off = 0;
+ ret = amlogic_spifc_a1_set_freq(spifc, mem->spi->max_speed_hz);
+ if (ret)
+ return ret;
- do {
- size_t block_size = min_t(size_t, nbytes, SPIFC_A1_BUFFER_SIZE);
+ amlogic_spifc_a1_user_init(spifc);
+ amlogic_spifc_a1_set_cmd(spifc, SPIFC_A1_USER_CMD(op));
- amlogic_spifc_a1_set_cmd(spifc, cmd_cfg);
+ if (op->addr.nbytes)
+ amlogic_spifc_a1_set_addr(spifc, op->addr.val,
+ SPIFC_A1_USER_ADDR(op));
- if (op->addr.nbytes)
- amlogic_spifc_a1_set_addr(spifc, op->addr.val + off,
- addr_cfg);
+ if (op->dummy.nbytes)
+ amlogic_spifc_a1_set_dummy(spifc, SPIFC_A1_USER_DUMMY(op));
- if (op->dummy.nbytes)
- amlogic_spifc_a1_set_dummy(spifc, dummy_cfg);
+ if (data_size) {
+ u32 mode = ilog2(op->data.buswidth);
writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
if (op->data.dir == SPI_MEM_DATA_IN)
- ret = amlogic_spifc_a1_read(spifc,
- op->data.buf.in + off,
- block_size, dmode);
+ ret = amlogic_spifc_a1_read(spifc, op->data.buf.in,
+ data_size, mode);
else
- ret = amlogic_spifc_a1_write(spifc,
- op->data.buf.out + off,
- block_size, dmode);
-
- nbytes -= block_size;
- off += block_size;
- } while (nbytes != 0 && !ret);
+ ret = amlogic_spifc_a1_write(spifc, op->data.buf.out,
+ data_size, mode);
+ } else {
+ ret = amlogic_spifc_a1_request(spifc, false);
+ }
return ret;
}
+static int amlogic_spifc_a1_adjust_op_size(struct spi_mem *mem,
+ struct spi_mem_op *op)
+{
+ op->data.nbytes = min(op->data.nbytes, SPIFC_A1_BUFFER_SIZE);
+ return 0;
+}
+
static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
{
u32 regv;
@@ -314,6 +317,7 @@ static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
.exec_op = amlogic_spifc_a1_exec_op,
+ .adjust_op_size = amlogic_spifc_a1_adjust_op_size,
};
static int amlogic_spifc_a1_probe(struct platform_device *pdev)
@@ -322,7 +326,7 @@ static int amlogic_spifc_a1_probe(struct platform_device *pdev)
struct amlogic_spifc_a1 *spifc;
int ret;
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*spifc));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*spifc));
if (!ctrl)
return -ENOMEM;
diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c
index 9dcada8c4cb9..58b98cea31d9 100644
--- a/drivers/spi/spi-ar934x.c
+++ b/drivers/spi/spi-ar934x.c
@@ -14,7 +14,8 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#define DRIVER_NAME "spi-ar934x"
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index a7fb7c94e70e..0103ac0158c0 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -17,8 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/spi/spi.h>
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index e75b0d51f06a..21b0fa646c7d 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -295,7 +295,7 @@ static const struct aspeed_spi_data ast2400_spi_data;
static int do_aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(mem->spi, 0)];
u32 addr_mode, addr_mode_backup;
u32 ctl_val;
@@ -374,7 +374,7 @@ static int aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static const char *aspeed_spi_get_name(struct spi_mem *mem)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = aspi->dev;
return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
@@ -553,7 +553,7 @@ static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip);
static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
struct spi_mem_op *op = &desc->info.op_tmpl;
u32 ctl_val;
@@ -620,7 +620,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offset, size_t len, void *buf)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
/* Switch to USER command mode if mapping window is too small */
@@ -669,7 +669,7 @@ static void aspeed_spi_chip_enable(struct aspeed_spi *aspi, unsigned int cs, boo
static int aspeed_spi_setup(struct spi_device *spi)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
const struct aspeed_spi_data *data = aspi->data;
unsigned int cs = spi_get_chipselect(spi, 0);
struct aspeed_spi_chip *chip = &aspi->chips[cs];
@@ -697,7 +697,7 @@ static int aspeed_spi_setup(struct spi_device *spi)
static void aspeed_spi_cleanup(struct spi_device *spi)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
unsigned int cs = spi_get_chipselect(spi, 0);
aspeed_spi_chip_enable(aspi, cs, false);
@@ -726,7 +726,7 @@ static int aspeed_spi_probe(struct platform_device *pdev)
if (!data)
return -ENODEV;
- ctlr = devm_spi_alloc_master(dev, sizeof(*aspi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*aspi));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
index 7854d9790fe9..b11d0f993cc7 100644
--- a/drivers/spi/spi-at91-usart.c
+++ b/drivers/spi/spi-at91-usart.c
@@ -13,7 +13,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -486,10 +485,7 @@ static int at91_usart_gpio_setup(struct platform_device *pdev)
cs_gpios = devm_gpiod_get_array_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
- if (IS_ERR(cs_gpios))
- return PTR_ERR(cs_gpios);
-
- return 0;
+ return PTR_ERR_OR_ZERO(cs_gpios);
}
static int at91_usart_spi_probe(struct platform_device *pdev)
@@ -527,7 +523,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
controller->dev.of_node = pdev->dev.parent->of_node;
controller->bits_per_word_mask = SPI_BPW_MASK(8);
controller->setup = at91_usart_spi_setup;
- controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+ controller->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
controller->transfer_one = at91_usart_spi_transfer_one;
controller->prepare_message = at91_usart_spi_prepare_message;
controller->unprepare_message = at91_usart_spi_unprepare_message;
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index d3dd21386f12..1b6d977d111c 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -185,7 +185,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
host->use_gpio_descriptors = true;
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- host->flags = SPI_MASTER_GPIO_SS;
+ host->flags = SPI_CONTROLLER_GPIO_SS;
host->num_chipselect = 3;
host->mem_ops = &ath79_mem_ops;
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 152cd6773403..6aa8adbe4170 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1450,10 +1450,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
/* Select default pin state */
pinctrl_pm_select_default_state(&pdev->dev);
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs)
- return -ENXIO;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1475,8 +1471,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
host->bus_num = pdev->id;
host->num_chipselect = 4;
host->setup = atmel_spi_setup;
- host->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
- SPI_MASTER_GPIO_SS);
+ host->flags = (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX |
+ SPI_CONTROLLER_GPIO_SS);
host->transfer_one = atmel_spi_one_transfer;
host->set_cs = atmel_spi_set_cs;
host->cleanup = atmel_spi_cleanup;
@@ -1490,7 +1486,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
spin_lock_init(&as->lock);
as->pdev = pdev;
- as->regs = devm_ioremap_resource(&pdev->dev, regs);
+ as->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(as->regs)) {
ret = PTR_ERR(as->regs);
goto out_unmap_regs;
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 0b57e6afce0f..1011b1a8f241 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -54,7 +54,7 @@ struct au1550_spi {
int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
irqreturn_t (*irq_callback)(struct au1550_spi *hw);
- struct completion master_done;
+ struct completion host_done;
unsigned int usedma;
u32 dma_tx_id;
@@ -66,7 +66,7 @@ struct au1550_spi {
unsigned int dma_rx_tmpbuf_size;
u32 dma_rx_tmpbuf_addr;
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
struct au1550_spi_info *pdata;
struct resource *ioarea;
@@ -159,7 +159,7 @@ static void au1550_spi_reset_fifos(struct au1550_spi *hw)
*/
static void au1550_spi_chipsel(struct spi_device *spi, int value)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
u32 cfg, stat;
@@ -219,7 +219,7 @@ static void au1550_spi_chipsel(struct spi_device *spi, int value)
static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
unsigned int bpw, hz;
u32 cfg, stat;
@@ -272,7 +272,7 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
* no reliable way how to recognize that spi transfer is done
* dma complete callbacks are called before real spi transfer is finished
* and if only tx dma channel is set up (and rx fifo overflow event masked)
- * spi master done event irq is not generated unless rx fifo is empty (emptied)
+ * spi host done event irq is not generated unless rx fifo is empty (emptied)
* so we need rx tmp buffer to use for rx dma if user does not provide one
*/
static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned int size)
@@ -303,7 +303,7 @@ static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw)
static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
dma_addr_t dma_tx_addr;
dma_addr_t dma_rx_addr;
u32 res;
@@ -387,7 +387,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->regs->psc_spipcr = PSC_SPIPCR_MS;
wmb(); /* drain writebuffer */
- wait_for_completion(&hw->master_done);
+ wait_for_completion(&hw->host_done);
au1xxx_dbdma_stop(hw->dma_tx_ch);
au1xxx_dbdma_stop(hw->dma_rx_ch);
@@ -449,7 +449,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
"dma transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
- complete(&hw->master_done);
+ complete(&hw->host_done);
return IRQ_HANDLED;
}
@@ -458,7 +458,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
au1550_spi_mask_ack_all(hw);
hw->rx_count = hw->len;
hw->tx_count = hw->len;
- complete(&hw->master_done);
+ complete(&hw->host_done);
}
return IRQ_HANDLED;
}
@@ -502,7 +502,7 @@ AU1550_SPI_TX_WORD(32, 0xffffff)
static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
u32 stat, mask;
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -537,7 +537,7 @@ static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->regs->psc_spipcr = PSC_SPIPCR_MS;
wmb(); /* drain writebuffer */
- wait_for_completion(&hw->master_done);
+ wait_for_completion(&hw->host_done);
return min(hw->rx_count, hw->tx_count);
}
@@ -568,7 +568,7 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
dev_err(hw->dev,
"pio transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
- complete(&hw->master_done);
+ complete(&hw->host_done);
return IRQ_HANDLED;
}
@@ -605,11 +605,11 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
/*
* Restart the SPI transmission in case of a transmit underflow.
* This seems to work despite the notes in the Au1550 data book
- * of Figure 8-4 with flowchart for SPI master operation:
+ * of Figure 8-4 with flowchart for SPI host operation:
*
* """Note 1: An XFR Error Interrupt occurs, unless masked,
* for any of the following events: Tx FIFO Underflow,
- * Rx FIFO Overflow, or Multiple-master Error
+ * Rx FIFO Overflow, or Multiple-host Error
* Note 2: In case of a Tx Underflow Error, all zeroes are
* transmitted."""
*
@@ -627,14 +627,14 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
if (hw->rx_count >= hw->len) {
/* transfer completed successfully */
au1550_spi_mask_ack_all(hw);
- complete(&hw->master_done);
+ complete(&hw->host_done);
}
return IRQ_HANDLED;
}
static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
return hw->txrx_bufs(spi, t);
}
@@ -723,24 +723,24 @@ static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
static int au1550_spi_probe(struct platform_device *pdev)
{
struct au1550_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *r;
int err = 0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));
- if (master == NULL) {
- dev_err(&pdev->dev, "No memory for spi_master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct au1550_spi));
+ if (host == NULL) {
+ dev_err(&pdev->dev, "No memory for spi_controller\n");
err = -ENOMEM;
goto err_nomem;
}
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
- hw->master = master;
+ hw->host = host;
hw->pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
@@ -798,9 +798,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hw);
- init_completion(&hw->master_done);
+ init_completion(&hw->host_done);
- hw->bitbang.master = hw->master;
+ hw->bitbang.master = hw->host;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
@@ -858,8 +858,8 @@ static int au1550_spi_probe(struct platform_device *pdev)
goto err_no_irq;
}
- master->bus_num = pdev->id;
- master->num_chipselect = hw->pdata->num_chipselect;
+ host->bus_num = pdev->id;
+ host->num_chipselect = hw->pdata->num_chipselect;
/*
* precompute valid range for spi freq - from au1550 datasheet:
@@ -874,8 +874,8 @@ static int au1550_spi_probe(struct platform_device *pdev)
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
- master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
- master->min_speed_hz =
+ host->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+ host->min_speed_hz =
hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
@@ -883,13 +883,13 @@ static int au1550_spi_probe(struct platform_device *pdev)
err = spi_bitbang_start(&hw->bitbang);
if (err) {
- dev_err(&pdev->dev, "Failed to register SPI master\n");
+ dev_err(&pdev->dev, "Failed to register SPI host\n");
goto err_register;
}
dev_info(&pdev->dev,
- "spi master registered: bus_num=%d num_chipselect=%d\n",
- master->bus_num, master->num_chipselect);
+ "spi host registered: bus_num=%d num_chipselect=%d\n",
+ host->bus_num, host->num_chipselect);
return 0;
@@ -917,7 +917,7 @@ err_ioremap:
err_no_iores:
err_no_pdata:
- spi_master_put(hw->master);
+ spi_controller_put(hw->host);
err_nomem:
return err;
@@ -927,8 +927,8 @@ static void au1550_spi_remove(struct platform_device *pdev)
{
struct au1550_spi *hw = platform_get_drvdata(pdev);
- dev_info(&pdev->dev, "spi master remove: bus_num=%d\n",
- hw->master->bus_num);
+ dev_info(&pdev->dev, "spi host remove: bus_num=%d\n",
+ hw->host->bus_num);
spi_bitbang_stop(&hw->bitbang);
free_irq(hw->irq, hw);
@@ -941,7 +941,7 @@ static void au1550_spi_remove(struct platform_device *pdev)
au1xxx_dbdma_chan_free(hw->dma_tx_ch);
}
- spi_master_put(hw->master);
+ spi_controller_put(hw->host);
}
/* work with hotplug and coldplug */
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 89661f3b0d44..0258c9a72fdc 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -356,8 +356,8 @@ static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine)
static irqreturn_t spi_engine_irq(int irq, void *devid)
{
- struct spi_master *master = devid;
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ struct spi_controller *host = devid;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
unsigned int disable_int = 0;
unsigned int pending;
@@ -396,7 +396,7 @@ static irqreturn_t spi_engine_irq(int irq, void *devid)
msg->status = 0;
msg->actual_length = msg->frame_length;
spi_engine->msg = NULL;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
disable_int |= SPI_ENGINE_INT_SYNC;
}
}
@@ -412,11 +412,11 @@ static irqreturn_t spi_engine_irq(int irq, void *devid)
return IRQ_HANDLED;
}
-static int spi_engine_transfer_one_message(struct spi_master *master,
+static int spi_engine_transfer_one_message(struct spi_controller *host,
struct spi_message *msg)
{
struct spi_engine_program p_dry, *p;
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
unsigned int int_enable = 0;
unsigned long flags;
size_t size;
@@ -464,42 +464,42 @@ static int spi_engine_transfer_one_message(struct spi_master *master,
static int spi_engine_probe(struct platform_device *pdev)
{
struct spi_engine *spi_engine;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned int version;
int irq;
int ret;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENXIO;
+ if (irq < 0)
+ return irq;
spi_engine = devm_kzalloc(&pdev->dev, sizeof(*spi_engine), GFP_KERNEL);
if (!spi_engine)
return -ENOMEM;
- master = spi_alloc_master(&pdev->dev, 0);
- if (!master)
+ host = spi_alloc_host(&pdev->dev, 0);
+ if (!host)
return -ENOMEM;
- spi_master_set_devdata(master, spi_engine);
+ spi_controller_set_devdata(host, spi_engine);
spin_lock_init(&spi_engine->lock);
spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
if (IS_ERR(spi_engine->clk)) {
ret = PTR_ERR(spi_engine->clk);
- goto err_put_master;
+ goto err_put_host;
}
spi_engine->ref_clk = devm_clk_get(&pdev->dev, "spi_clk");
if (IS_ERR(spi_engine->ref_clk)) {
ret = PTR_ERR(spi_engine->ref_clk);
- goto err_put_master;
+ goto err_put_host;
}
ret = clk_prepare_enable(spi_engine->clk);
if (ret)
- goto err_put_master;
+ goto err_put_host;
ret = clk_prepare_enable(spi_engine->ref_clk);
if (ret)
@@ -525,46 +525,46 @@ static int spi_engine_probe(struct platform_device *pdev)
writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
- ret = request_irq(irq, spi_engine_irq, 0, pdev->name, master);
+ ret = request_irq(irq, spi_engine_irq, 0, pdev->name, host);
if (ret)
goto err_ref_clk_disable;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
- master->transfer_one_message = spi_engine_transfer_one_message;
- master->num_chipselect = 8;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
+ host->transfer_one_message = spi_engine_transfer_one_message;
+ host->num_chipselect = 8;
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret)
goto err_free_irq;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
return 0;
err_free_irq:
- free_irq(irq, master);
+ free_irq(irq, host);
err_ref_clk_disable:
clk_disable_unprepare(spi_engine->ref_clk);
err_clk_disable:
clk_disable_unprepare(spi_engine->clk);
-err_put_master:
- spi_master_put(master);
+err_put_host:
+ spi_controller_put(host);
return ret;
}
static void spi_engine_remove(struct platform_device *pdev)
{
- struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ struct spi_controller *host = spi_controller_get(platform_get_drvdata(pdev));
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
int irq = platform_get_irq(pdev, 0);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
- free_irq(irq, master);
+ free_irq(irq, host);
- spi_master_put(master);
+ spi_controller_put(host);
writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index d91dfbe47aa5..ef08fcac2f6d 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -220,7 +220,7 @@ struct qspi_trans {
struct bcm_qspi {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
u32 base_clk;
u32 max_speed_hz;
@@ -732,7 +732,7 @@ static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi,
struct qspi_trans *qt)
{
if (qt->mspi_last_trans &&
- spi_transfer_is_last(qspi->master, qt->trans))
+ spi_transfer_is_last(qspi->host, qt->trans))
return true;
else
return false;
@@ -979,7 +979,7 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
MSPI_CDRAM_BITSE_BIT);
- /* set 3wrire halfduplex mode data from master to slave */
+ /* set 3wrire halfduplex mode data from host to target */
if ((spi->mode & SPI_3WIRE) && tp.trans->tx_buf)
mspi_cdram |= MSPI_CDRAM_OUTP;
@@ -1035,7 +1035,7 @@ done:
static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
const struct spi_mem_op *op)
{
- struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
u32 addr = 0, len, rdlen, len_words, from = 0;
int ret = 0;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1118,11 +1118,11 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
return ret;
}
-static int bcm_qspi_transfer_one(struct spi_master *master,
+static int bcm_qspi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *trans)
{
- struct bcm_qspi *qspi = spi_master_get_devdata(master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(host);
int slots;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1150,8 +1150,8 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
const struct spi_mem_op *op)
{
- struct spi_master *master = spi->master;
- struct bcm_qspi *qspi = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct bcm_qspi *qspi = spi_controller_get_devdata(host);
struct spi_transfer t[2];
u8 cmd[6] = { };
int ret, i;
@@ -1171,7 +1171,7 @@ static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
t[0].tx_nbits = op->cmd.buswidth;
/* lets mspi know that this is not last transfer */
qspi->trans_pos.mspi_last_trans = false;
- ret = bcm_qspi_transfer_one(master, spi, &t[0]);
+ ret = bcm_qspi_transfer_one(host, spi, &t[0]);
/* rx */
qspi->trans_pos.mspi_last_trans = true;
@@ -1181,7 +1181,7 @@ static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
t[1].len = op->data.nbytes;
t[1].rx_nbits = op->data.buswidth;
t[1].bits_per_word = spi->bits_per_word;
- ret = bcm_qspi_transfer_one(master, spi, &t[1]);
+ ret = bcm_qspi_transfer_one(host, spi, &t[1]);
}
return ret;
@@ -1191,7 +1191,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct spi_device *spi = mem->spi;
- struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
int ret = 0;
bool mspi_read = false;
u32 addr = 0, len;
@@ -1486,7 +1486,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
const struct bcm_qspi_data *data;
struct device *dev = &pdev->dev;
struct bcm_qspi *qspi;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
int irq, ret = 0, num_ints = 0;
u32 val;
@@ -1504,13 +1504,13 @@ int bcm_qspi_probe(struct platform_device *pdev,
data = of_id->data;
- master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
- if (!master) {
- dev_err(dev, "error allocating spi_master\n");
+ host = devm_spi_alloc_host(dev, sizeof(struct bcm_qspi));
+ if (!host) {
+ dev_err(dev, "error allocating spi_controller\n");
return -ENOMEM;
}
- qspi = spi_master_get_devdata(master);
+ qspi = spi_controller_get_devdata(host);
qspi->clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(qspi->clk))
@@ -1520,23 +1520,23 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->trans_pos.trans = NULL;
qspi->trans_pos.byte = 0;
qspi->trans_pos.mspi_last_trans = true;
- qspi->master = master;
+ qspi->host = host;
- master->bus_num = -1;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_3WIRE;
- master->setup = bcm_qspi_setup;
- master->transfer_one = bcm_qspi_transfer_one;
- master->mem_ops = &bcm_qspi_mem_ops;
- master->cleanup = bcm_qspi_cleanup;
- master->dev.of_node = dev->of_node;
- master->num_chipselect = NUM_CHIPSELECT;
- master->use_gpio_descriptors = true;
+ host->setup = bcm_qspi_setup;
+ host->transfer_one = bcm_qspi_transfer_one;
+ host->mem_ops = &bcm_qspi_mem_ops;
+ host->cleanup = bcm_qspi_cleanup;
+ host->dev.of_node = dev->of_node;
+ host->num_chipselect = NUM_CHIPSELECT;
+ host->use_gpio_descriptors = true;
qspi->big_endian = of_device_is_big_endian(dev->of_node);
if (!of_property_read_u32(dev->of_node, "num-cs", &val))
- master->num_chipselect = val;
+ host->num_chipselect = val;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hif_mspi");
if (!res)
@@ -1659,9 +1659,9 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->xfer_mode.addrlen = -1;
qspi->xfer_mode.hp = -1;
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret < 0) {
- dev_err(dev, "can't register master\n");
+ dev_err(dev, "can't register host\n");
goto qspi_reg_err;
}
@@ -1682,7 +1682,7 @@ void bcm_qspi_remove(struct platform_device *pdev)
{
struct bcm_qspi *qspi = platform_get_drvdata(pdev);
- spi_unregister_master(qspi->master);
+ spi_unregister_controller(qspi->host);
bcm_qspi_hw_uninit(qspi);
clk_disable_unprepare(qspi->clk);
kfree(qspi->dev_ids);
@@ -1700,7 +1700,7 @@ static int __maybe_unused bcm_qspi_suspend(struct device *dev)
qspi->s3_strap_override_ctrl =
bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
- spi_master_suspend(qspi->master);
+ spi_controller_suspend(qspi->host);
clk_disable_unprepare(qspi->clk);
bcm_qspi_hw_uninit(qspi);
@@ -1721,7 +1721,7 @@ static int __maybe_unused bcm_qspi_resume(struct device *dev)
ret = clk_prepare_enable(qspi->clk);
if (!ret)
- spi_master_resume(qspi->master);
+ spi_controller_resume(qspi->host);
return ret;
}
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 3b253da98c05..e7bb2714678a 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -24,7 +24,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h> /* FIXME: using chip internals */
#include <linux/gpio/driver.h> /* FIXME: using chip internals */
@@ -105,7 +105,7 @@ MODULE_PARM_DESC(polling_limit_us,
* These are counted as well in @count_transfer_polling and
* @count_transfer_irq
* @count_transfer_dma: count how often dma mode is used
- * @slv: SPI slave currently selected
+ * @target: SPI target currently selected
* (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs)
* @tx_dma_active: whether a TX DMA descriptor is in progress
* @rx_dma_active: whether a RX DMA descriptor is in progress
@@ -135,7 +135,7 @@ struct bcm2835_spi {
u64 count_transfer_irq_after_polling;
u64 count_transfer_dma;
- struct bcm2835_spidev *slv;
+ struct bcm2835_spidev *target;
unsigned int tx_dma_active;
unsigned int rx_dma_active;
struct dma_async_tx_descriptor *fill_tx_desc;
@@ -143,14 +143,14 @@ struct bcm2835_spi {
};
/**
- * struct bcm2835_spidev - BCM2835 SPI slave
+ * struct bcm2835_spidev - BCM2835 SPI target
* @prepare_cs: precalculated CS register value for ->prepare_message()
- * (uses slave-specific clock polarity and phase settings)
+ * (uses target-specific clock polarity and phase settings)
* @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
* (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
* @clear_rx_addr: bus address of @clear_rx_cs
* @clear_rx_cs: precalculated CS register value to clear RX FIFO
- * (uses slave-specific clock polarity and phase settings)
+ * (uses target-specific clock polarity and phase settings)
*/
struct bcm2835_spidev {
u32 prepare_cs;
@@ -434,7 +434,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
/**
* bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
* @cs: CS register
@@ -596,7 +596,7 @@ out:
/**
* bcm2835_spi_dma_rx_done() - callback for DMA RX channel
- * @data: SPI master controller
+ * @data: SPI host controller
*
* Used for bidirectional and RX-only transfers.
*/
@@ -624,7 +624,7 @@ static void bcm2835_spi_dma_rx_done(void *data)
/**
* bcm2835_spi_dma_tx_done() - callback for DMA TX channel
- * @data: SPI master controller
+ * @data: SPI host controller
*
* Used for TX-only transfers.
*/
@@ -635,7 +635,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
/* busy-wait for TX FIFO to empty */
while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
- bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs);
+ bcm2835_wr(bs, BCM2835_SPI_CS, bs->target->clear_rx_cs);
bs->tx_dma_active = false;
smp_wmb();
@@ -655,10 +655,10 @@ static void bcm2835_spi_dma_tx_done(void *data)
/**
* bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
- * @slv: BCM2835 SPI slave
+ * @target: BCM2835 SPI target
* @is_tx: whether to submit DMA descriptor for TX or RX sglist
*
* Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr.
@@ -667,7 +667,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
struct spi_transfer *tfr,
struct bcm2835_spi *bs,
- struct bcm2835_spidev *slv,
+ struct bcm2835_spidev *target,
bool is_tx)
{
struct dma_chan *chan;
@@ -707,7 +707,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
} else if (!tfr->rx_buf) {
desc->callback = bcm2835_spi_dma_tx_done;
desc->callback_param = ctlr;
- bs->slv = slv;
+ bs->target = target;
}
/* submit it to DMA-engine */
@@ -718,9 +718,9 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
/**
* bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
- * @slv: BCM2835 SPI slave
+ * @target: BCM2835 SPI target
* @cs: CS register
*
* For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
@@ -732,7 +732,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
* clear the RX FIFO by setting the CLEAR_RX bit in the CS register.
*
* The CS register value is precalculated in bcm2835_spi_setup(). Normally
- * this is called only once, on slave registration. A DMA descriptor to write
+ * this is called only once, on target registration. A DMA descriptor to write
* this value is preallocated in bcm2835_dma_init(). All that's left to do
* when performing a TX-only transfer is to submit this descriptor to the RX
* DMA channel. Latency is thereby minimized. The descriptor does not
@@ -765,7 +765,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
*/
static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
struct spi_transfer *tfr,
- struct bcm2835_spidev *slv,
+ struct bcm2835_spidev *target,
u32 cs)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
@@ -783,7 +783,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
/* setup tx-DMA */
if (bs->tx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, target, true);
} else {
cookie = dmaengine_submit(bs->fill_tx_desc);
ret = dma_submit_error(cookie);
@@ -809,9 +809,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
* this saves 10us or more.
*/
if (bs->rx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, target, false);
} else {
- cookie = dmaengine_submit(slv->clear_rx_desc);
+ cookie = dmaengine_submit(target->clear_rx_desc);
ret = dma_submit_error(cookie);
}
if (ret) {
@@ -903,15 +903,15 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
/* get tx/rx dma */
ctlr->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(ctlr->dma_tx)) {
- dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
- ret = PTR_ERR(ctlr->dma_tx);
+ ret = dev_err_probe(dev, PTR_ERR(ctlr->dma_tx),
+ "no tx-dma configuration found - not using dma mode\n");
ctlr->dma_tx = NULL;
goto err;
}
ctlr->dma_rx = dma_request_chan(dev, "rx");
if (IS_ERR(ctlr->dma_rx)) {
- dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
- ret = PTR_ERR(ctlr->dma_rx);
+ ret = dev_err_probe(dev, PTR_ERR(ctlr->dma_rx),
+ "no rx-dma configuration found - not using dma mode\n");
ctlr->dma_rx = NULL;
goto err_release;
}
@@ -1050,10 +1050,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *tfr)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
unsigned long spi_hz, cdiv;
unsigned long hz_per_byte, byte_limit;
- u32 cs = slv->prepare_cs;
+ u32 cs = target->prepare_cs;
/* set clock */
spi_hz = tfr->speed_hz;
@@ -1101,7 +1101,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
* this 1 idle clock cycle pattern but runs the spi clock without gaps
*/
if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
- return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs);
+ return bcm2835_spi_transfer_one_dma(ctlr, tfr, target, cs);
/* run in interrupt-mode */
return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
@@ -1112,7 +1112,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
{
struct spi_device *spi = msg->spi;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
int ret;
if (ctlr->can_dma) {
@@ -1131,7 +1131,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
* Set up clock polarity before spi_transfer_one_message() asserts
* chip select to avoid a gratuitous clock signal edge.
*/
- bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs);
+ bcm2835_wr(bs, BCM2835_SPI_CS, target->prepare_cs);
return 0;
}
@@ -1163,51 +1163,51 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
static void bcm2835_spi_cleanup(struct spi_device *spi)
{
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
struct spi_controller *ctlr = spi->controller;
- if (slv->clear_rx_desc)
- dmaengine_desc_free(slv->clear_rx_desc);
+ if (target->clear_rx_desc)
+ dmaengine_desc_free(target->clear_rx_desc);
- if (slv->clear_rx_addr)
+ if (target->clear_rx_addr)
dma_unmap_single(ctlr->dma_rx->device->dev,
- slv->clear_rx_addr,
+ target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
- kfree(slv);
+ kfree(target);
}
static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct bcm2835_spi *bs,
- struct bcm2835_spidev *slv)
+ struct bcm2835_spidev *target)
{
int ret;
if (!ctlr->dma_rx)
return 0;
- slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
- &slv->clear_rx_cs,
- sizeof(u32),
- DMA_TO_DEVICE);
- if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) {
+ target->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
+ &target->clear_rx_cs,
+ sizeof(u32),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctlr->dma_rx->device->dev, target->clear_rx_addr)) {
dev_err(&spi->dev, "cannot map clear_rx_cs\n");
- slv->clear_rx_addr = 0;
+ target->clear_rx_addr = 0;
return -ENOMEM;
}
- slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
- slv->clear_rx_addr,
- sizeof(u32), 0,
- DMA_MEM_TO_DEV, 0);
- if (!slv->clear_rx_desc) {
+ target->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
+ target->clear_rx_addr,
+ sizeof(u32), 0,
+ DMA_MEM_TO_DEV, 0);
+ if (!target->clear_rx_desc) {
dev_err(&spi->dev, "cannot prepare clear_rx_desc\n");
return -ENOMEM;
}
- ret = dmaengine_desc_set_reuse(slv->clear_rx_desc);
+ ret = dmaengine_desc_set_reuse(target->clear_rx_desc);
if (ret) {
dev_err(&spi->dev, "cannot reuse clear_rx_desc\n");
return ret;
@@ -1220,26 +1220,26 @@ static int bcm2835_spi_setup(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
struct gpio_chip *chip;
int ret;
u32 cs;
- if (!slv) {
- slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()),
+ if (!target) {
+ target = kzalloc(ALIGN(sizeof(*target), dma_get_cache_alignment()),
GFP_KERNEL);
- if (!slv)
+ if (!target)
return -ENOMEM;
- spi_set_ctldata(spi, slv);
+ spi_set_ctldata(spi, target);
- ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv);
+ ret = bcm2835_spi_setup_dma(ctlr, spi, bs, target);
if (ret)
goto err_cleanup;
}
/*
- * Precalculate SPI slave's CS register value for ->prepare_message():
+ * Precalculate SPI target's CS register value for ->prepare_message():
* The driver always uses software-controlled GPIO chip select, hence
* set the hardware-controlled native chip select to an invalid value
* to prevent it from interfering.
@@ -1249,18 +1249,18 @@ static int bcm2835_spi_setup(struct spi_device *spi)
cs |= BCM2835_SPI_CS_CPOL;
if (spi->mode & SPI_CPHA)
cs |= BCM2835_SPI_CS_CPHA;
- slv->prepare_cs = cs;
+ target->prepare_cs = cs;
/*
- * Precalculate SPI slave's CS register value to clear RX FIFO
+ * Precalculate SPI target's CS register value to clear RX FIFO
* in case of a TX-only DMA transfer.
*/
if (ctlr->dma_rx) {
- slv->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
+ target->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
BCM2835_SPI_CS_DMAEN |
BCM2835_SPI_CS_CLEAR_RX;
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
- slv->clear_rx_addr,
+ target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
}
@@ -1328,7 +1328,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
struct bcm2835_spi *bs;
int err;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*bs));
if (!ctlr)
return -ENOMEM;
@@ -1360,10 +1360,12 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
ctlr->max_speed_hz = clk_get_rate(bs->clk) / 2;
bs->irq = platform_get_irq(pdev, 0);
- if (bs->irq <= 0)
- return bs->irq ? bs->irq : -ENODEV;
+ if (bs->irq < 0)
+ return bs->irq;
- clk_prepare_enable(bs->clk);
+ err = clk_prepare_enable(bs->clk);
+ if (err)
+ return err;
bs->clk_hz = clk_get_rate(bs->clk);
err = bcm2835_dma_init(ctlr, &pdev->dev, bs);
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 288f7b994b36..6d2a5d9f2498 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -20,9 +20,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
@@ -233,8 +231,8 @@ static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs)
static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* IRQ may be shared, so return if our interrupts are disabled */
if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) &
@@ -253,17 +251,17 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
/* and if rx_len is 0 then disable interrupts and wake up completion */
if (!bs->rx_len) {
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
return IRQ_HANDLED;
}
-static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
+static int __bcm2835aux_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* enable interrupts */
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] |
@@ -274,11 +272,11 @@ static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
return 1;
}
-static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* update statistics */
bs->count_transfer_irq++;
@@ -296,14 +294,14 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
}
/* now run the interrupt mode */
- return __bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+ return __bcm2835aux_spi_transfer_one_irq(host, spi, tfr);
}
-static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one_poll(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
unsigned long timeout;
/* update statistics */
@@ -330,7 +328,7 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
bs->tx_len, bs->rx_len);
/* forward to interrupt handler */
bs->count_transfer_irq_after_poll++;
- return __bcm2835aux_spi_transfer_one_irq(master,
+ return __bcm2835aux_spi_transfer_one_irq(host,
spi, tfr);
}
}
@@ -339,11 +337,11 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
return 0;
}
-static int bcm2835aux_spi_transfer_one(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
unsigned long spi_hz, clk_hz, speed;
unsigned long hz_per_byte, byte_limit;
@@ -394,17 +392,17 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
/* run in polling mode for short transfers */
if (tfr->len < byte_limit)
- return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
+ return bcm2835aux_spi_transfer_one_poll(host, spi, tfr);
/* run in interrupt mode for all others */
- return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+ return bcm2835aux_spi_transfer_one_irq(host, spi, tfr);
}
-static int bcm2835aux_spi_prepare_message(struct spi_master *master,
+static int bcm2835aux_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
@@ -424,20 +422,20 @@ static int bcm2835aux_spi_prepare_message(struct spi_master *master,
return 0;
}
-static int bcm2835aux_spi_unprepare_message(struct spi_master *master,
+static int bcm2835aux_spi_unprepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_spi_reset_hw(bs);
return 0;
}
-static void bcm2835aux_spi_handle_err(struct spi_master *master,
+static void bcm2835aux_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_spi_reset_hw(bs);
}
@@ -475,18 +473,18 @@ static int bcm2835aux_spi_setup(struct spi_device *spi)
static int bcm2835aux_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcm2835aux_spi *bs;
unsigned long clk_hz;
int err;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
- master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ platform_set_drvdata(pdev, host);
+ host->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
/* even though the driver never officially supported native CS
* allow a single native CS for legacy DT support purposes when
* no cs-gpio is configured.
@@ -498,16 +496,16 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
* * cs_delay_usec: cs is always deasserted one SCK cycle after
* a spi_transfer
*/
- master->num_chipselect = 1;
- master->setup = bcm2835aux_spi_setup;
- master->transfer_one = bcm2835aux_spi_transfer_one;
- master->handle_err = bcm2835aux_spi_handle_err;
- master->prepare_message = bcm2835aux_spi_prepare_message;
- master->unprepare_message = bcm2835aux_spi_unprepare_message;
- master->dev.of_node = pdev->dev.of_node;
- master->use_gpio_descriptors = true;
+ host->num_chipselect = 1;
+ host->setup = bcm2835aux_spi_setup;
+ host->transfer_one = bcm2835aux_spi_transfer_one;
+ host->handle_err = bcm2835aux_spi_handle_err;
+ host->prepare_message = bcm2835aux_spi_prepare_message;
+ host->unprepare_message = bcm2835aux_spi_unprepare_message;
+ host->dev.of_node = pdev->dev.of_node;
+ host->use_gpio_descriptors = true;
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
/* the main area */
bs->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -522,8 +520,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
}
bs->irq = platform_get_irq(pdev, 0);
- if (bs->irq <= 0)
- return bs->irq ? bs->irq : -ENODEV;
+ if (bs->irq < 0)
+ return bs->irq;
/* this also enables the HW block */
err = clk_prepare_enable(bs->clk);
@@ -546,15 +544,15 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, bs->irq,
bcm2835aux_spi_interrupt,
IRQF_SHARED,
- dev_name(&pdev->dev), master);
+ dev_name(&pdev->dev), host);
if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
goto out_clk_disable;
}
- err = spi_register_master(master);
+ err = spi_register_controller(host);
if (err) {
- dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
+ dev_err(&pdev->dev, "could not register SPI host: %d\n", err);
goto out_clk_disable;
}
@@ -569,12 +567,12 @@ out_clk_disable:
static void bcm2835aux_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_debugfs_remove(bs);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
bcm2835aux_spi_reset_hw(bs);
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index 9e218e143263..1ca857c2a4aa 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -149,7 +149,7 @@ static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->wait_mode);
}
@@ -158,7 +158,7 @@ static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -185,7 +185,7 @@ static ssize_t xfer_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->xfer_mode);
}
@@ -194,7 +194,7 @@ static ssize_t xfer_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -262,12 +262,12 @@ static int bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi *bs)
return rc;
}
-static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
+static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
struct spi_message *msg,
struct spi_transfer *t_prepend)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
bool tx_only = false;
struct spi_transfer *t;
@@ -348,7 +348,7 @@ static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
struct spi_transfer *t)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
const u8 *tx = t->tx_buf;
@@ -467,7 +467,7 @@ static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
int pending = t->len;
@@ -541,7 +541,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
static int bcm63xx_hsspi_setup(struct spi_device *spi)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = __raw_readl(bs->regs +
@@ -579,7 +579,7 @@ static int bcm63xx_hsspi_setup(struct spi_device *spi)
static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
struct spi_message *msg)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
int status = -EINVAL;
int dummy_cs;
bool keep_cs = false;
@@ -653,10 +653,10 @@ static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
return status;
}
-static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
+static int bcm63xx_hsspi_transfer_one(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
int status = -EINVAL;
bool prependable = false;
@@ -665,7 +665,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
mutex_lock(&bs->msg_mutex);
if (bs->xfer_mode != HSSPI_XFER_MODE_DUMMYCS)
- prependable = bcm63xx_prepare_prepend_transfer(master, msg, &t_prepend);
+ prependable = bcm63xx_prepare_prepend_transfer(host, msg, &t_prepend);
if (prependable) {
status = bcm63xx_hsspi_do_prepend_txrx(spi, &t_prepend);
@@ -681,7 +681,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
mutex_unlock(&bs->msg_mutex);
msg->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -723,7 +723,7 @@ static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
static int bcm63xx_hsspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcm63xx_hsspi *bs;
void __iomem *regs;
struct device *dev = &pdev->dev;
@@ -779,13 +779,13 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
}
}
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
+ host = spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host) {
ret = -ENOMEM;
goto out_disable_pll_clk;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
bs->pdev = pdev;
bs->clk = clk;
bs->pll_clk = pll_clk;
@@ -796,17 +796,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL);
if (!bs->prepend_buf) {
ret = -ENOMEM;
- goto out_put_master;
+ goto out_put_host;
}
mutex_init(&bs->bus_mutex);
mutex_init(&bs->msg_mutex);
init_completion(&bs->done);
- master->mem_ops = &bcm63xx_hsspi_mem_ops;
- master->dev.of_node = dev->of_node;
+ host->mem_ops = &bcm63xx_hsspi_mem_ops;
+ host->dev.of_node = dev->of_node;
if (!dev->of_node)
- master->bus_num = HSSPI_BUS_NUM;
+ host->bus_num = HSSPI_BUS_NUM;
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
if (num_cs > 8) {
@@ -814,18 +814,18 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
num_cs);
num_cs = HSSPI_SPI_MAX_CS;
}
- master->num_chipselect = num_cs;
- master->setup = bcm63xx_hsspi_setup;
- master->transfer_one_message = bcm63xx_hsspi_transfer_one;
- master->max_transfer_size = bcm63xx_hsspi_max_message_size;
- master->max_message_size = bcm63xx_hsspi_max_message_size;
+ host->num_chipselect = num_cs;
+ host->setup = bcm63xx_hsspi_setup;
+ host->transfer_one_message = bcm63xx_hsspi_transfer_one;
+ host->max_transfer_size = bcm63xx_hsspi_max_message_size;
+ host->max_message_size = bcm63xx_hsspi_max_message_size;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
SPI_RX_DUAL | SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->auto_runtime_pm = true;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
/* Initialize the hardware */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -844,7 +844,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
pdev->name, bs);
if (ret)
- goto out_put_master;
+ goto out_put_host;
}
pm_runtime_enable(&pdev->dev);
@@ -856,7 +856,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
}
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto out_sysgroup_disable;
@@ -868,8 +868,8 @@ out_sysgroup_disable:
sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
out_pm_disable:
pm_runtime_disable(&pdev->dev);
-out_put_master:
- spi_master_put(master);
+out_put_host:
+ spi_controller_put(host);
out_disable_pll_clk:
clk_disable_unprepare(pll_clk);
out_disable_clk:
@@ -880,8 +880,8 @@ out_disable_clk:
static void bcm63xx_hsspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -893,10 +893,10 @@ static void bcm63xx_hsspi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int bcm63xx_hsspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
@@ -905,8 +905,8 @@ static int bcm63xx_hsspi_suspend(struct device *dev)
static int bcm63xx_hsspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
@@ -921,7 +921,7 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
}
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 07b5b71b2352..aac41bd05f98 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -186,7 +186,7 @@ static const unsigned int bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
u8 clk_cfg, reg;
int i;
@@ -217,7 +217,7 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
unsigned int num_transfers)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
u16 msg_ctl;
u16 cmd;
unsigned int i, timeout = 0, prepend_len = 0, len = 0;
@@ -312,10 +312,10 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
return 0;
}
-static int bcm63xx_spi_transfer_one(struct spi_master *master,
+static int bcm63xx_spi_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
struct spi_transfer *t, *first = NULL;
struct spi_device *spi = m->spi;
int status = 0;
@@ -385,18 +385,18 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
}
exit:
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
-/* This driver supports single master mode only. Hence
+/* This driver supports single host mode only. Hence
* CMD_DONE is the only interrupt we care about
*/
static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = (struct spi_master *)dev_id;
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = (struct spi_controller *)dev_id;
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
u8 intr;
/* Read interupts and clear them immediately */
@@ -413,7 +413,7 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
static size_t bcm63xx_spi_max_length(struct spi_device *spi)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
return bs->fifo_size;
}
@@ -479,7 +479,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
const unsigned long *bcm63xx_spireg;
struct device *dev = &pdev->dev;
int irq, bus_num;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
struct bcm63xx_spi *bs;
int ret;
@@ -525,16 +525,16 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(reset))
return PTR_ERR(reset);
- master = spi_alloc_master(dev, sizeof(*bs));
- if (!master) {
+ host = spi_alloc_host(dev, sizeof(*bs));
+ if (!host) {
dev_err(dev, "out of memory\n");
return -ENOMEM;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
init_completion(&bs->done);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
bs->pdev = pdev;
bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
@@ -549,21 +549,21 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
bs->fifo_size = bs->reg_offsets[SPI_MSG_DATA_SIZE];
ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
- pdev->name, master);
+ pdev->name, host);
if (ret) {
dev_err(dev, "unable to request irq\n");
goto out_err;
}
- master->dev.of_node = dev->of_node;
- master->bus_num = bus_num;
- master->num_chipselect = num_cs;
- master->transfer_one_message = bcm63xx_spi_transfer_one;
- master->mode_bits = MODEBITS;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_transfer_size = bcm63xx_spi_max_length;
- master->max_message_size = bcm63xx_spi_max_length;
- master->auto_runtime_pm = true;
+ host->dev.of_node = dev->of_node;
+ host->bus_num = bus_num;
+ host->num_chipselect = num_cs;
+ host->transfer_one_message = bcm63xx_spi_transfer_one;
+ host->mode_bits = MODEBITS;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_transfer_size = bcm63xx_spi_max_length;
+ host->max_message_size = bcm63xx_spi_max_length;
+ host->auto_runtime_pm = true;
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
bs->tx_io = (u8 *)(bs->regs + bs->reg_offsets[SPI_MSG_DATA]);
@@ -585,7 +585,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
dev_err(dev, "spi register failed\n");
goto out_pm_disable;
@@ -601,14 +601,14 @@ out_pm_disable:
out_clk_disable:
clk_disable_unprepare(clk);
out_err:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void bcm63xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
/* reset spi block */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
@@ -619,10 +619,10 @@ static void bcm63xx_spi_remove(struct platform_device *pdev)
static int bcm63xx_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->clk);
@@ -631,15 +631,15 @@ static int bcm63xx_spi_suspend(struct device *dev)
static int bcm63xx_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
if (ret)
return ret;
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c
index ca1b4741e9f4..9f64afd8164e 100644
--- a/drivers/spi/spi-bcmbca-hsspi.c
+++ b/drivers/spi/spi-bcmbca-hsspi.c
@@ -127,7 +127,7 @@ static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->wait_mode);
}
@@ -136,7 +136,7 @@ static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -250,7 +250,7 @@ static int bcmbca_hsspi_wait_cmd(struct bcmbca_hsspi *bs, unsigned int cs)
static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
struct spi_message *msg)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
int pending = t->len;
@@ -328,7 +328,7 @@ static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
static int bcmbca_hsspi_setup(struct spi_device *spi)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = __raw_readl(bs->regs +
@@ -366,10 +366,10 @@ static int bcmbca_hsspi_setup(struct spi_device *spi)
return 0;
}
-static int bcmbca_hsspi_transfer_one(struct spi_master *master,
+static int bcmbca_hsspi_transfer_one(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
struct spi_transfer *t;
struct spi_device *spi = msg->spi;
int status = -EINVAL;
@@ -409,7 +409,7 @@ static int bcmbca_hsspi_transfer_one(struct spi_master *master,
bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
msg->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -431,7 +431,7 @@ static irqreturn_t bcmbca_hsspi_interrupt(int irq, void *dev_id)
static int bcmbca_hsspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcmbca_hsspi *bs;
struct resource *res_mem;
void __iomem *spim_ctrl;
@@ -487,13 +487,13 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
}
}
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
+ host = spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host) {
ret = -ENOMEM;
goto out_disable_pll_clk;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
bs->pdev = pdev;
bs->clk = clk;
bs->pll_clk = pll_clk;
@@ -507,9 +507,9 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
mutex_init(&bs->msg_mutex);
init_completion(&bs->done);
- master->dev.of_node = dev->of_node;
+ host->dev.of_node = dev->of_node;
if (!dev->of_node)
- master->bus_num = HSSPI_BUS_NUM;
+ host->bus_num = HSSPI_BUS_NUM;
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
if (num_cs > 8) {
@@ -517,15 +517,15 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
num_cs);
num_cs = HSSPI_SPI_MAX_CS;
}
- master->num_chipselect = num_cs;
- master->setup = bcmbca_hsspi_setup;
- master->transfer_one_message = bcmbca_hsspi_transfer_one;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
- SPI_RX_DUAL | SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->auto_runtime_pm = true;
+ host->num_chipselect = num_cs;
+ host->setup = bcmbca_hsspi_setup;
+ host->transfer_one_message = bcmbca_hsspi_transfer_one;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ SPI_RX_DUAL | SPI_TX_DUAL;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
/* Initialize the hardware */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -543,7 +543,7 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED,
pdev->name, bs);
if (ret)
- goto out_put_master;
+ goto out_put_host;
}
pm_runtime_enable(&pdev->dev);
@@ -555,7 +555,7 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
}
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto out_sysgroup_disable;
@@ -567,8 +567,8 @@ out_sysgroup_disable:
sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
out_pm_disable:
pm_runtime_disable(&pdev->dev);
-out_put_master:
- spi_master_put(master);
+out_put_host:
+ spi_controller_put(host);
out_disable_pll_clk:
clk_disable_unprepare(pll_clk);
out_disable_clk:
@@ -578,8 +578,8 @@ out_disable_clk:
static void bcmbca_hsspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -591,10 +591,10 @@ static void bcmbca_hsspi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int bcmbca_hsspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
@@ -603,8 +603,8 @@ static int bcmbca_hsspi_suspend(struct device *dev)
static int bcmbca_hsspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
@@ -619,7 +619,7 @@ static int bcmbca_hsspi_resume(struct device *dev)
}
}
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h
index 2dcbe166df63..0cab48b7875b 100644
--- a/drivers/spi/spi-bitbang-txrx.h
+++ b/drivers/spi/spi-bitbang-txrx.h
@@ -57,7 +57,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on trailing edge */
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
@@ -70,7 +70,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
/* sample MSB (from slave) on leading edge */
word <<= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi);
setsck(spi, cpol);
}
@@ -90,7 +90,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
/* setup MSB (to slave) on leading edge */
setsck(spi, !cpol);
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
@@ -103,7 +103,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
/* sample MSB (from slave) on trailing edge */
word <<= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi);
}
return word;
@@ -122,7 +122,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
for (; likely(bits); bits--) {
/* setup LSB (to slave) on trailing edge */
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & 1) != oldbit) {
setmosi(spi, word & 1);
oldbit = word & 1;
@@ -135,7 +135,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
/* sample LSB (from slave) on leading edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi) << rxbit;
setsck(spi, cpol);
}
@@ -156,7 +156,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
/* setup LSB (to slave) on leading edge */
setsck(spi, !cpol);
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & 1) != oldbit) {
setmosi(spi, word & 1);
oldbit = word & 1;
@@ -169,7 +169,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
/* sample LSB (from slave) on trailing edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi) << rxbit;
}
return word;
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index 27d0087f8688..ecd44016c197 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -248,7 +248,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
if (spi->mode & SPI_3WIRE) {
unsigned flags;
- flags = t->tx_buf ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
+ flags = t->tx_buf ? SPI_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX;
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags);
}
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, 0);
@@ -349,11 +349,11 @@ int spi_bitbang_init(struct spi_bitbang *bitbang)
/*
* We only need the chipselect callback if we are actually using it.
* If we just use GPIO descriptors, it is surplus. If the
- * SPI_MASTER_GPIO_SS flag is set, we always need to call the
+ * SPI_CONTROLLER_GPIO_SS flag is set, we always need to call the
* driver-specific chipselect routine.
*/
custom_cs = (!master->use_gpio_descriptors ||
- (master->flags & SPI_MASTER_GPIO_SS));
+ (master->flags & SPI_CONTROLLER_GPIO_SS));
if (custom_cs && !bitbang->chipselect)
return -EINVAL;
@@ -371,7 +371,7 @@ int spi_bitbang_init(struct spi_bitbang *bitbang)
master->transfer_one = spi_bitbang_transfer_one;
/*
* When using GPIO descriptors, the ->set_cs() callback doesn't even
- * get called unless SPI_MASTER_GPIO_SS is set.
+ * get called unless SPI_CONTROLLER_GPIO_SS is set.
*/
if (custom_cs)
master->set_cs = spi_bitbang_set_cs;
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index cceae816cebc..289b4454242a 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -178,7 +178,7 @@ static void butterfly_attach(struct parport *p)
struct pardevice *pd;
int status;
struct butterfly *pp;
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev = p->physport->dev;
struct pardev_cb butterfly_cb;
@@ -189,12 +189,12 @@ static void butterfly_attach(struct parport *p)
* and no way to be selective about what it binds to.
*/
- master = spi_alloc_master(dev, sizeof(*pp));
- if (!master) {
+ host = spi_alloc_host(dev, sizeof(*pp));
+ if (!host) {
status = -ENOMEM;
goto done;
}
- pp = spi_master_get_devdata(master);
+ pp = spi_controller_get_devdata(host);
/*
* SPI and bitbang hookup
@@ -202,10 +202,10 @@ static void butterfly_attach(struct parport *p)
* use default setup(), cleanup(), and transfer() methods; and
* only bother implementing mode 0. Start it later.
*/
- master->bus_num = 42;
- master->num_chipselect = 2;
+ host->bus_num = 42;
+ host->num_chipselect = 2;
- pp->bitbang.master = master;
+ pp->bitbang.master = host;
pp->bitbang.chipselect = butterfly_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
@@ -280,7 +280,7 @@ clean2:
clean1:
parport_unregister_device(pd);
clean0:
- spi_master_put(pp->bitbang.master);
+ spi_controller_put(host);
done:
pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
}
@@ -308,7 +308,7 @@ static void butterfly_detach(struct parport *p)
parport_release(pp->pd);
parport_unregister_device(pp->pd);
- spi_master_put(pp->bitbang.master);
+ spi_controller_put(pp->bitbang.master);
}
static struct parport_driver butterfly_driver = {
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index abf10f92415d..b50db71ac4cc 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -47,6 +46,12 @@
#define CQSPI_OP_WIDTH(part) ((part).nbytes ? ilog2((part).buswidth) : 0)
+enum {
+ CLK_QSPI_APB = 0,
+ CLK_QSPI_AHB,
+ CLK_QSPI_NUM,
+};
+
struct cqspi_st;
struct cqspi_flash_pdata {
@@ -62,8 +67,9 @@ struct cqspi_flash_pdata {
struct cqspi_st {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
+ struct clk *clks[CLK_QSPI_NUM];
unsigned int sclk;
void __iomem *iobase;
@@ -92,6 +98,8 @@ struct cqspi_st {
bool wr_completion;
bool slow_sram;
bool apb_ahb_hazard;
+
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
};
struct cqspi_driver_platdata {
@@ -100,6 +108,8 @@ struct cqspi_driver_platdata {
int (*indirect_read_dma)(struct cqspi_flash_pdata *f_pdata,
u_char *rxbuf, loff_t from_addr, size_t n_rx);
u32 (*get_dma_status)(struct cqspi_st *cqspi);
+ int (*jh7110_clk_init)(struct platform_device *pdev,
+ struct cqspi_st *cqspi);
};
/* Operation timeout value */
@@ -1369,7 +1379,7 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
struct cqspi_flash_pdata *f_pdata;
f_pdata = &cqspi->f_pdata[spi_get_chipselect(mem->spi, 0)];
@@ -1575,7 +1585,7 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
static const char *cqspi_get_name(struct spi_mem *mem)
{
- struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = &cqspi->pdev->dev;
return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
@@ -1630,31 +1640,77 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi)
return 0;
}
+static int cqspi_jh7110_clk_init(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+ static struct clk_bulk_data qspiclk[] = {
+ { .id = "apb" },
+ { .id = "ahb" },
+ };
+
+ int ret = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(qspiclk), qspiclk);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to get qspi clocks\n", __func__);
+ return ret;
+ }
+
+ cqspi->clks[CLK_QSPI_APB] = qspiclk[0].clk;
+ cqspi->clks[CLK_QSPI_AHB] = qspiclk[1].clk;
+
+ ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_APB]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_APB\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_AHB]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_AHB\n", __func__);
+ goto disable_apb_clk;
+ }
+
+ cqspi->is_jh7110 = true;
+
+ return 0;
+
+disable_apb_clk:
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+
+ return ret;
+}
+
+static void cqspi_jh7110_disable_clk(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+}
static int cqspi_probe(struct platform_device *pdev)
{
const struct cqspi_driver_platdata *ddata;
struct reset_control *rstc, *rstc_ocp, *rstc_ref;
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res_ahb;
struct cqspi_st *cqspi;
int ret;
int irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*cqspi));
- if (!master) {
- dev_err(&pdev->dev, "spi_alloc_master failed\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*cqspi));
+ if (!host) {
+ dev_err(&pdev->dev, "devm_spi_alloc_host failed\n");
return -ENOMEM;
}
- master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
- master->mem_ops = &cqspi_mem_ops;
- master->mem_caps = &cqspi_mem_caps;
- master->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
+ host->mem_ops = &cqspi_mem_ops;
+ host->mem_caps = &cqspi_mem_caps;
+ host->dev.of_node = pdev->dev.of_node;
- cqspi = spi_master_get_devdata(master);
+ cqspi = spi_controller_get_devdata(host);
cqspi->pdev = pdev;
- cqspi->master = master;
+ cqspi->host = host;
+ cqspi->is_jh7110 = false;
platform_set_drvdata(pdev, cqspi);
/* Obtain configuration from OF. */
@@ -1741,7 +1797,7 @@ static int cqspi_probe(struct platform_device *pdev)
reset_control_deassert(rstc_ocp);
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
- master->max_speed_hz = cqspi->master_ref_clk_hz;
+ host->max_speed_hz = cqspi->master_ref_clk_hz;
/* write completion is supported by default */
cqspi->wr_completion = true;
@@ -1752,7 +1808,7 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC,
cqspi->master_ref_clk_hz);
if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
- master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
+ host->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) {
cqspi->use_direct_mode = true;
cqspi->use_direct_mode_wr = true;
@@ -1766,6 +1822,12 @@ static int cqspi_probe(struct platform_device *pdev)
if (ddata->quirks & CQSPI_NEEDS_APB_AHB_HAZARD_WAR)
cqspi->apb_ahb_hazard = true;
+ if (ddata->jh7110_clk_init) {
+ ret = cqspi_jh7110_clk_init(pdev, cqspi);
+ if (ret)
+ goto probe_clk_failed;
+ }
+
if (of_device_is_compatible(pdev->dev.of_node,
"xlnx,versal-ospi-1.0")) {
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
@@ -1786,7 +1848,7 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->current_cs = -1;
cqspi->sclk = 0;
- master->num_chipselect = cqspi->num_chipselect;
+ host->num_chipselect = cqspi->num_chipselect;
ret = cqspi_setup_flash(cqspi);
if (ret) {
@@ -1800,7 +1862,7 @@ static int cqspi_probe(struct platform_device *pdev)
goto probe_setup_failed;
}
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret) {
dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret);
goto probe_setup_failed;
@@ -1822,7 +1884,7 @@ static void cqspi_remove(struct platform_device *pdev)
{
struct cqspi_st *cqspi = platform_get_drvdata(pdev);
- spi_unregister_master(cqspi->master);
+ spi_unregister_controller(cqspi->host);
cqspi_controller_enable(cqspi, 0);
if (cqspi->rx_chan)
@@ -1830,6 +1892,9 @@ static void cqspi_remove(struct platform_device *pdev)
clk_disable_unprepare(cqspi->clk);
+ if (cqspi->is_jh7110)
+ cqspi_jh7110_disable_clk(pdev, cqspi);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
@@ -1837,10 +1902,10 @@ static void cqspi_remove(struct platform_device *pdev)
static int cqspi_suspend(struct device *dev)
{
struct cqspi_st *cqspi = dev_get_drvdata(dev);
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
cqspi_controller_enable(cqspi, 0);
clk_disable_unprepare(cqspi->clk);
@@ -1851,7 +1916,7 @@ static int cqspi_suspend(struct device *dev)
static int cqspi_resume(struct device *dev)
{
struct cqspi_st *cqspi = dev_get_drvdata(dev);
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
clk_prepare_enable(cqspi->clk);
cqspi_wait_idle(cqspi);
@@ -1860,7 +1925,7 @@ static int cqspi_resume(struct device *dev)
cqspi->current_cs = -1;
cqspi->sclk = 0;
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
static DEFINE_SIMPLE_DEV_PM_OPS(cqspi_dev_pm_ops, cqspi_suspend, cqspi_resume);
@@ -1897,6 +1962,7 @@ static const struct cqspi_driver_platdata versal_ospi = {
static const struct cqspi_driver_platdata jh7110_qspi = {
.quirks = CQSPI_DISABLE_DAC_MODE,
+ .jh7110_clk_init = cqspi_jh7110_clk_init,
};
static const struct cqspi_driver_platdata pensando_cdns_qspi = {
diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c
index ce4a3145f065..b7e04b03be58 100644
--- a/drivers/spi/spi-cadence-xspi.c
+++ b/drivers/spi/spi-cadence-xspi.c
@@ -11,7 +11,6 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -420,7 +419,7 @@ static int cdns_xspi_mem_op_execute(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct cdns_xspi_dev *cdns_xspi =
- spi_master_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
int ret = 0;
ret = cdns_xspi_mem_op(cdns_xspi, mem, op);
@@ -431,7 +430,7 @@ static int cdns_xspi_mem_op_execute(struct spi_mem *mem,
static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
struct cdns_xspi_dev *cdns_xspi =
- spi_master_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
op->data.nbytes = clamp_val(op->data.nbytes, 0, cdns_xspi->sdmasize);
@@ -528,26 +527,26 @@ static void cdns_xspi_print_phy_config(struct cdns_xspi_dev *cdns_xspi)
static int cdns_xspi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master = NULL;
+ struct spi_controller *host = NULL;
struct cdns_xspi_dev *cdns_xspi = NULL;
struct resource *res;
int ret;
- master = devm_spi_alloc_master(dev, sizeof(*cdns_xspi));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*cdns_xspi));
+ if (!host)
return -ENOMEM;
- master->mode_bits = SPI_3WIRE | SPI_TX_DUAL | SPI_TX_QUAD |
+ host->mode_bits = SPI_3WIRE | SPI_TX_DUAL | SPI_TX_QUAD |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL | SPI_RX_OCTAL |
SPI_MODE_0 | SPI_MODE_3;
- master->mem_ops = &cadence_xspi_mem_ops;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = -1;
+ host->mem_ops = &cadence_xspi_mem_ops;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = -1;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- cdns_xspi = spi_master_get_devdata(master);
+ cdns_xspi = spi_controller_get_devdata(host);
cdns_xspi->pdev = pdev;
cdns_xspi->dev = &pdev->dev;
cdns_xspi->cur_cs = 0;
@@ -597,15 +596,15 @@ static int cdns_xspi_probe(struct platform_device *pdev)
return ret;
}
- master->num_chipselect = 1 << cdns_xspi->hw_num_banks;
+ host->num_chipselect = 1 << cdns_xspi->hw_num_banks;
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
- dev_err(dev, "Failed to register SPI master\n");
+ dev_err(dev, "Failed to register SPI host\n");
return ret;
}
- dev_info(dev, "Successfully registered SPI master\n");
+ dev_info(dev, "Successfully registered SPI host\n");
return 0;
}
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index de8fe3c5becb..12c940ba074a 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Cadence SPI controller driver (master and slave mode)
+ * Cadence SPI controller driver (host and target mode)
*
* Copyright (C) 2008 - 2014 Xilinx, Inc.
*
@@ -59,10 +59,10 @@
CDNS_SPI_CR_BAUD_DIV_4)
/*
- * SPI Configuration Register - Baud rate and slave select
+ * SPI Configuration Register - Baud rate and target select
*
* These are the values used in the calculation of baud rate divisor and
- * setting the slave select.
+ * setting the target select.
*/
#define CDNS_SPI_BAUD_DIV_MAX 7 /* Baud rate divisor maximum */
@@ -141,20 +141,20 @@ static inline void cdns_spi_write(struct cdns_spi *xspi, u32 offset, u32 val)
/**
* cdns_spi_init_hw - Initialize the hardware and configure the SPI controller
* @xspi: Pointer to the cdns_spi structure
- * @is_slave: Flag to indicate slave or master mode
- * * On reset the SPI controller is configured to slave or master mode.
- * In master mode baud rate divisor is set to 4, threshold value for TX FIFO
+ * @is_target: Flag to indicate target or host mode
+ * * On reset the SPI controller is configured to target or host mode.
+ * In host mode baud rate divisor is set to 4, threshold value for TX FIFO
* not full interrupt is set to 1 and size of the word to be transferred as 8 bit.
*
* This function initializes the SPI controller to disable and clear all the
- * interrupts, enable manual slave select and manual start, deselect all the
+ * interrupts, enable manual target select and manual start, deselect all the
* chip select lines, and enable the SPI controller.
*/
-static void cdns_spi_init_hw(struct cdns_spi *xspi, bool is_slave)
+static void cdns_spi_init_hw(struct cdns_spi *xspi, bool is_target)
{
u32 ctrl_reg = 0;
- if (!is_slave)
+ if (!is_target)
ctrl_reg |= CDNS_SPI_CR_DEFAULT;
if (xspi->is_decoded_cs)
@@ -185,10 +185,10 @@ static void cdns_spi_chipselect(struct spi_device *spi, bool is_high)
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
if (is_high) {
- /* Deselect the slave */
+ /* Deselect the target */
ctrl_reg |= CDNS_SPI_CR_SSCTRL;
} else {
- /* Select the slave */
+ /* Select the target */
ctrl_reg &= ~CDNS_SPI_CR_SSCTRL;
if (!(xspi->is_decoded_cs))
ctrl_reg |= ((~(CDNS_SPI_SS0 << spi_get_chipselect(spi, 0))) <<
@@ -227,7 +227,7 @@ static void cdns_spi_config_clock_mode(struct spi_device *spi)
/*
* Just writing the CR register does not seem to apply the clock
* setting changes. This is problematic when changing the clock
- * polarity as it will cause the SPI slave to see spurious clock
+ * polarity as it will cause the SPI target to see spurious clock
* transitions. To workaround the issue toggle the ER register.
*/
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
@@ -317,12 +317,6 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
xspi->rx_bytes -= nrx;
while (ntx || nrx) {
- /* When xspi in busy condition, bytes may send failed,
- * then spi control did't work thoroughly, add one byte delay
- */
- if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
- udelay(10);
-
if (ntx) {
if (xspi->txbuf)
cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
@@ -392,6 +386,11 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
if (xspi->tx_bytes) {
cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
} else {
+ /* Fixed delay due to controller limitation with
+ * RX_NEMPTY incorrect status
+ * Xilinx AR:65885 contains more details
+ */
+ udelay(10);
cdns_spi_process_fifo(xspi, 0, trans_cnt);
cdns_spi_write(xspi, CDNS_SPI_IDR,
CDNS_SPI_IXR_DEFAULT);
@@ -406,7 +405,7 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
static int cdns_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
- if (!spi_controller_is_slave(ctlr))
+ if (!spi_controller_is_target(ctlr))
cdns_spi_config_clock_mode(msg->spi);
return 0;
}
@@ -418,9 +417,9 @@ static int cdns_prepare_message(struct spi_controller *ctlr,
* @transfer: Pointer to the spi_transfer structure which provides
* information about next transfer parameters
*
- * This function in master mode fills the TX FIFO, starts the SPI transfer and
+ * This function in host mode fills the TX FIFO, starts the SPI transfer and
* returns a positive transfer count so that core will wait for completion.
- * This function in slave mode fills the TX FIFO and wait for transfer trigger.
+ * This function in target mode fills the TX FIFO and wait for transfer trigger.
*
* Return: Number of bytes transferred in the last transfer
*/
@@ -435,16 +434,22 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
xspi->tx_bytes = transfer->len;
xspi->rx_bytes = transfer->len;
- if (!spi_controller_is_slave(ctlr)) {
+ if (!spi_controller_is_target(ctlr)) {
cdns_spi_setup_transfer(spi, transfer);
} else {
/* Set TX empty threshold to half of FIFO depth
- * only if TX bytes are more than half FIFO depth.
+ * only if TX bytes are more than FIFO depth.
*/
if (xspi->tx_bytes > xspi->tx_fifo_depth)
cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
}
+ /* When xspi in busy condition, bytes may send failed,
+ * then spi control didn't work thoroughly, add one byte delay
+ */
+ if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
+ udelay(10);
+
cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
spi_transfer_delay_exec(transfer);
@@ -457,7 +462,7 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
* @ctlr: Pointer to the spi_controller structure which provides
* information about the controller.
*
- * This function enables SPI master controller.
+ * This function enables SPI host controller.
*
* Return: 0 always
*/
@@ -475,7 +480,7 @@ static int cdns_prepare_transfer_hardware(struct spi_controller *ctlr)
* @ctlr: Pointer to the spi_controller structure which provides
* information about the controller.
*
- * This function disables the SPI master controller when no slave selected.
+ * This function disables the SPI host controller when no target selected.
* This function flush out if any pending data in FIFO.
*
* Return: 0 always
@@ -486,15 +491,15 @@ static int cdns_unprepare_transfer_hardware(struct spi_controller *ctlr)
u32 ctrl_reg;
unsigned int cnt = xspi->tx_fifo_depth;
- if (spi_controller_is_slave(ctlr)) {
+ if (spi_controller_is_target(ctlr)) {
while (cnt--)
cdns_spi_read(xspi, CDNS_SPI_RXD);
}
- /* Disable the SPI if slave is deselected */
+ /* Disable the SPI if target is deselected */
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
ctrl_reg = (ctrl_reg & CDNS_SPI_CR_SSCTRL) >> CDNS_SPI_SS_SHIFT;
- if (ctrl_reg == CDNS_SPI_NOSS || spi_controller_is_slave(ctlr))
+ if (ctrl_reg == CDNS_SPI_NOSS || spi_controller_is_target(ctlr))
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
/* Reset to default */
@@ -521,14 +526,14 @@ static void cdns_spi_detect_fifo_depth(struct cdns_spi *xspi)
}
/**
- * cdns_slave_abort - Abort slave transfer
+ * cdns_target_abort - Abort target transfer
* @ctlr: Pointer to the spi_controller structure
*
- * This function abort slave transfer if there any transfer timeout.
+ * This function abort target transfer if there any transfer timeout.
*
* Return: 0 always
*/
-static int cdns_slave_abort(struct spi_controller *ctlr)
+static int cdns_target_abort(struct spi_controller *ctlr)
{
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
u32 intr_status;
@@ -555,13 +560,13 @@ static int cdns_spi_probe(struct platform_device *pdev)
struct spi_controller *ctlr;
struct cdns_spi *xspi;
u32 num_cs;
- bool slave;
+ bool target;
- slave = of_property_read_bool(pdev->dev.of_node, "spi-slave");
- if (slave)
- ctlr = spi_alloc_slave(&pdev->dev, sizeof(*xspi));
+ target = of_property_read_bool(pdev->dev.of_node, "spi-slave");
+ if (target)
+ ctlr = spi_alloc_target(&pdev->dev, sizeof(*xspi));
else
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xspi));
if (!ctlr)
return -ENOMEM;
@@ -589,7 +594,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto remove_ctlr;
}
- if (!spi_controller_is_slave(ctlr)) {
+ if (!spi_controller_is_target(ctlr)) {
xspi->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
if (IS_ERR(xspi->ref_clk)) {
dev_err(&pdev->dev, "ref_clk clock not found.\n");
@@ -624,11 +629,11 @@ static int cdns_spi_probe(struct platform_device *pdev)
cdns_spi_detect_fifo_depth(xspi);
/* SPI controller initializations */
- cdns_spi_init_hw(xspi, spi_controller_is_slave(ctlr));
+ cdns_spi_init_hw(xspi, spi_controller_is_target(ctlr));
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- ret = -ENXIO;
+ if (irq < 0) {
+ ret = irq;
goto clk_dis_all;
}
@@ -648,7 +653,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
- if (!spi_controller_is_slave(ctlr)) {
+ if (!spi_controller_is_target(ctlr)) {
ctlr->mode_bits |= SPI_CS_HIGH;
ctlr->set_cs = cdns_spi_chipselect;
ctlr->auto_runtime_pm = true;
@@ -660,7 +665,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
pm_runtime_put_autosuspend(&pdev->dev);
} else {
ctlr->mode_bits |= SPI_NO_CS;
- ctlr->slave_abort = cdns_slave_abort;
+ ctlr->target_abort = cdns_target_abort;
}
ret = spi_register_controller(ctlr);
if (ret) {
@@ -671,7 +676,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
return ret;
clk_dis_all:
- if (!spi_controller_is_slave(ctlr)) {
+ if (!spi_controller_is_target(ctlr)) {
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(xspi->ref_clk);
@@ -690,8 +695,6 @@ remove_ctlr:
* This function is called if a device is physically removed from the system or
* if the driver module is being unloaded. It frees all resources allocated to
* the device.
- *
- * Return: 0 on success and error value on error
*/
static void cdns_spi_remove(struct platform_device *pdev)
{
@@ -737,7 +740,7 @@ static int __maybe_unused cdns_spi_resume(struct device *dev)
struct spi_controller *ctlr = dev_get_drvdata(dev);
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
- cdns_spi_init_hw(xspi, spi_controller_is_slave(ctlr));
+ cdns_spi_init_hw(xspi, spi_controller_is_target(ctlr));
return spi_controller_resume(ctlr);
}
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
index 58060be33106..4511c3b31223 100644
--- a/drivers/spi/spi-cavium-octeon.c
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -19,15 +19,15 @@
static int octeon_spi_probe(struct platform_device *pdev)
{
void __iomem *reg_base;
- struct spi_master *master;
+ struct spi_controller *host;
struct octeon_spi *p;
int err = -ENOENT;
- master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct octeon_spi));
+ if (!host)
return -ENOMEM;
- p = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, master);
+ p = spi_controller_get_devdata(host);
+ platform_set_drvdata(pdev, host);
reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(reg_base)) {
@@ -43,21 +43,21 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->regs.tx = 0x10;
p->regs.data = 0x80;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPHA |
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPHA |
SPI_CPOL |
SPI_CS_HIGH |
SPI_LSB_FIRST |
SPI_3WIRE;
- master->transfer_one_message = octeon_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ host->transfer_one_message = octeon_spi_transfer_one_message;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
- master->dev.of_node = pdev->dev.of_node;
- err = devm_spi_register_master(&pdev->dev, master);
+ host->dev.of_node = pdev->dev.of_node;
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err) {
- dev_err(&pdev->dev, "register master failed: %d\n", err);
+ dev_err(&pdev->dev, "register host failed: %d\n", err);
goto fail;
}
@@ -65,14 +65,14 @@ static int octeon_spi_probe(struct platform_device *pdev)
return 0;
fail:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
static void octeon_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct octeon_spi *p = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct octeon_spi *p = spi_controller_get_devdata(host);
/* Clear the CSENA* and put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c
index 60c0d6934654..f7c378a5f1bc 100644
--- a/drivers/spi/spi-cavium-thunderx.c
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -20,15 +20,15 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct octeon_spi *p;
int ret;
- master = spi_alloc_master(dev, sizeof(struct octeon_spi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct octeon_spi));
+ if (!host)
return -ENOMEM;
- p = spi_master_get_devdata(master);
+ p = spi_controller_get_devdata(host);
ret = pcim_enable_device(pdev);
if (ret)
@@ -64,18 +64,18 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
p->sys_freq = SYS_FREQ_DEFAULT;
dev_info(dev, "Set system clock to %u\n", p->sys_freq);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
SPI_LSB_FIRST | SPI_3WIRE;
- master->transfer_one_message = octeon_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
- master->dev.of_node = pdev->dev.of_node;
+ host->transfer_one_message = octeon_spi_transfer_one_message;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ host->dev.of_node = pdev->dev.of_node;
- pci_set_drvdata(pdev, master);
+ pci_set_drvdata(pdev, host);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto error;
@@ -84,16 +84,16 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
error:
clk_disable_unprepare(p->clk);
pci_release_regions(pdev);
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void thunderx_spi_remove(struct pci_dev *pdev)
{
- struct spi_master *master = pci_get_drvdata(pdev);
+ struct spi_controller *host = pci_get_drvdata(pdev);
struct octeon_spi *p;
- p = spi_master_get_devdata(master);
+ p = spi_controller_get_devdata(host);
if (!p)
return;
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index c005ed26a3e1..5552ccd716fc 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -33,10 +33,10 @@ struct spi_clps711x_data {
int len;
};
-static int spi_clps711x_prepare_message(struct spi_master *master,
+static int spi_clps711x_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
/* Setup mode for transfer */
@@ -45,11 +45,11 @@ static int spi_clps711x_prepare_message(struct spi_master *master,
SYSCON3_ADCCKNSEN : 0);
}
-static int spi_clps711x_transfer_one(struct spi_master *master,
+static int spi_clps711x_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
u8 data;
clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz);
@@ -68,8 +68,8 @@ static int spi_clps711x_transfer_one(struct spi_master *master,
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
u8 data;
/* Handle RX */
@@ -83,7 +83,7 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
hw->syncio);
} else
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
@@ -92,26 +92,26 @@ static int spi_clps711x_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spi_clps711x_data *hw;
- struct spi_master *master;
+ struct spi_controller *host;
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*hw));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*hw));
+ if (!host)
return -ENOMEM;
- master->use_gpio_descriptors = true;
- master->bus_num = -1;
- master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
- master->dev.of_node = pdev->dev.of_node;
- master->prepare_message = spi_clps711x_prepare_message;
- master->transfer_one = spi_clps711x_transfer_one;
+ host->use_gpio_descriptors = true;
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->prepare_message = spi_clps711x_prepare_message;
+ host->transfer_one = spi_clps711x_transfer_one;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) {
@@ -138,16 +138,16 @@ static int spi_clps711x_probe(struct platform_device *pdev)
readl(hw->syncio);
ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
- dev_name(&pdev->dev), master);
+ dev_name(&pdev->dev), host);
if (ret)
goto err_out;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (!ret)
return 0;
err_out:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index b1bd8a6b5bf9..f0b630fe16c3 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -286,7 +286,7 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(spi->controller);
bool cs_high = spi->mode & SPI_CS_HIGH;
if (enable)
@@ -295,11 +295,11 @@ static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
mcfqspi_cs_deselect(mcfqspi, spi_get_chipselect(spi, 0), cs_high);
}
-static int mcfqspi_transfer_one(struct spi_master *master,
+static int mcfqspi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
u16 qmr = MCFQSPI_QMR_MSTR;
qmr |= t->bits_per_word << 10;
@@ -323,7 +323,7 @@ static int mcfqspi_transfer_one(struct spi_master *master,
static int mcfqspi_setup(struct spi_device *spi)
{
- mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
+ mcfqspi_cs_deselect(spi_controller_get_devdata(spi->controller),
spi_get_chipselect(spi, 0), spi->mode & SPI_CS_HIGH);
dev_dbg(&spi->dev,
@@ -337,7 +337,7 @@ static int mcfqspi_setup(struct spi_device *spi)
static int mcfqspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct mcfqspi *mcfqspi;
struct mcfqspi_platform_data *pdata;
int status;
@@ -353,13 +353,13 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
- if (master == NULL) {
- dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*mcfqspi));
+ if (host == NULL) {
+ dev_dbg(&pdev->dev, "spi_alloc_host failed\n");
return -ENOMEM;
}
- mcfqspi = spi_master_get_devdata(master);
+ mcfqspi = spi_controller_get_devdata(host);
mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mcfqspi->iobase)) {
@@ -381,53 +381,50 @@ static int mcfqspi_probe(struct platform_device *pdev)
goto fail0;
}
- mcfqspi->clk = devm_clk_get(&pdev->dev, "qspi_clk");
+ mcfqspi->clk = devm_clk_get_enabled(&pdev->dev, "qspi_clk");
if (IS_ERR(mcfqspi->clk)) {
dev_dbg(&pdev->dev, "clk_get failed\n");
status = PTR_ERR(mcfqspi->clk);
goto fail0;
}
- clk_prepare_enable(mcfqspi->clk);
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->num_chipselect;
+ host->bus_num = pdata->bus_num;
+ host->num_chipselect = pdata->num_chipselect;
mcfqspi->cs_control = pdata->cs_control;
status = mcfqspi_cs_setup(mcfqspi);
if (status) {
dev_dbg(&pdev->dev, "error initializing cs_control\n");
- goto fail1;
+ goto fail0;
}
init_waitqueue_head(&mcfqspi->waitq);
- master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
- master->setup = mcfqspi_setup;
- master->set_cs = mcfqspi_set_cs;
- master->transfer_one = mcfqspi_transfer_one;
- master->auto_runtime_pm = true;
+ host->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
+ host->setup = mcfqspi_setup;
+ host->set_cs = mcfqspi_set_cs;
+ host->transfer_one = mcfqspi_transfer_one;
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
pm_runtime_enable(&pdev->dev);
- status = devm_spi_register_master(&pdev->dev, master);
+ status = devm_spi_register_controller(&pdev->dev, host);
if (status) {
- dev_dbg(&pdev->dev, "spi_register_master failed\n");
- goto fail2;
+ dev_dbg(&pdev->dev, "devm_spi_register_controller failed\n");
+ goto fail1;
}
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
return 0;
-fail2:
+fail1:
pm_runtime_disable(&pdev->dev);
mcfqspi_cs_teardown(mcfqspi);
-fail1:
- clk_disable_unprepare(mcfqspi->clk);
fail0:
- spi_master_put(master);
+ spi_controller_put(host);
dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
@@ -436,8 +433,8 @@ fail0:
static void mcfqspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
@@ -450,11 +447,11 @@ static void mcfqspi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int mcfqspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -465,20 +462,20 @@ static int mcfqspi_suspend(struct device *dev)
static int mcfqspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_enable(mcfqspi->clk);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif
#ifdef CONFIG_PM
static int mcfqspi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_disable(mcfqspi->clk);
@@ -487,8 +484,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
static int mcfqspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_enable(mcfqspi->clk);
diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c
new file mode 100644
index 000000000000..453a9b37ce78
--- /dev/null
+++ b/drivers/spi/spi-cs42l43.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 SPI Controller Driver
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#define CS42L43_FIFO_SIZE 16
+#define CS42L43_SPI_ROOT_HZ (40 * HZ_PER_MHZ)
+#define CS42L43_SPI_MAX_LENGTH 65532
+
+enum cs42l43_spi_cmd {
+ CS42L43_WRITE,
+ CS42L43_READ
+};
+
+struct cs42l43_spi {
+ struct device *dev;
+ struct regmap *regmap;
+ struct spi_controller *ctlr;
+};
+
+static const unsigned int cs42l43_clock_divs[] = {
+ 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+};
+
+static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len)
+{
+ const u8 *end = buf + len;
+ u32 val = 0;
+ int ret;
+
+ while (buf < end) {
+ const u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
+
+ while (buf < block) {
+ const u8 *word = min(buf + sizeof(u32), block);
+ int pad = (buf + sizeof(u32)) - word;
+
+ while (buf < word) {
+ val >>= BITS_PER_BYTE;
+ val |= FIELD_PREP(GENMASK(31, 24), *buf);
+
+ buf++;
+ }
+
+ val >>= pad * BITS_PER_BYTE;
+
+ regmap_write(regmap, CS42L43_TX_DATA, val);
+ }
+
+ regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_TX_DONE_MASK);
+
+ ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
+ val, (val & CS42L43_SPI_TX_REQUEST_MASK),
+ 1000, 5000);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cs42l43_spi_rx(struct regmap *regmap, u8 *buf, unsigned int len)
+{
+ u8 *end = buf + len;
+ u32 val;
+ int ret;
+
+ while (buf < end) {
+ u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
+
+ ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
+ val, (val & CS42L43_SPI_RX_REQUEST_MASK),
+ 1000, 5000);
+ if (ret)
+ return ret;
+
+ while (buf < block) {
+ u8 *word = min(buf + sizeof(u32), block);
+
+ ret = regmap_read(regmap, CS42L43_RX_DATA, &val);
+ if (ret)
+ return ret;
+
+ while (buf < word) {
+ *buf = FIELD_GET(GENMASK(7, 0), val);
+
+ val >>= BITS_PER_BYTE;
+ buf++;
+ }
+ }
+
+ regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_RX_DONE_MASK);
+ }
+
+ return 0;
+}
+
+static int cs42l43_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_clock_divs); i++) {
+ if (CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[i] <= tfr->speed_hz)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cs42l43_clock_divs))
+ return -EINVAL;
+
+ regmap_write(priv->regmap, CS42L43_SPI_CLK_CONFIG1, i);
+
+ if (tfr->tx_buf) {
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_WRITE);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG4, tfr->len - 1);
+ } else if (tfr->rx_buf) {
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_READ);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG5, tfr->len - 1);
+ }
+
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG1, CS42L43_SPI_START_MASK);
+
+ if (tfr->tx_buf)
+ ret = cs42l43_spi_tx(priv->regmap, (const u8 *)tfr->tx_buf, tfr->len);
+ else if (tfr->rx_buf)
+ ret = cs42l43_spi_rx(priv->regmap, (u8 *)tfr->rx_buf, tfr->len);
+
+ return ret;
+}
+
+static void cs42l43_set_cs(struct spi_device *spi, bool is_high)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
+
+ if (spi_get_chipselect(spi, 0) == 0)
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG2, !is_high);
+}
+
+static int cs42l43_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ struct spi_device *spi = msg->spi;
+ unsigned int spi_config1 = 0;
+
+ /* select another internal CS, which doesn't exist, so CS 0 is not used */
+ if (spi_get_csgpiod(spi, 0))
+ spi_config1 |= 1 << CS42L43_SPI_SS_SEL_SHIFT;
+ if (spi->mode & SPI_CPOL)
+ spi_config1 |= CS42L43_SPI_CPOL_MASK;
+ if (spi->mode & SPI_CPHA)
+ spi_config1 |= CS42L43_SPI_CPHA_MASK;
+ if (spi->mode & SPI_3WIRE)
+ spi_config1 |= CS42L43_SPI_THREE_WIRE_MASK;
+
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG1, spi_config1);
+
+ return 0;
+}
+
+static int cs42l43_prepare_transfer_hardware(struct spi_controller *ctlr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, CS42L43_SPI_MSTR_EN_MASK);
+ if (ret)
+ dev_err(priv->dev, "Failed to enable SPI controller: %d\n", ret);
+
+ return ret;
+}
+
+static int cs42l43_unprepare_transfer_hardware(struct spi_controller *ctlr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, 0);
+ if (ret)
+ dev_err(priv->dev, "Failed to disable SPI controller: %d\n", ret);
+
+ return ret;
+}
+
+static size_t cs42l43_spi_max_length(struct spi_device *spi)
+{
+ return CS42L43_SPI_MAX_LENGTH;
+}
+
+static int cs42l43_spi_probe(struct platform_device *pdev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+ struct cs42l43_spi *priv;
+ struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*priv->ctlr));
+ if (!priv->ctlr)
+ return -ENOMEM;
+
+ spi_controller_set_devdata(priv->ctlr, priv);
+
+ priv->dev = &pdev->dev;
+ priv->regmap = cs42l43->regmap;
+
+ priv->ctlr->prepare_message = cs42l43_prepare_message;
+ priv->ctlr->prepare_transfer_hardware = cs42l43_prepare_transfer_hardware;
+ priv->ctlr->unprepare_transfer_hardware = cs42l43_unprepare_transfer_hardware;
+ priv->ctlr->transfer_one = cs42l43_transfer_one;
+ priv->ctlr->set_cs = cs42l43_set_cs;
+ priv->ctlr->max_transfer_size = cs42l43_spi_max_length;
+
+ if (is_of_node(fwnode))
+ fwnode = fwnode_get_named_child_node(fwnode, "spi");
+
+ device_set_node(&priv->ctlr->dev, fwnode);
+
+ priv->ctlr->mode_bits = SPI_3WIRE | SPI_MODE_X_MASK;
+ priv->ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ priv->ctlr->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(32);
+ priv->ctlr->min_speed_hz = CS42L43_SPI_ROOT_HZ /
+ cs42l43_clock_divs[ARRAY_SIZE(cs42l43_clock_divs) - 1];
+ priv->ctlr->max_speed_hz = CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[0];
+ priv->ctlr->use_gpio_descriptors = true;
+ priv->ctlr->auto_runtime_pm = true;
+
+ devm_pm_runtime_enable(priv->dev);
+ pm_runtime_idle(priv->dev);
+
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG6, CS42L43_FIFO_SIZE - 1);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG7, CS42L43_FIFO_SIZE - 1);
+
+ // Disable Watchdog timer and enable stall
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG3, 0);
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG4, CS42L43_SPI_STALL_ENA_MASK);
+
+ ret = devm_spi_register_controller(priv->dev, priv->ctlr);
+ if (ret) {
+ pm_runtime_disable(priv->dev);
+ dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static const struct platform_device_id cs42l43_spi_id_table[] = {
+ { "cs42l43-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs42l43_spi_id_table);
+
+static struct platform_driver cs42l43_spi_driver = {
+ .driver = {
+ .name = "cs42l43-spi",
+ },
+ .probe = cs42l43_spi_probe,
+ .id_table = cs42l43_spi_id_table,
+};
+module_platform_driver(cs42l43_spi_driver);
+
+MODULE_DESCRIPTION("CS42L43 SPI Driver");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_AUTHOR("Maciej Strozek <mstrozek@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index b04811c911e2..c457b550d3ad 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -15,7 +15,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
@@ -202,7 +201,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
u8 chip_sel = spi_get_chipselect(spi, 0);
u16 spidat1 = CS_DEFAULT;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
/* program delay transfers if tx_delay is non zero */
if (spicfg && spicfg->wdelay)
@@ -272,7 +271,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
u32 hz = 0, spifmt = 0;
int prescale;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
spicfg = spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
@@ -380,7 +379,7 @@ static int davinci_spi_of_setup(struct spi_device *spi)
{
struct davinci_spi_config *spicfg = spi->controller_data;
struct device_node *np = spi->dev.of_node;
- struct davinci_spi *dspi = spi_master_get_devdata(spi->master);
+ struct davinci_spi *dspi = spi_controller_get_devdata(spi->controller);
u32 prop;
if (spicfg == NULL && np) {
@@ -412,7 +411,7 @@ static int davinci_spi_setup(struct spi_device *spi)
struct device_node *np = spi->dev.of_node;
bool internal_cs = true;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
if (!(spi->mode & SPI_NO_CS)) {
if (np && spi_get_csgpiod(spi, 0))
@@ -442,7 +441,7 @@ static void davinci_spi_cleanup(struct spi_device *spi)
kfree(spicfg);
}
-static bool davinci_spi_can_dma(struct spi_master *master,
+static bool davinci_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
@@ -572,7 +571,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct davinci_spi_config *spicfg;
struct davinci_spi_platform_data *pdata;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
pdata = &dspi->pdata;
spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
@@ -593,7 +592,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
reinit_completion(&dspi->done);
- if (!davinci_spi_can_dma(spi->master, spi, t)) {
+ if (!davinci_spi_can_dma(spi->controller, spi, t)) {
if (spicfg->io_type != SPI_IO_TYPE_POLL)
set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
/* start the transfer */
@@ -674,7 +673,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
}
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
- if (davinci_spi_can_dma(spi->master, spi, t))
+ if (davinci_spi_can_dma(spi->controller, spi, t))
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
@@ -856,22 +855,22 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
*/
static int davinci_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct resource *r;
int ret = 0;
u32 spipc0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
- if (master == NULL) {
+ host = spi_alloc_host(&pdev->dev, sizeof(struct davinci_spi));
+ if (host == NULL) {
ret = -ENOMEM;
goto err;
}
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- dspi = spi_master_get_devdata(master);
+ dspi = spi_controller_get_devdata(host);
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@@ -880,7 +879,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
/* update dspi pdata with that from the DT */
ret = spi_davinci_get_pdata(pdev, dspi);
if (ret < 0)
- goto free_master;
+ goto free_host;
}
/* pdata in dspi is now updated and point pdata to that */
@@ -892,57 +891,48 @@ static int davinci_spi_probe(struct platform_device *pdev)
GFP_KERNEL);
if (dspi->bytes_per_word == NULL) {
ret = -ENOMEM;
- goto free_master;
+ goto free_host;
}
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENOENT;
- goto free_master;
- }
-
- dspi->pbase = r->start;
-
- dspi->base = devm_ioremap_resource(&pdev->dev, r);
+ dspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(dspi->base)) {
ret = PTR_ERR(dspi->base);
- goto free_master;
+ goto free_host;
}
+ dspi->pbase = r->start;
init_completion(&dspi->done);
ret = platform_get_irq(pdev, 0);
- if (ret == 0)
- ret = -EINVAL;
if (ret < 0)
- goto free_master;
+ goto free_host;
dspi->irq = ret;
ret = devm_request_threaded_irq(&pdev->dev, dspi->irq, davinci_spi_irq,
dummy_thread_fn, 0, dev_name(&pdev->dev), dspi);
if (ret)
- goto free_master;
+ goto free_host;
- dspi->bitbang.master = master;
+ dspi->bitbang.master = host;
dspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
ret = clk_prepare_enable(dspi->clk);
if (ret)
- goto free_master;
-
- master->use_gpio_descriptors = true;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->num_chipselect = pdata->num_chipselect;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
- master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_GPIO_SS;
- master->setup = davinci_spi_setup;
- master->cleanup = davinci_spi_cleanup;
- master->can_dma = davinci_spi_can_dma;
+ goto free_host;
+
+ host->use_gpio_descriptors = true;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = pdata->num_chipselect;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
+ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_GPIO_SS;
+ host->setup = davinci_spi_setup;
+ host->cleanup = davinci_spi_cleanup;
+ host->can_dma = davinci_spi_can_dma;
dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
@@ -983,7 +973,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
- /* master mode default */
+ /* host mode default */
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
@@ -1003,8 +993,8 @@ free_dma:
}
free_clk:
clk_disable_unprepare(dspi->clk);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
err:
return ret;
}
@@ -1021,10 +1011,10 @@ err:
static void davinci_spi_remove(struct platform_device *pdev)
{
struct davinci_spi *dspi;
- struct spi_master *master;
+ struct spi_controller *host;
- master = platform_get_drvdata(pdev);
- dspi = spi_master_get_devdata(master);
+ host = platform_get_drvdata(pdev);
+ dspi = spi_controller_get_devdata(host);
spi_bitbang_stop(&dspi->bitbang);
@@ -1035,7 +1025,7 @@ static void davinci_spi_remove(struct platform_device *pdev)
dma_release_channel(dspi->dma_tx);
}
- spi_master_put(master);
+ spi_controller_put(host);
}
static struct platform_driver davinci_spi_driver = {
diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c
index 6bd93c47853c..d319dc357fef 100644
--- a/drivers/spi/spi-dln2.c
+++ b/drivers/spi/spi-dln2.c
@@ -79,7 +79,7 @@
struct dln2_spi {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
u8 port;
/*
@@ -176,7 +176,7 @@ static int dln2_spi_cs_enable(struct dln2_spi *dln2, u8 cs_mask, bool enable)
static int dln2_spi_cs_enable_all(struct dln2_spi *dln2, bool enable)
{
- u8 cs_mask = GENMASK(dln2->master->num_chipselect - 1, 0);
+ u8 cs_mask = GENMASK(dln2->host->num_chipselect - 1, 0);
return dln2_spi_cs_enable(dln2, cs_mask, enable);
}
@@ -589,11 +589,11 @@ static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data,
return 0;
}
-static int dln2_spi_prepare_message(struct spi_master *master,
+static int dln2_spi_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
int ret;
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
struct spi_device *spi = message->spi;
if (dln2->cs != spi_get_chipselect(spi, 0)) {
@@ -650,11 +650,11 @@ static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed,
return dln2_spi_enable(dln2, true);
}
-static int dln2_spi_transfer_one(struct spi_master *master,
+static int dln2_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
int status;
u8 attr = 0;
@@ -666,7 +666,7 @@ static int dln2_spi_transfer_one(struct spi_master *master,
return status;
}
- if (!xfer->cs_change && !spi_transfer_is_last(master, xfer))
+ if (!xfer->cs_change && !spi_transfer_is_last(host, xfer))
attr = DLN2_SPI_ATTR_LEAVE_SS_LOW;
status = dln2_spi_rdwr(dln2, xfer->tx_buf, xfer->rx_buf,
@@ -679,29 +679,29 @@ static int dln2_spi_transfer_one(struct spi_master *master,
static int dln2_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct dln2_spi *dln2;
struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*dln2));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*dln2));
+ if (!host)
return -ENOMEM;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&host->dev, dev_fwnode(dev));
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- dln2 = spi_master_get_devdata(master);
+ dln2 = spi_controller_get_devdata(host);
dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL);
if (!dln2->buf) {
ret = -ENOMEM;
- goto exit_free_master;
+ goto exit_free_host;
}
- dln2->master = master;
+ dln2->host = host;
dln2->pdev = pdev;
dln2->port = pdata->port;
/* cs/mode can never be 0xff, so the first transfer will set them */
@@ -712,47 +712,47 @@ static int dln2_spi_probe(struct platform_device *pdev)
ret = dln2_spi_enable(dln2, false);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable SPI module\n");
- goto exit_free_master;
+ goto exit_free_host;
}
- ret = dln2_spi_get_cs_num(dln2, &master->num_chipselect);
+ ret = dln2_spi_get_cs_num(dln2, &host->num_chipselect);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get number of CS pins\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_get_speed_range(dln2,
- &master->min_speed_hz,
- &master->max_speed_hz);
+ &host->min_speed_hz,
+ &host->max_speed_hz);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read bus min/max freqs\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_get_supported_frame_sizes(dln2,
- &master->bits_per_word_mask);
+ &host->bits_per_word_mask);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read supported frame sizes\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_cs_enable_all(dln2, true);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable CS pins\n");
- goto exit_free_master;
+ goto exit_free_host;
}
- master->bus_num = -1;
- master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->prepare_message = dln2_spi_prepare_message;
- master->transfer_one = dln2_spi_transfer_one;
- master->auto_runtime_pm = true;
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPOL | SPI_CPHA;
+ host->prepare_message = dln2_spi_prepare_message;
+ host->transfer_one = dln2_spi_transfer_one;
+ host->auto_runtime_pm = true;
/* enable SPI module, we're good to go */
ret = dln2_spi_enable(dln2, true);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable SPI module\n");
- goto exit_free_master;
+ goto exit_free_host;
}
pm_runtime_set_autosuspend_delay(&pdev->dev,
@@ -761,9 +761,9 @@ static int dln2_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register master\n");
+ dev_err(&pdev->dev, "Failed to register host\n");
goto exit_register;
}
@@ -775,16 +775,16 @@ exit_register:
if (dln2_spi_enable(dln2, false) < 0)
dev_err(&pdev->dev, "Failed to disable SPI module\n");
-exit_free_master:
- spi_master_put(master);
+exit_free_host:
+ spi_controller_put(host);
return ret;
}
static void dln2_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
@@ -796,10 +796,10 @@ static void dln2_spi_remove(struct platform_device *pdev)
static int dln2_spi_suspend(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret < 0)
return ret;
@@ -824,8 +824,8 @@ static int dln2_spi_suspend(struct device *dev)
static int dln2_spi_resume(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
if (!pm_runtime_suspended(dev)) {
ret = dln2_spi_cs_enable_all(dln2, true);
@@ -837,23 +837,23 @@ static int dln2_spi_resume(struct device *dev)
return ret;
}
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int dln2_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
return dln2_spi_enable(dln2, false);
}
static int dln2_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
return dln2_spi_enable(dln2, true);
}
@@ -875,7 +875,7 @@ static struct platform_driver spi_dln2_driver = {
};
module_platform_driver(spi_dln2_driver);
-MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI master interface");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI host interface");
MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:dln2-spi");
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index a8ba41ad4541..0274c9295514 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -61,7 +61,7 @@ static void dw_spi_debugfs_init(struct dw_spi *dws)
{
char name[32];
- snprintf(name, 32, "dw_spi%d", dws->master->bus_num);
+ snprintf(name, 32, "dw_spi%d", dws->host->bus_num);
dws->debugfs = debugfs_create_dir(name, NULL);
dws->regset.regs = dw_spi_dbgfs_regs;
@@ -183,25 +183,25 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
irq_status = dw_readl(dws, DW_SPI_ISR);
if (irq_status & DW_SPI_INT_RXOI) {
- dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
+ dev_err(&dws->host->dev, "RX FIFO overflow detected\n");
ret = -EIO;
}
if (irq_status & DW_SPI_INT_RXUI) {
- dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
+ dev_err(&dws->host->dev, "RX FIFO underflow detected\n");
ret = -EIO;
}
if (irq_status & DW_SPI_INT_TXOI) {
- dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
+ dev_err(&dws->host->dev, "TX FIFO overflow detected\n");
ret = -EIO;
}
/* Generically handle the erroneous situation */
if (ret) {
dw_spi_reset_chip(dws);
- if (dws->master->cur_msg)
- dws->master->cur_msg->status = ret;
+ if (dws->host->cur_msg)
+ dws->host->cur_msg->status = ret;
}
return ret;
@@ -213,7 +213,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
if (dw_spi_check_status(dws, false)) {
- spi_finalize_current_transfer(dws->master);
+ spi_finalize_current_transfer(dws->host);
return IRQ_HANDLED;
}
@@ -227,7 +227,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
dw_reader(dws);
if (!dws->rx_len) {
dw_spi_mask_intr(dws, 0xff);
- spi_finalize_current_transfer(dws->master);
+ spi_finalize_current_transfer(dws->host);
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
}
@@ -248,14 +248,14 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{
- struct spi_controller *master = dev_id;
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct dw_spi *dws = spi_controller_get_devdata(host);
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK;
if (!irq_status)
return IRQ_NONE;
- if (!master->cur_msg) {
+ if (!host->cur_msg) {
dw_spi_mask_intr(dws, 0xff);
return IRQ_HANDLED;
}
@@ -408,11 +408,11 @@ static int dw_spi_poll_transfer(struct dw_spi *dws,
return 0;
}
-static int dw_spi_transfer_one(struct spi_controller *master,
+static int dw_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *transfer)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(host);
struct dw_spi_cfg cfg = {
.tmode = DW_SPI_CTRLR0_TMOD_TR,
.dfs = transfer->bits_per_word,
@@ -440,8 +440,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
transfer->effective_speed_hz = dws->current_freq;
/* Check if current transfer is a DMA transaction */
- if (master->can_dma && master->can_dma(master, spi, transfer))
- dws->dma_mapped = master->cur_msg_mapped;
+ if (host->can_dma && host->can_dma(host, spi, transfer))
+ dws->dma_mapped = host->cur_msg_mapped;
/* For poll mode just disable all interrupts */
dw_spi_mask_intr(dws, 0xff);
@@ -464,10 +464,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,
return 1;
}
-static void dw_spi_handle_err(struct spi_controller *master,
+static void dw_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(host);
if (dws->dma_mapped)
dws->dma_ops->dma_stop(dws);
@@ -576,7 +576,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
while (len) {
entries = readl_relaxed(dws->regs + DW_SPI_TXFLR);
if (!entries) {
- dev_err(&dws->master->dev, "CS de-assertion on Tx\n");
+ dev_err(&dws->host->dev, "CS de-assertion on Tx\n");
return -EIO;
}
room = min(dws->fifo_len - entries, len);
@@ -596,7 +596,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
if (!entries) {
sts = readl_relaxed(dws->regs + DW_SPI_RISR);
if (sts & DW_SPI_INT_RXOI) {
- dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
+ dev_err(&dws->host->dev, "FIFO overflow on Rx\n");
return -EIO;
}
continue;
@@ -637,7 +637,7 @@ static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
spi_delay_exec(&delay, NULL);
if (retry < 0) {
- dev_err(&dws->master->dev, "Mem op hanged up\n");
+ dev_err(&dws->host->dev, "Mem op hanged up\n");
return -EIO;
}
@@ -884,56 +884,56 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
{
- struct spi_controller *master;
+ struct spi_controller *host;
int ret;
if (!dws)
return -EINVAL;
- master = spi_alloc_master(dev, 0);
- if (!master)
+ host = spi_alloc_host(dev, 0);
+ if (!host)
return -ENOMEM;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&host->dev, dev_fwnode(dev));
- dws->master = master;
+ dws->host = host;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
- spi_controller_set_devdata(master, dws);
+ spi_controller_set_devdata(host, dws);
/* Basic HW init */
dw_spi_hw_init(dev, dws);
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
- master);
+ host);
if (ret < 0 && ret != -ENOTCONN) {
dev_err(dev, "can not get IRQ\n");
- goto err_free_master;
+ goto err_free_host;
}
dw_spi_init_mem_ops(dws);
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+ host->use_gpio_descriptors = true;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
if (dws->caps & DW_SPI_CAP_DFS32)
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
else
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
- master->bus_num = dws->bus_num;
- master->num_chipselect = dws->num_cs;
- master->setup = dw_spi_setup;
- master->cleanup = dw_spi_cleanup;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ host->bus_num = dws->bus_num;
+ host->num_chipselect = dws->num_cs;
+ host->setup = dw_spi_setup;
+ host->cleanup = dw_spi_cleanup;
if (dws->set_cs)
- master->set_cs = dws->set_cs;
+ host->set_cs = dws->set_cs;
else
- master->set_cs = dw_spi_set_cs;
- master->transfer_one = dw_spi_transfer_one;
- master->handle_err = dw_spi_handle_err;
+ host->set_cs = dw_spi_set_cs;
+ host->transfer_one = dw_spi_transfer_one;
+ host->handle_err = dw_spi_handle_err;
if (dws->mem_ops.exec_op)
- master->mem_ops = &dws->mem_ops;
- master->max_speed_hz = dws->max_freq;
- master->flags = SPI_MASTER_GPIO_SS;
- master->auto_runtime_pm = true;
+ host->mem_ops = &dws->mem_ops;
+ host->max_speed_hz = dws->max_freq;
+ host->flags = SPI_CONTROLLER_GPIO_SS;
+ host->auto_runtime_pm = true;
/* Get default rx sample delay */
device_property_read_u32(dev, "rx-sample-delay-ns",
@@ -946,14 +946,14 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
} else if (ret) {
dev_warn(dev, "DMA init failed\n");
} else {
- master->can_dma = dws->dma_ops->can_dma;
- master->flags |= SPI_CONTROLLER_MUST_TX;
+ host->can_dma = dws->dma_ops->can_dma;
+ host->flags |= SPI_CONTROLLER_MUST_TX;
}
}
- ret = spi_register_controller(master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err_probe(dev, ret, "problem registering spi master\n");
+ dev_err_probe(dev, ret, "problem registering spi host\n");
goto err_dma_exit;
}
@@ -965,9 +965,9 @@ err_dma_exit:
dws->dma_ops->dma_exit(dws);
dw_spi_enable_chip(dws, 0);
err_free_irq:
- free_irq(dws->irq, master);
-err_free_master:
- spi_controller_put(master);
+ free_irq(dws->irq, host);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE);
@@ -976,14 +976,14 @@ void dw_spi_remove_host(struct dw_spi *dws)
{
dw_spi_debugfs_remove(dws);
- spi_unregister_controller(dws->master);
+ spi_unregister_controller(dws->host);
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
dw_spi_shutdown_chip(dws);
- free_irq(dws->irq, dws->master);
+ free_irq(dws->irq, dws->host);
}
EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE);
@@ -991,7 +991,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
{
int ret;
- ret = spi_controller_suspend(dws->master);
+ ret = spi_controller_suspend(dws->host);
if (ret)
return ret;
@@ -1002,8 +1002,8 @@ EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE);
int dw_spi_resume_host(struct dw_spi *dws)
{
- dw_spi_hw_init(&dws->master->dev, dws);
- return spi_controller_resume(dws->master);
+ dw_spi_hw_init(&dws->host->dev, dws);
+ return spi_controller_resume(dws->host);
}
EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE);
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index df819652901a..0ecbb6c36e23 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -139,8 +139,8 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
if (!dws->txchan)
goto free_rxchan;
- dws->master->dma_rx = dws->rxchan;
- dws->master->dma_tx = dws->txchan;
+ dws->host->dma_rx = dws->rxchan;
+ dws->host->dma_tx = dws->txchan;
init_completion(&dws->dma_completion);
@@ -183,8 +183,8 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
goto free_rxchan;
}
- dws->master->dma_rx = dws->rxchan;
- dws->master->dma_tx = dws->txchan;
+ dws->host->dma_rx = dws->rxchan;
+ dws->host->dma_tx = dws->txchan;
init_completion(&dws->dma_completion);
@@ -242,10 +242,10 @@ static enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes)
}
}
-static bool dw_spi_can_dma(struct spi_controller *master,
+static bool dw_spi_can_dma(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *xfer)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(host);
enum dma_slave_buswidth dma_bus_width;
if (xfer->len <= dws->fifo_len)
@@ -271,7 +271,7 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
msecs_to_jiffies(ms));
if (ms == 0) {
- dev_err(&dws->master->cur_msg->spi->dev,
+ dev_err(&dws->host->cur_msg->spi->dev,
"DMA transaction timed out\n");
return -ETIMEDOUT;
}
@@ -299,7 +299,7 @@ static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
spi_delay_exec(&delay, xfer);
if (retry < 0) {
- dev_err(&dws->master->dev, "Tx hanged up\n");
+ dev_err(&dws->host->dev, "Tx hanged up\n");
return -EIO;
}
@@ -400,7 +400,7 @@ static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
spi_delay_exec(&delay, NULL);
if (retry < 0) {
- dev_err(&dws->master->dev, "Rx hanged up\n");
+ dev_err(&dws->host->dev, "Rx hanged up\n");
return -EIO;
}
@@ -656,13 +656,13 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
if (ret)
return ret;
- if (dws->master->cur_msg->status == -EINPROGRESS) {
+ if (dws->host->cur_msg->status == -EINPROGRESS) {
ret = dw_spi_dma_wait_tx_done(dws, xfer);
if (ret)
return ret;
}
- if (xfer->rx_buf && dws->master->cur_msg->status == -EINPROGRESS)
+ if (xfer->rx_buf && dws->host->cur_msg->status == -EINPROGRESS)
ret = dw_spi_dma_wait_rx_done(dws);
return ret;
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index a963bc96c223..805264c9c65c 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -76,7 +76,7 @@ struct dw_spi_mscc {
*/
static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
u32 cs = spi_get_chipselect(spi, 0);
@@ -149,7 +149,7 @@ static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
*/
static void dw_spi_sparx5_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
u8 cs = spi_get_chipselect(spi, 0);
@@ -277,7 +277,7 @@ static void dw_spi_elba_override_cs(struct regmap *syscon, int cs, int enable)
static void dw_spi_elba_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct regmap *syscon = dwsmmio->priv;
u8 cs;
@@ -369,7 +369,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws->max_freq = clk_get_rate(dwsmmio->clk);
- device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width);
+ if (device_property_read_u32(&pdev->dev, "reg-io-width",
+ &dws->reg_io_width))
+ dws->reg_io_width = 4;
num_cs = 4;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 3962e6dcf880..6cafeee8ee2a 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -142,14 +142,14 @@ struct dw_spi_dma_ops {
int (*dma_init)(struct device *dev, struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
- bool (*can_dma)(struct spi_controller *master, struct spi_device *spi,
+ bool (*can_dma)(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws);
};
struct dw_spi {
- struct spi_controller *master;
+ struct spi_controller *host;
u32 ip; /* Synopsys DW SSI IP-core ID */
u32 ver; /* Synopsys component version */
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1615fd22f9a2..a1d60e51c053 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -104,15 +104,15 @@ struct ep93xx_spi {
/**
* ep93xx_spi_calc_divisors() - calculates SPI clock divisors
- * @master: SPI master
+ * @host: SPI host
* @rate: desired SPI output clock rate
* @div_cpsr: pointer to return the cpsr (pre-scaler) divider
* @div_scr: pointer to return the scr divider
*/
-static int ep93xx_spi_calc_divisors(struct spi_master *master,
+static int ep93xx_spi_calc_divisors(struct spi_controller *host,
u32 rate, u8 *div_cpsr, u8 *div_scr)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -120,7 +120,7 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master,
* Make sure that max value is between values supported by the
* controller.
*/
- rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
+ rate = clamp(rate, host->min_speed_hz, host->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@@ -143,18 +143,18 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master,
return -EINVAL;
}
-static int ep93xx_spi_chip_setup(struct spi_master *master,
+static int ep93xx_spi_chip_setup(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u8 dss = bits_per_word_to_dss(xfer->bits_per_word);
u8 div_cpsr = 0;
u8 div_scr = 0;
u16 cr0;
int err;
- err = ep93xx_spi_calc_divisors(master, xfer->speed_hz,
+ err = ep93xx_spi_calc_divisors(host, xfer->speed_hz,
&div_cpsr, &div_scr);
if (err)
return err;
@@ -166,9 +166,9 @@ static int ep93xx_spi_chip_setup(struct spi_master *master,
cr0 |= SSPCR0_SPH;
cr0 |= dss;
- dev_dbg(&master->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+ dev_dbg(&host->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
spi->mode, div_cpsr, div_scr, dss);
- dev_dbg(&master->dev, "setup: cr0 %#x\n", cr0);
+ dev_dbg(&host->dev, "setup: cr0 %#x\n", cr0);
writel(div_cpsr, espi->mmio + SSPCPSR);
writel(cr0, espi->mmio + SSPCR0);
@@ -176,10 +176,10 @@ static int ep93xx_spi_chip_setup(struct spi_master *master,
return 0;
}
-static void ep93xx_do_write(struct spi_master *master)
+static void ep93xx_do_write(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
u32 val = 0;
if (xfer->bits_per_word > 8) {
@@ -194,10 +194,10 @@ static void ep93xx_do_write(struct spi_master *master)
writel(val, espi->mmio + SSPDR);
}
-static void ep93xx_do_read(struct spi_master *master)
+static void ep93xx_do_read(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
u32 val;
val = readl(espi->mmio + SSPDR);
@@ -214,7 +214,7 @@ static void ep93xx_do_read(struct spi_master *master)
/**
* ep93xx_spi_read_write() - perform next RX/TX transfer
- * @master: SPI master
+ * @host: SPI host
*
* This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
* called several times, the whole transfer will be completed. Returns
@@ -223,20 +223,20 @@ static void ep93xx_do_read(struct spi_master *master)
* When this function is finished, RX FIFO should be empty and TX FIFO should be
* full.
*/
-static int ep93xx_spi_read_write(struct spi_master *master)
+static int ep93xx_spi_read_write(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
/* read as long as RX FIFO has frames in it */
while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) {
- ep93xx_do_read(master);
+ ep93xx_do_read(host);
espi->fifo_level--;
}
/* write as long as TX FIFO has room */
while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < xfer->len) {
- ep93xx_do_write(master);
+ ep93xx_do_write(host);
espi->fifo_level++;
}
@@ -261,7 +261,7 @@ ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
/**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer
- * @master: SPI master
+ * @host: SPI host
* @dir: DMA transfer direction
*
* Function configures the DMA, maps the buffer and prepares the DMA
@@ -269,11 +269,11 @@ ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
* in case of failure.
*/
static struct dma_async_tx_descriptor *
-ep93xx_spi_dma_prepare(struct spi_master *master,
+ep93xx_spi_dma_prepare(struct spi_controller *host,
enum dma_data_direction dir)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth;
struct dma_slave_config conf;
@@ -348,7 +348,7 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
}
if (WARN_ON(len)) {
- dev_warn(&master->dev, "len = %zu expected 0!\n", len);
+ dev_warn(&host->dev, "len = %zu expected 0!\n", len);
return ERR_PTR(-EINVAL);
}
@@ -367,16 +367,16 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
/**
* ep93xx_spi_dma_finish() - finishes with a DMA transfer
- * @master: SPI master
+ * @host: SPI host
* @dir: DMA transfer direction
*
* Function finishes with the DMA transfer. After this, the DMA buffer is
* unmapped.
*/
-static void ep93xx_spi_dma_finish(struct spi_master *master,
+static void ep93xx_spi_dma_finish(struct spi_controller *host,
enum dma_data_direction dir)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
struct dma_chan *chan;
struct sg_table *sgt;
@@ -393,35 +393,35 @@ static void ep93xx_spi_dma_finish(struct spi_master *master,
static void ep93xx_spi_dma_callback(void *callback_param)
{
- struct spi_master *master = callback_param;
+ struct spi_controller *host = callback_param;
- ep93xx_spi_dma_finish(master, DMA_TO_DEVICE);
- ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
+ ep93xx_spi_dma_finish(host, DMA_TO_DEVICE);
+ ep93xx_spi_dma_finish(host, DMA_FROM_DEVICE);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
-static int ep93xx_spi_dma_transfer(struct spi_master *master)
+static int ep93xx_spi_dma_transfer(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
struct dma_async_tx_descriptor *rxd, *txd;
- rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE);
+ rxd = ep93xx_spi_dma_prepare(host, DMA_FROM_DEVICE);
if (IS_ERR(rxd)) {
- dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
+ dev_err(&host->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
return PTR_ERR(rxd);
}
- txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE);
+ txd = ep93xx_spi_dma_prepare(host, DMA_TO_DEVICE);
if (IS_ERR(txd)) {
- ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
- dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
+ ep93xx_spi_dma_finish(host, DMA_FROM_DEVICE);
+ dev_err(&host->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
return PTR_ERR(txd);
}
/* We are ready when RX is done */
rxd->callback = ep93xx_spi_dma_callback;
- rxd->callback_param = master;
+ rxd->callback_param = host;
/* Now submit both descriptors and start DMA */
dmaengine_submit(rxd);
@@ -436,8 +436,8 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master)
static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
/*
@@ -447,15 +447,15 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
if (readl(espi->mmio + SSPIIR) & SSPIIR_RORIS) {
/* clear the overrun interrupt */
writel(0, espi->mmio + SSPICR);
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"receive overrun, aborting the message\n");
- master->cur_msg->status = -EIO;
+ host->cur_msg->status = -EIO;
} else {
/*
* Interrupt is either RX (RIS) or TX (TIS). For both cases we
* simply execute next data transfer.
*/
- if (ep93xx_spi_read_write(master)) {
+ if (ep93xx_spi_read_write(host)) {
/*
* In normal case, there still is some processing left
* for current transfer. Let's wait for the next
@@ -474,26 +474,26 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
writel(val, espi->mmio + SSPCR1);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
-static int ep93xx_spi_transfer_one(struct spi_master *master,
+static int ep93xx_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
int ret;
- ret = ep93xx_spi_chip_setup(master, spi, xfer);
+ ret = ep93xx_spi_chip_setup(host, spi, xfer);
if (ret) {
- dev_err(&master->dev, "failed to setup chip for transfer\n");
+ dev_err(&host->dev, "failed to setup chip for transfer\n");
return ret;
}
- master->cur_msg->state = xfer;
+ host->cur_msg->state = xfer;
espi->rx = 0;
espi->tx = 0;
@@ -503,10 +503,10 @@ static int ep93xx_spi_transfer_one(struct spi_master *master,
* So in these cases we will be using PIO and don't bother for DMA.
*/
if (espi->dma_rx && xfer->len > SPI_FIFO_SIZE)
- return ep93xx_spi_dma_transfer(master);
+ return ep93xx_spi_dma_transfer(host);
/* Using PIO so prime the TX FIFO and enable interrupts */
- ep93xx_spi_read_write(master);
+ ep93xx_spi_read_write(host);
val = readl(espi->mmio + SSPCR1);
val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
@@ -516,10 +516,10 @@ static int ep93xx_spi_transfer_one(struct spi_master *master,
return 1;
}
-static int ep93xx_spi_prepare_message(struct spi_master *master,
+static int ep93xx_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
unsigned long timeout;
/*
@@ -528,7 +528,7 @@ static int ep93xx_spi_prepare_message(struct spi_master *master,
timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
while (readl(espi->mmio + SSPSR) & SSPSR_RNE) {
if (time_after(jiffies, timeout)) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"timeout while flushing RX FIFO\n");
return -ETIMEDOUT;
}
@@ -544,9 +544,9 @@ static int ep93xx_spi_prepare_message(struct spi_master *master,
return 0;
}
-static int ep93xx_spi_prepare_hardware(struct spi_master *master)
+static int ep93xx_spi_prepare_hardware(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
int ret;
@@ -561,9 +561,9 @@ static int ep93xx_spi_prepare_hardware(struct spi_master *master)
return 0;
}
-static int ep93xx_spi_unprepare_hardware(struct spi_master *master)
+static int ep93xx_spi_unprepare_hardware(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
val = readl(espi->mmio + SSPCR1);
@@ -646,7 +646,7 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
static int ep93xx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct ep93xx_spi_info *info;
struct ep93xx_spi *espi;
struct resource *res;
@@ -661,63 +661,56 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return -EBUSY;
+ return irq;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "unable to get iomem resource\n");
- return -ENODEV;
- }
-
- master = spi_alloc_master(&pdev->dev, sizeof(*espi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*espi));
+ if (!host)
return -ENOMEM;
- master->use_gpio_descriptors = true;
- master->prepare_transfer_hardware = ep93xx_spi_prepare_hardware;
- master->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware;
- master->prepare_message = ep93xx_spi_prepare_message;
- master->transfer_one = ep93xx_spi_transfer_one;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ host->use_gpio_descriptors = true;
+ host->prepare_transfer_hardware = ep93xx_spi_prepare_hardware;
+ host->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware;
+ host->prepare_message = ep93xx_spi_prepare_message;
+ host->transfer_one = ep93xx_spi_transfer_one;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
/*
* The SPI core will count the number of GPIO descriptors to figure
* out the number of chip selects available on the platform.
*/
- master->num_chipselect = 0;
+ host->num_chipselect = 0;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- espi = spi_master_get_devdata(master);
+ espi = spi_controller_get_devdata(host);
espi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(espi->clk)) {
dev_err(&pdev->dev, "unable to get spi clock\n");
error = PTR_ERR(espi->clk);
- goto fail_release_master;
+ goto fail_release_host;
}
/*
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
- master->max_speed_hz = clk_get_rate(espi->clk) / 2;
- master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
+ host->max_speed_hz = clk_get_rate(espi->clk) / 2;
+ host->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
- espi->sspdr_phys = res->start + SSPDR;
-
- espi->mmio = devm_ioremap_resource(&pdev->dev, res);
+ espi->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(espi->mmio)) {
error = PTR_ERR(espi->mmio);
- goto fail_release_master;
+ goto fail_release_host;
}
+ espi->sspdr_phys = res->start + SSPDR;
error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
- 0, "ep93xx-spi", master);
+ 0, "ep93xx-spi", host);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto fail_release_master;
+ goto fail_release_host;
}
if (info->use_dma && ep93xx_spi_setup_dma(espi))
@@ -726,9 +719,9 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
/* make sure that the hardware is disabled */
writel(0, espi->mmio + SSPCR1);
- error = devm_spi_register_master(&pdev->dev, master);
+ error = devm_spi_register_controller(&pdev->dev, host);
if (error) {
- dev_err(&pdev->dev, "failed to register SPI master\n");
+ dev_err(&pdev->dev, "failed to register SPI host\n");
goto fail_free_dma;
}
@@ -739,16 +732,16 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
fail_free_dma:
ep93xx_spi_release_dma(espi);
-fail_release_master:
- spi_master_put(master);
+fail_release_host:
+ spi_controller_put(host);
return error;
}
static void ep93xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
ep93xx_spi_release_dma(espi);
}
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index 4c103dff0d44..84279058f0f1 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -91,14 +91,14 @@
struct falcon_sflash {
u32 sfcmd; /* for caching of opcode, direction, ... */
- struct spi_master *master;
+ struct spi_controller *host;
};
int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
unsigned long flags)
{
struct device *dev = &spi->dev;
- struct falcon_sflash *priv = spi_master_get_devdata(spi->master);
+ struct falcon_sflash *priv = spi_controller_get_devdata(spi->controller);
const u8 *txp = t->tx_buf;
u8 *rxp = t->rx_buf;
unsigned int bytelen = ((8 * t->len + 7) / 8);
@@ -351,10 +351,10 @@ static int falcon_sflash_setup(struct spi_device *spi)
return 0;
}
-static int falcon_sflash_xfer_one(struct spi_master *master,
+static int falcon_sflash_xfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct falcon_sflash *priv = spi_master_get_devdata(master);
+ struct falcon_sflash *priv = spi_controller_get_devdata(host);
struct spi_transfer *t;
unsigned long spi_flags;
unsigned long flags;
@@ -382,7 +382,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
}
m->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -390,25 +390,25 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
static int falcon_sflash_probe(struct platform_device *pdev)
{
struct falcon_sflash *priv;
- struct spi_master *master;
+ struct spi_controller *host;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*priv));
+ if (!host)
return -ENOMEM;
- priv = spi_master_get_devdata(master);
- priv->master = master;
+ priv = spi_controller_get_devdata(host);
+ priv->host = host;
- master->mode_bits = SPI_MODE_3;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->setup = falcon_sflash_setup;
- master->transfer_one_message = falcon_sflash_xfer_one;
- master->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = falcon_sflash_setup;
+ host->transfer_one_message = falcon_sflash_xfer_one;
+ host->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret)
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c
index ba3b17d7c9ec..fc9e33be1e0e 100644
--- a/drivers/spi/spi-fsi.c
+++ b/drivers/spi/spi-fsi.c
@@ -542,7 +542,7 @@ static int fsi_spi_probe(struct device *dev)
if (of_property_read_u32(np, "reg", &base))
continue;
- ctlr = spi_alloc_master(dev, sizeof(*ctx));
+ ctlr = spi_alloc_host(dev, sizeof(*ctx));
if (!ctlr) {
of_node_put(np);
break;
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index 38452089e8f3..47c7a5c6257f 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -56,12 +56,12 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
QE_CR_PROTOCOL_UNSPECIFIED, 0);
} else {
if (mspi->flags & SPI_CPM1) {
- out_be32(&mspi->pram->rstate, 0);
- out_be16(&mspi->pram->rbptr,
- in_be16(&mspi->pram->rbase));
- out_be32(&mspi->pram->tstate, 0);
- out_be16(&mspi->pram->tbptr,
- in_be16(&mspi->pram->tbase));
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite16be(ioread16be(&mspi->pram->rbase),
+ &mspi->pram->rbptr);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite16be(ioread16be(&mspi->pram->tbase),
+ &mspi->pram->tbptr);
} else {
cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
}
@@ -75,24 +75,24 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
unsigned int xfer_ofs;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
if (mspi->rx_dma == mspi->dma_dummy_rx)
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
+ iowrite32be(mspi->rx_dma, &rx_bd->cbd_bufaddr);
else
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
- out_be16(&rx_bd->cbd_datlen, 0);
- out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+ iowrite32be(mspi->rx_dma + xfer_ofs, &rx_bd->cbd_bufaddr);
+ iowrite16be(0, &rx_bd->cbd_datlen);
+ iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP, &rx_bd->cbd_sc);
if (mspi->tx_dma == mspi->dma_dummy_tx)
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
+ iowrite32be(mspi->tx_dma, &tx_bd->cbd_bufaddr);
else
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
- out_be16(&tx_bd->cbd_datlen, xfer_len);
- out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
- BD_SC_LAST);
+ iowrite32be(mspi->tx_dma + xfer_ofs, &tx_bd->cbd_bufaddr);
+ iowrite16be(xfer_len, &tx_bd->cbd_datlen);
+ iowrite16be(BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST,
+ &tx_bd->cbd_sc);
/* start transfer */
mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
@@ -102,7 +102,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, bool is_dma_mapped)
{
struct device *dev = mspi->dev;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
if (is_dma_mapped) {
mspi->map_tx_dma = 0;
@@ -123,7 +123,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
}
if (t->bits_per_word == 16 && t->tx_buf) {
const u16 *src = t->tx_buf;
- u16 *dst;
+ __le16 *dst;
int i;
dst = kmalloc(t->len, GFP_KERNEL);
@@ -202,12 +202,12 @@ EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete);
void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
{
u16 len;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
- in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+ ioread16be(&mspi->rx_bd->cbd_datlen), mspi->count);
- len = in_be16(&mspi->rx_bd->cbd_datlen);
+ len = ioread16be(&mspi->rx_bd->cbd_datlen);
if (len > mspi->count) {
WARN_ON(1);
len = mspi->count;
@@ -328,7 +328,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
}
if (mspi->flags & SPI_CPM1) {
- void *pram;
+ void __iomem *pram;
pram = devm_platform_ioremap_resource(to_platform_device(dev),
1);
@@ -374,21 +374,21 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
/* Initialize parameter ram. */
- out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
- out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
- out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
- out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
- out_be16(&mspi->pram->mrblr, SPI_MRBLR);
- out_be32(&mspi->pram->rstate, 0);
- out_be32(&mspi->pram->rdp, 0);
- out_be16(&mspi->pram->rbptr, 0);
- out_be16(&mspi->pram->rbc, 0);
- out_be32(&mspi->pram->rxtmp, 0);
- out_be32(&mspi->pram->tstate, 0);
- out_be32(&mspi->pram->tdp, 0);
- out_be16(&mspi->pram->tbptr, 0);
- out_be16(&mspi->pram->tbc, 0);
- out_be32(&mspi->pram->txtmp, 0);
+ iowrite16be(cpm_muram_offset(mspi->tx_bd), &mspi->pram->tbase);
+ iowrite16be(cpm_muram_offset(mspi->rx_bd), &mspi->pram->rbase);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->tfcr);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->rfcr);
+ iowrite16be(SPI_MRBLR, &mspi->pram->mrblr);
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite32be(0, &mspi->pram->rdp);
+ iowrite16be(0, &mspi->pram->rbptr);
+ iowrite16be(0, &mspi->pram->rbc);
+ iowrite32be(0, &mspi->pram->rxtmp);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite32be(0, &mspi->pram->tdp);
+ iowrite16be(0, &mspi->pram->tbptr);
+ iowrite16be(0, &mspi->pram->tbc);
+ iowrite32be(0, &mspi->pram->txtmp);
return 0;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 674cfe05f411..8318249f8a1f 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -13,7 +13,8 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -22,7 +23,7 @@
#define DRIVER_NAME "fsl-dspi"
#define SPI_MCR 0x00
-#define SPI_MCR_MASTER BIT(31)
+#define SPI_MCR_HOST BIT(31)
#define SPI_MCR_PCSIS(x) ((x) << 16)
#define SPI_MCR_CLR_TXF BIT(11)
#define SPI_MCR_CLR_RXF BIT(10)
@@ -339,7 +340,7 @@ static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
{
u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
- if (spi_controller_is_slave(dspi->ctlr))
+ if (spi_controller_is_target(dspi->ctlr))
return data;
if (dspi->len > 0)
@@ -429,7 +430,7 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
dma_async_issue_pending(dma->chan_rx);
dma_async_issue_pending(dma->chan_tx);
- if (spi_controller_is_slave(dspi->ctlr)) {
+ if (spi_controller_is_target(dspi->ctlr)) {
wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete);
return 0;
}
@@ -502,15 +503,14 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
dma->chan_rx = dma_request_chan(dev, "rx");
if (IS_ERR(dma->chan_rx)) {
- dev_err(dev, "rx dma channel not available\n");
- ret = PTR_ERR(dma->chan_rx);
- return ret;
+ return dev_err_probe(dev, PTR_ERR(dma->chan_rx),
+ "rx dma channel not available\n");
}
dma->chan_tx = dma_request_chan(dev, "tx");
if (IS_ERR(dma->chan_tx)) {
- dev_err(dev, "tx dma channel not available\n");
ret = PTR_ERR(dma->chan_tx);
+ dev_err_probe(dev, ret, "tx dma channel not available\n");
goto err_tx_channel;
}
@@ -1061,7 +1061,7 @@ static int dspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
chip->ctar_val |= SPI_CTAR_CPHA;
- if (!spi_controller_is_slave(dspi->ctlr)) {
+ if (!spi_controller_is_target(dspi->ctlr)) {
chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) |
SPI_CTAR_CSSCK(cssck) |
SPI_CTAR_PASC(pasc) |
@@ -1216,8 +1216,8 @@ static int dspi_init(struct fsl_dspi *dspi)
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
mcr |= SPI_MCR_XSPI;
- if (!spi_controller_is_slave(dspi->ctlr))
- mcr |= SPI_MCR_MASTER;
+ if (!spi_controller_is_target(dspi->ctlr))
+ mcr |= SPI_MCR_HOST;
regmap_write(dspi->regmap, SPI_MCR, mcr);
regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
@@ -1240,13 +1240,13 @@ static int dspi_init(struct fsl_dspi *dspi)
return 0;
}
-static int dspi_slave_abort(struct spi_master *master)
+static int dspi_target_abort(struct spi_controller *host)
{
- struct fsl_dspi *dspi = spi_master_get_devdata(master);
+ struct fsl_dspi *dspi = spi_controller_get_devdata(host);
/*
* Terminate all pending DMA transactions for the SPI working
- * in SLAVE mode.
+ * in TARGET mode.
*/
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
dmaengine_terminate_sync(dspi->dma->chan_rx);
@@ -1277,7 +1277,7 @@ static int dspi_probe(struct platform_device *pdev)
if (!dspi)
return -ENOMEM;
- ctlr = spi_alloc_master(&pdev->dev, 0);
+ ctlr = spi_alloc_host(&pdev->dev, 0);
if (!ctlr)
return -ENOMEM;
@@ -1292,7 +1292,7 @@ static int dspi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->cleanup = dspi_cleanup;
- ctlr->slave_abort = dspi_slave_abort;
+ ctlr->target_abort = dspi_target_abort;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
ctlr->use_gpio_descriptors = true;
@@ -1317,7 +1317,7 @@ static int dspi_probe(struct platform_device *pdev)
ctlr->bus_num = bus_num;
if (of_property_read_bool(np, "spi-slave"))
- ctlr->slave = true;
+ ctlr->target = true;
dspi->devtype_data = of_device_get_match_data(&pdev->dev);
if (!dspi->devtype_data) {
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index b3d2d3db5850..ea647ee94da8 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -148,7 +148,7 @@ static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset,
static int fsl_espi_check_message(struct spi_message *m)
{
- struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(m->spi->controller);
struct spi_transfer *t, *first;
if (m->frame_length > SPCOM_TRANLEN_MAX) {
@@ -323,7 +323,7 @@ start:
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct fsl_espi *espi = spi_master_get_devdata(spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(spi->controller);
int bits_per_word = t ? t->bits_per_word : spi->bits_per_word;
u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz;
struct fsl_espi_cs *cs = spi_get_ctldata(spi);
@@ -351,7 +351,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct fsl_espi *espi = spi_master_get_devdata(spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(spi->controller);
unsigned int rx_len = t->len;
u32 mask, spcom;
int ret;
@@ -396,7 +396,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
{
- struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(m->spi->controller);
struct spi_device *spi = m->spi;
int ret;
@@ -432,7 +432,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
return ret;
}
-static int fsl_espi_do_one_msg(struct spi_master *master,
+static int fsl_espi_do_one_msg(struct spi_controller *host,
struct spi_message *m)
{
unsigned int rx_nbits = 0, delay_nsecs = 0;
@@ -470,7 +470,7 @@ out:
if (m->status == -EINPROGRESS)
m->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return ret;
}
@@ -488,7 +488,7 @@ static int fsl_espi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
}
- espi = spi_master_get_devdata(spi->master);
+ espi = spi_controller_get_devdata(spi->controller);
pm_runtime_get_sync(espi->dev);
@@ -584,8 +584,8 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
#ifdef CONFIG_PM
static int fsl_espi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
u32 regval;
regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
@@ -597,8 +597,8 @@ static int fsl_espi_runtime_suspend(struct device *dev)
static int fsl_espi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
u32 regval;
regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
@@ -616,8 +616,8 @@ static size_t fsl_espi_max_message_size(struct spi_device *spi)
static void fsl_espi_init_regs(struct device *dev, bool initial)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
struct device_node *nc;
u32 csmode, cs, prop;
int ret;
@@ -629,10 +629,10 @@ static void fsl_espi_init_regs(struct device *dev, bool initial)
fsl_espi_write_reg(espi, ESPI_SPIE, 0xffffffff);
/* Init eSPI CS mode register */
- for_each_available_child_of_node(master->dev.of_node, nc) {
+ for_each_available_child_of_node(host->dev.of_node, nc) {
/* get chip select */
ret = of_property_read_u32(nc, "reg", &cs);
- if (ret || cs >= master->num_chipselect)
+ if (ret || cs >= host->num_chipselect)
continue;
csmode = CSMODE_INIT_VAL;
@@ -664,28 +664,28 @@ static void fsl_espi_init_regs(struct device *dev, bool initial)
static int fsl_espi_probe(struct device *dev, struct resource *mem,
unsigned int irq, unsigned int num_cs)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct fsl_espi *espi;
int ret;
- master = spi_alloc_master(dev, sizeof(struct fsl_espi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct fsl_espi));
+ if (!host)
return -ENOMEM;
- dev_set_drvdata(dev, master);
+ dev_set_drvdata(dev, host);
- master->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
- SPI_LSB_FIRST | SPI_LOOP;
- master->dev.of_node = dev->of_node;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
- master->setup = fsl_espi_setup;
- master->cleanup = fsl_espi_cleanup;
- master->transfer_one_message = fsl_espi_do_one_msg;
- master->auto_runtime_pm = true;
- master->max_message_size = fsl_espi_max_message_size;
- master->num_chipselect = num_cs;
+ host->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ SPI_LSB_FIRST | SPI_LOOP;
+ host->dev.of_node = dev->of_node;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ host->setup = fsl_espi_setup;
+ host->cleanup = fsl_espi_cleanup;
+ host->transfer_one_message = fsl_espi_do_one_msg;
+ host->auto_runtime_pm = true;
+ host->max_message_size = fsl_espi_max_message_size;
+ host->num_chipselect = num_cs;
- espi = spi_master_get_devdata(master);
+ espi = spi_controller_get_devdata(host);
spin_lock_init(&espi->lock);
espi->dev = dev;
@@ -696,8 +696,8 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
goto err_probe;
}
/* determined by clock divider fields DIV16/PM in register SPMODEx */
- master->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
- master->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
+ host->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
+ host->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
init_completion(&espi->done);
@@ -720,7 +720,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret < 0)
goto err_pm;
@@ -736,7 +736,7 @@ err_pm:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
err_probe:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
@@ -791,10 +791,10 @@ static void of_fsl_espi_remove(struct platform_device *dev)
#ifdef CONFIG_PM_SLEEP
static int of_fsl_espi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -803,7 +803,7 @@ static int of_fsl_espi_suspend(struct device *dev)
static int of_fsl_espi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
fsl_espi_init_regs(dev, false);
@@ -812,7 +812,7 @@ static int of_fsl_espi_resume(struct device *dev)
if (ret < 0)
return ret;
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 76e1192eb025..885757c29fbb 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -18,7 +18,8 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#ifdef CONFIG_FSL_SOC
#include <sysdev/fsl_soc.h>
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 015a1abb6a84..50a07f984b23 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -103,12 +103,9 @@ extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
struct fsl_spi_platform_data *pdata);
-extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, unsigned int len);
extern const char *mpc8xxx_spi_strmode(unsigned int flags);
extern void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq);
-extern int mpc8xxx_spi_remove(struct device *dev);
extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev);
#endif /* __SPI_FSL_LIB_H__ */
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index fb68c72df171..11991eb12636 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/dma/imx-dma.h>
@@ -73,7 +72,7 @@
#define CFGR1_PINCFG (BIT(24)|BIT(25))
#define CFGR1_PCSPOL BIT(8)
#define CFGR1_NOSTALL BIT(3)
-#define CFGR1_MASTER BIT(0)
+#define CFGR1_HOST BIT(0)
#define FSR_TXCOUNT (0xFF)
#define RSR_RXEMPTY BIT(1)
#define TCR_CPOL BIT(31)
@@ -97,8 +96,7 @@ struct fsl_lpspi_data {
unsigned long base_phys;
struct clk *clk_ipg;
struct clk *clk_per;
- bool is_slave;
- u32 num_cs;
+ bool is_target;
bool is_only_cs1;
bool is_first_byte;
@@ -115,7 +113,7 @@ struct fsl_lpspi_data {
struct lpspi_config config;
struct completion xfer_done;
- bool slave_aborted;
+ bool target_aborted;
/* DMA */
bool usedma;
@@ -236,7 +234,7 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
}
if (txfifo_cnt < fsl_lpspi->txfifosize) {
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
temp &= ~TCR_CONTC;
writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
@@ -260,7 +258,7 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
temp |= fsl_lpspi->config.bpw - 1;
temp |= (fsl_lpspi->config.mode & 0x3) << 30;
temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
temp |= fsl_lpspi->config.prescale << 27;
/*
* Set TCR_CONT will keep SS asserted after current transfer.
@@ -387,7 +385,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
u32 temp;
int ret;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
ret = fsl_lpspi_set_bitrate(fsl_lpspi);
if (ret)
return ret;
@@ -395,8 +393,8 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
fsl_lpspi_set_watermark(fsl_lpspi);
- if (!fsl_lpspi->is_slave)
- temp = CFGR1_MASTER;
+ if (!fsl_lpspi->is_target)
+ temp = CFGR1_HOST;
else
temp = CFGR1_PINCFG;
if (fsl_lpspi->config.mode & SPI_CS_HIGH)
@@ -463,12 +461,12 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
return fsl_lpspi_config(fsl_lpspi);
}
-static int fsl_lpspi_slave_abort(struct spi_controller *controller)
+static int fsl_lpspi_target_abort(struct spi_controller *controller)
{
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
- fsl_lpspi->slave_aborted = true;
+ fsl_lpspi->target_aborted = true;
if (!fsl_lpspi->usedma)
complete(&fsl_lpspi->xfer_done);
else {
@@ -484,9 +482,9 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
- if (fsl_lpspi->is_slave) {
+ if (fsl_lpspi->is_target) {
if (wait_for_completion_interruptible(&fsl_lpspi->xfer_done) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev, "interrupted\n");
return -EINTR;
}
@@ -589,9 +587,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
reinit_completion(&fsl_lpspi->dma_tx_completion);
dma_async_issue_pending(controller->dma_tx);
- fsl_lpspi->slave_aborted = false;
+ fsl_lpspi->target_aborted = false;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
transfer_timeout = fsl_lpspi_calculate_timeout(fsl_lpspi,
transfer->len);
@@ -617,7 +615,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
}
} else {
if (wait_for_completion_interruptible(&fsl_lpspi->dma_tx_completion) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA TX interrupted\n");
dmaengine_terminate_all(controller->dma_tx);
@@ -627,7 +625,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
}
if (wait_for_completion_interruptible(&fsl_lpspi->dma_rx_completion) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA RX interrupted\n");
dmaengine_terminate_all(controller->dma_tx);
@@ -702,7 +700,7 @@ static int fsl_lpspi_pio_transfer(struct spi_controller *controller,
fsl_lpspi->remain = t->len;
reinit_completion(&fsl_lpspi->xfer_done);
- fsl_lpspi->slave_aborted = false;
+ fsl_lpspi->target_aborted = false;
fsl_lpspi_write_tx_fifo(fsl_lpspi);
@@ -826,16 +824,17 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
struct spi_controller *controller;
struct resource *res;
int ret, irq;
+ u32 num_cs;
u32 temp;
- bool is_slave;
+ bool is_target;
- is_slave = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
- if (is_slave)
- controller = spi_alloc_slave(&pdev->dev,
- sizeof(struct fsl_lpspi_data));
+ is_target = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
+ if (is_target)
+ controller = spi_alloc_target(&pdev->dev,
+ sizeof(struct fsl_lpspi_data));
else
- controller = spi_alloc_master(&pdev->dev,
- sizeof(struct fsl_lpspi_data));
+ controller = spi_alloc_host(&pdev->dev,
+ sizeof(struct fsl_lpspi_data));
if (!controller)
return -ENOMEM;
@@ -844,25 +843,9 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
fsl_lpspi = spi_controller_get_devdata(controller);
fsl_lpspi->dev = &pdev->dev;
- fsl_lpspi->is_slave = is_slave;
+ fsl_lpspi->is_target = is_target;
fsl_lpspi->is_only_cs1 = of_property_read_bool((&pdev->dev)->of_node,
"fsl,spi-only-use-cs1-sel");
- if (of_property_read_u32((&pdev->dev)->of_node, "num-cs",
- &fsl_lpspi->num_cs))
- fsl_lpspi->num_cs = 1;
-
- controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
- controller->transfer_one = fsl_lpspi_transfer_one;
- controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
- controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
- controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
- controller->dev.of_node = pdev->dev.of_node;
- controller->bus_num = pdev->id;
- controller->num_chipselect = fsl_lpspi->num_cs;
- controller->slave_abort = fsl_lpspi_slave_abort;
- if (!fsl_lpspi->is_slave)
- controller->use_gpio_descriptors = true;
init_completion(&fsl_lpspi->xfer_done);
@@ -912,6 +895,26 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+ if (of_property_read_u32((&pdev->dev)->of_node, "num-cs",
+ &num_cs)) {
+ if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx93-spi"))
+ num_cs = ((temp >> 16) & 0xf);
+ else
+ num_cs = 1;
+ }
+
+ controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ controller->transfer_one = fsl_lpspi_transfer_one;
+ controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
+ controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
+ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ controller->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+ controller->dev.of_node = pdev->dev.of_node;
+ controller->bus_num = pdev->id;
+ controller->num_chipselect = num_cs;
+ controller->target_abort = fsl_lpspi_target_abort;
+ if (!fsl_lpspi->is_target)
+ controller->use_gpio_descriptors = true;
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
if (ret == -EPROBE_DEFER)
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 8ade61e5ebc0..79bac30e79af 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/sizes.h>
@@ -368,7 +367,7 @@ static int fsl_qspi_check_buswidth(struct fsl_qspi *q, u8 width)
static bool fsl_qspi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
int ret;
ret = fsl_qspi_check_buswidth(q, op->cmd.buswidth);
@@ -641,7 +640,7 @@ static int fsl_qspi_readl_poll_tout(struct fsl_qspi *q, void __iomem *base,
static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
void __iomem *base = q->iobase;
u32 addr_offset = 0;
int err = 0;
@@ -703,7 +702,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int fsl_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
if (op->data.dir == SPI_MEM_DATA_OUT) {
if (op->data.nbytes > q->devtype_data->txfifo)
@@ -809,7 +808,7 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
static const char *fsl_qspi_get_name(struct spi_mem *mem)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = &mem->spi->dev;
const char *name;
@@ -849,7 +848,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct fsl_qspi *q;
int ret;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*q));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*q));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 106fe60a0a50..97faf984801f 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -88,7 +88,7 @@ static int fsl_spi_get_type(struct device *dev)
static void fsl_spi_change_mode(struct spi_device *spi)
{
- struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mspi = spi_controller_get_devdata(spi->controller);
struct spi_mpc8xxx_cs *cs = spi->controller_state;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
__be32 __iomem *mode = &reg_base->mode;
@@ -183,7 +183,7 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
u32 hz = 0;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
if (t) {
bits_per_word = t->bits_per_word;
@@ -252,7 +252,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
bool is_dma_mapped)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base;
unsigned int len = t->len;
u8 bits_per_word;
@@ -385,7 +385,7 @@ static int fsl_spi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
initial_setup = true;
}
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
reg_base = mpc8xxx_spi->reg_base;
@@ -479,7 +479,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
u32 slvsel;
u16 cs = spi_get_chipselect(spi, 0);
@@ -493,8 +493,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
static void fsl_spi_grlib_probe(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
int mbits;
u32 capabilities;
@@ -511,8 +511,8 @@ static void fsl_spi_grlib_probe(struct device *dev)
mpc8xxx_spi->native_chipselects = SPCAP_SSSZ(capabilities);
mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
- master->num_chipselect = mpc8xxx_spi->native_chipselects;
- master->set_cs = fsl_spi_grlib_cs_control;
+ host->num_chipselect = mpc8xxx_spi->native_chipselects;
+ host->set_cs = fsl_spi_grlib_cs_control;
}
static void fsl_spi_cs_control(struct spi_device *spi, bool on)
@@ -526,35 +526,35 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on)
iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
}
-static struct spi_master *fsl_spi_probe(struct device *dev,
+static struct spi_controller *fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct spi_master *master;
+ struct spi_controller *host;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg __iomem *reg_base;
u32 regval;
int ret = 0;
- master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
- if (master == NULL) {
+ host = spi_alloc_host(dev, sizeof(struct mpc8xxx_spi));
+ if (host == NULL) {
ret = -ENOMEM;
goto err;
}
- dev_set_drvdata(dev, master);
+ dev_set_drvdata(dev, host);
mpc8xxx_spi_probe(dev, mem, irq);
- master->setup = fsl_spi_setup;
- master->cleanup = fsl_spi_cleanup;
- master->prepare_message = fsl_spi_prepare_message;
- master->transfer_one = fsl_spi_transfer_one;
- master->unprepare_message = fsl_spi_unprepare_message;
- master->use_gpio_descriptors = true;
- master->set_cs = fsl_spi_cs_control;
+ host->setup = fsl_spi_setup;
+ host->cleanup = fsl_spi_cleanup;
+ host->prepare_message = fsl_spi_prepare_message;
+ host->transfer_one = fsl_spi_transfer_one;
+ host->unprepare_message = fsl_spi_unprepare_message;
+ host->use_gpio_descriptors = true;
+ host->set_cs = fsl_spi_cs_control;
- mpc8xxx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi = spi_controller_get_devdata(host);
mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev);
@@ -572,13 +572,13 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
fsl_spi_grlib_probe(dev);
if (mpc8xxx_spi->flags & SPI_CPM_MODE)
- master->bits_per_word_mask =
+ host->bits_per_word_mask =
(SPI_BPW_RANGE_MASK(4, 8) | SPI_BPW_MASK(16) | SPI_BPW_MASK(32));
else
- master->bits_per_word_mask =
+ host->bits_per_word_mask =
(SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32));
- master->bits_per_word_mask &=
+ host->bits_per_word_mask &=
SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
@@ -615,19 +615,19 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret < 0)
goto err_probe;
dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
- return master;
+ return host;
err_probe:
fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init:
- spi_master_put(master);
+ spi_controller_put(host);
err:
return ERR_PTR(ret);
}
@@ -636,7 +636,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource mem;
int irq, type;
int ret;
@@ -689,9 +689,9 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
goto unmap_out;
}
- master = fsl_spi_probe(dev, &mem, irq);
+ host = fsl_spi_probe(dev, &mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ return PTR_ERR_OR_ZERO(host);
unmap_out:
#if IS_ENABLED(CONFIG_FSL_SOC)
@@ -703,8 +703,8 @@ unmap_out:
static void of_fsl_spi_remove(struct platform_device *ofdev)
{
- struct spi_master *master = platform_get_drvdata(ofdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(ofdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
}
@@ -730,7 +730,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
int irq;
- struct spi_master *master;
+ struct spi_controller *host;
if (!dev_get_platdata(&pdev->dev))
return -EINVAL;
@@ -740,17 +740,17 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq < 0)
+ return irq;
- master = fsl_spi_probe(&pdev->dev, mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ host = fsl_spi_probe(&pdev->dev, mem, irq);
+ return PTR_ERR_OR_ZERO(host);
}
static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
}
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 1df9d4844a68..f4f376a8351b 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/soc/qcom/geni-se.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
@@ -52,6 +53,9 @@
#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10)
#define SPI_CS_CLK_DELAY_SHFT 10
+#define SE_SPI_SLAVE_EN (0x2BC)
+#define SPI_SLAVE_EN BIT(0)
+
/* M_CMD OP codes for SPI */
#define SPI_TX_ONLY 1
#define SPI_RX_ONLY 2
@@ -99,6 +103,16 @@ struct spi_geni_master {
int cur_xfer_mode;
};
+static void spi_slv_setup(struct spi_geni_master *mas)
+{
+ struct geni_se *se = &mas->se;
+
+ writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN);
+ writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL);
+ writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START);
+ dev_dbg(mas->dev, "spi slave setup done\n");
+}
+
static int get_spi_clk_cfg(unsigned int speed_hz,
struct spi_geni_master *mas,
unsigned int *clk_idx,
@@ -140,12 +154,22 @@ static void handle_se_timeout(struct spi_master *spi,
const struct spi_transfer *xfer;
spin_lock_irq(&mas->lock);
- reinit_completion(&mas->cancel_done);
if (mas->cur_xfer_mode == GENI_SE_FIFO)
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
xfer = mas->cur_xfer;
mas->cur_xfer = NULL;
+
+ if (spi->slave) {
+ /*
+ * skip CMD Cancel sequnece since spi slave
+ * doesn`t support CMD Cancel sequnece
+ */
+ spin_unlock_irq(&mas->lock);
+ goto unmap_if_dma;
+ }
+
+ reinit_completion(&mas->cancel_done);
geni_se_cancel_m_cmd(se);
spin_unlock_irq(&mas->lock);
@@ -542,6 +566,10 @@ static bool geni_can_dma(struct spi_controller *ctlr,
if (mas->cur_xfer_mode == GENI_GPI_DMA)
return true;
+ /* Set SE DMA mode for SPI slave. */
+ if (ctlr->slave)
+ return true;
+
len = get_xfer_len_in_words(xfer, mas);
fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
@@ -619,6 +647,7 @@ static void spi_geni_release_dma_chan(struct spi_geni_master *mas)
static int spi_geni_init(struct spi_geni_master *mas)
{
+ struct spi_master *spi = dev_get_drvdata(mas->dev);
struct geni_se *se = &mas->se;
unsigned int proto, major, minor, ver;
u32 spi_tx_cfg, fifo_disable;
@@ -627,7 +656,14 @@ static int spi_geni_init(struct spi_geni_master *mas)
pm_runtime_get_sync(mas->dev);
proto = geni_se_read_proto(se);
- if (proto != GENI_SE_SPI) {
+
+ if (spi->slave) {
+ if (proto != GENI_SE_SPI_SLAVE) {
+ dev_err(mas->dev, "Invalid proto %d\n", proto);
+ goto out_pm;
+ }
+ spi_slv_setup(mas);
+ } else if (proto != GENI_SE_SPI) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
goto out_pm;
}
@@ -679,9 +715,11 @@ static int spi_geni_init(struct spi_geni_master *mas)
}
/* We always control CS manually */
- spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
- spi_tx_cfg &= ~CS_TOGGLE;
- writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+ if (!spi->slave) {
+ spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
+ spi_tx_cfg &= ~CS_TOGGLE;
+ writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+ }
out_pm:
pm_runtime_put(mas->dev);
@@ -1074,6 +1112,9 @@ static int spi_geni_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
pm_runtime_enable(dev);
+ if (device_property_read_bool(&pdev->dev, "spi-slave"))
+ spi->slave = true;
+
ret = geni_icc_get(&mas->se, NULL);
if (ret)
goto spi_geni_probe_runtime_disable;
@@ -1094,7 +1135,7 @@ static int spi_geni_probe(struct platform_device *pdev)
* for dma (gsi) mode, the gsi will set cs based on params passed in
* TRE
*/
- if (mas->cur_xfer_mode == GENI_SE_FIFO)
+ if (!spi->slave && mas->cur_xfer_mode == GENI_SE_FIFO)
spi->set_cs = spi_geni_set_cs;
/*
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 092afc7679d4..d8db4564b406 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * SPI master driver using generic bitbanged GPIO
+ * SPI host driver using generic bitbanged GPIO
*
* Copyright (C) 2006,2008 David Brownell
* Copyright (C) 2017 Linus Walleij
@@ -10,7 +10,6 @@
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -18,7 +17,7 @@
/*
- * This bitbanging SPI master driver should help make systems usable
+ * This bitbanging SPI host driver should help make systems usable
* when a native hardware SPI engine is not available, perhaps because
* its driver isn't yet working or because the I/O pins it requires
* are used for other purposes.
@@ -27,7 +26,7 @@
*
* spi->controller_state ... reserved for bitbang framework code
*
- * spi->master->dev.driver_data ... points to spi_gpio->bitbang
+ * spi->controller->dev.driver_data ... points to spi_gpio->bitbang
*/
struct spi_gpio {
@@ -78,7 +77,7 @@ spi_to_spi_gpio(const struct spi_device *spi)
const struct spi_bitbang *bang;
struct spi_gpio *spi_gpio;
- bang = spi_master_get_devdata(spi->master);
+ bang = spi_controller_get_devdata(spi->controller);
spi_gpio = container_of(bang, struct spi_gpio, bitbang);
return spi_gpio;
}
@@ -170,7 +169,7 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
/*
* These functions do not call setmosi or getmiso if respective flag
- * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to
+ * (SPI_CONTROLLER_NO_RX or SPI_CONTROLLER_NO_TX) is set, so they are safe to
* call when such pin is not present or defined in the controller.
* A separate set of callbacks is defined to get highest possible
* speed in the generic case (when both MISO and MOSI lines are
@@ -181,7 +180,7 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits);
else
@@ -191,7 +190,7 @@ static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits);
else
@@ -201,7 +200,7 @@ static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits);
else
@@ -211,7 +210,7 @@ static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits);
else
@@ -311,7 +310,7 @@ static void spi_gpio_cleanup(struct spi_device *spi)
* On platforms which can do so, configure MISO with a weak pullup unless
* there's an external pullup on that signal. That saves power by avoiding
* floating signals. (A weak pulldown would save power too, but many
- * drivers expect to see all-ones data as the no slave "response".)
+ * drivers expect to see all-ones data as the no target "response".)
*/
static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio)
{
@@ -335,27 +334,27 @@ static const struct of_device_id spi_gpio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
static int spi_gpio_probe_dt(struct platform_device *pdev,
- struct spi_master *master)
+ struct spi_controller *host)
{
- master->dev.of_node = pdev->dev.of_node;
- master->use_gpio_descriptors = true;
+ host->dev.of_node = pdev->dev.of_node;
+ host->use_gpio_descriptors = true;
return 0;
}
#else
static inline int spi_gpio_probe_dt(struct platform_device *pdev,
- struct spi_master *master)
+ struct spi_controller *host)
{
return 0;
}
#endif
static int spi_gpio_probe_pdata(struct platform_device *pdev,
- struct spi_master *master)
+ struct spi_controller *host)
{
struct device *dev = &pdev->dev;
struct spi_gpio_platform_data *pdata = dev_get_platdata(dev);
- struct spi_gpio *spi_gpio = spi_master_get_devdata(master);
+ struct spi_gpio *spi_gpio = spi_controller_get_devdata(host);
int i;
#ifdef GENERIC_BITBANG
@@ -363,18 +362,18 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev,
return -ENODEV;
#endif
/*
- * The master needs to think there is a chipselect even if not
+ * The host needs to think there is a chipselect even if not
* connected
*/
- master->num_chipselect = pdata->num_chipselect ?: 1;
+ host->num_chipselect = pdata->num_chipselect ?: 1;
- spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect,
+ spi_gpio->cs_gpios = devm_kcalloc(dev, host->num_chipselect,
sizeof(*spi_gpio->cs_gpios),
GFP_KERNEL);
if (!spi_gpio->cs_gpios)
return -ENOMEM;
- for (i = 0; i < master->num_chipselect; i++) {
+ for (i = 0; i < host->num_chipselect; i++) {
spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", i,
GPIOD_OUT_HIGH);
if (IS_ERR(spi_gpio->cs_gpios[i]))
@@ -387,58 +386,58 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev,
static int spi_gpio_probe(struct platform_device *pdev)
{
int status;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_gpio *spi_gpio;
struct device *dev = &pdev->dev;
struct spi_bitbang *bb;
- master = devm_spi_alloc_master(dev, sizeof(*spi_gpio));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*spi_gpio));
+ if (!host)
return -ENOMEM;
if (pdev->dev.of_node)
- status = spi_gpio_probe_dt(pdev, master);
+ status = spi_gpio_probe_dt(pdev, host);
else
- status = spi_gpio_probe_pdata(pdev, master);
+ status = spi_gpio_probe_pdata(pdev, host);
if (status)
return status;
- spi_gpio = spi_master_get_devdata(master);
+ spi_gpio = spi_controller_get_devdata(host);
status = spi_gpio_request(dev, spi_gpio);
if (status)
return status;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL |
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL |
SPI_CS_HIGH | SPI_LSB_FIRST;
if (!spi_gpio->mosi) {
/* HW configuration without MOSI pin
*
- * No setting SPI_MASTER_NO_RX here - if there is only
+ * No setting SPI_CONTROLLER_NO_RX here - if there is only
* a MOSI pin connected the host can still do RX by
* changing the direction of the line.
*/
- master->flags = SPI_MASTER_NO_TX;
+ host->flags = SPI_CONTROLLER_NO_TX;
}
- master->bus_num = pdev->id;
- master->setup = spi_gpio_setup;
- master->cleanup = spi_gpio_cleanup;
+ host->bus_num = pdev->id;
+ host->setup = spi_gpio_setup;
+ host->cleanup = spi_gpio_cleanup;
bb = &spi_gpio->bitbang;
- bb->master = master;
+ bb->master = host;
/*
* There is some additional business, apart from driving the CS GPIO
* line, that we need to do on selection. This makes the local
* callback for chipselect always get called.
*/
- master->flags |= SPI_MASTER_GPIO_SS;
+ host->flags |= SPI_CONTROLLER_GPIO_SS;
bb->chipselect = spi_gpio_chipselect;
bb->set_line_direction = spi_gpio_set_direction;
- if (master->flags & SPI_MASTER_NO_TX) {
+ if (host->flags & SPI_CONTROLLER_NO_TX) {
bb->txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
bb->txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;
bb->txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;
@@ -455,7 +454,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
if (status)
return status;
- return devm_spi_register_master(&pdev->dev, master);
+ return devm_spi_register_controller(&pdev->dev, host);
}
MODULE_ALIAS("platform:" DRIVER_NAME);
@@ -469,6 +468,6 @@ static struct platform_driver spi_gpio_driver = {
};
module_platform_driver(spi_gpio_driver);
-MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO ");
+MODULE_DESCRIPTION("SPI host driver using generic bitbanged GPIO ");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c
index 684d63f402f3..fd2fac236bbd 100644
--- a/drivers/spi/spi-gxp.c
+++ b/drivers/spi/spi-gxp.c
@@ -3,7 +3,6 @@
#include <linux/iopoll.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -200,7 +199,7 @@ static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op
static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->master);
+ struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->controller);
struct gxp_spi_chip *chip = &spifi->chips[spi_get_chipselect(mem->spi, 0)];
int ret;
@@ -236,7 +235,7 @@ static const struct spi_controller_mem_ops gxp_spi_mem_ops = {
static int gxp_spi_setup(struct spi_device *spi)
{
- struct gxp_spi *spifi = spi_controller_get_devdata(spi->master);
+ struct gxp_spi *spifi = spi_controller_get_devdata(spi->controller);
unsigned int cs = spi_get_chipselect(spi, 0);
struct gxp_spi_chip *chip = &spifi->chips[cs];
@@ -258,7 +257,7 @@ static int gxp_spifi_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- ctlr = devm_spi_alloc_master(dev, sizeof(*spifi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*spifi));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c
index 2b4b3d2a22b8..35ef5e8e2ffd 100644
--- a/drivers/spi/spi-hisi-kunpeng.c
+++ b/drivers/spi/spi-hisi-kunpeng.c
@@ -164,10 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
{
char name[32];
- struct spi_controller *master;
+ struct spi_controller *host;
- master = container_of(hs->dev, struct spi_controller, dev);
- snprintf(name, 32, "hisi_spi%d", master->bus_num);
+ host = container_of(hs->dev, struct spi_controller, dev);
+ snprintf(name, 32, "hisi_spi%d", host->bus_num);
hs->debugfs = debugfs_create_dir(name, NULL);
if (IS_ERR(hs->debugfs))
return -ENOMEM;
@@ -291,18 +291,18 @@ static void __hisi_calc_div_reg(struct hisi_chip_data *chip)
chip->div_post = (chip->clk_div / chip->div_pre) - 1;
}
-static u32 hisi_calc_effective_speed(struct spi_controller *master,
+static u32 hisi_calc_effective_speed(struct spi_controller *host,
struct hisi_chip_data *chip, u32 speed_hz)
{
u32 effective_speed;
/* Note clock divider doesn't support odd numbers */
- chip->clk_div = DIV_ROUND_UP(master->max_speed_hz, speed_hz) + 1;
+ chip->clk_div = DIV_ROUND_UP(host->max_speed_hz, speed_hz) + 1;
chip->clk_div &= 0xfffe;
if (chip->clk_div > CLK_DIV_MAX)
chip->clk_div = CLK_DIV_MAX;
- effective_speed = master->max_speed_hz / chip->clk_div;
+ effective_speed = host->max_speed_hz / chip->clk_div;
if (chip->speed_hz != effective_speed) {
__hisi_calc_div_reg(chip);
chip->speed_hz = effective_speed;
@@ -336,20 +336,20 @@ static void hisi_spi_hw_init(struct hisi_spi *hs)
static irqreturn_t hisi_spi_irq(int irq, void *dev_id)
{
- struct spi_controller *master = dev_id;
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK;
if (!irq_status)
return IRQ_NONE;
- if (!master->cur_msg)
+ if (!host->cur_msg)
return IRQ_HANDLED;
/* Error handling */
if (irq_status & ISR_RXOF) {
dev_err(hs->dev, "interrupt_transfer: fifo overflow\n");
- master->cur_msg->status = -EIO;
+ host->cur_msg->status = -EIO;
goto finalize_transfer;
}
@@ -369,20 +369,20 @@ static irqreturn_t hisi_spi_irq(int irq, void *dev_id)
finalize_transfer:
hisi_spi_disable(hs);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
-static int hisi_spi_transfer_one(struct spi_controller *master,
+static int hisi_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *transfer)
{
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
struct hisi_chip_data *chip = spi_get_ctldata(spi);
u32 cr = chip->cr;
/* Update per transfer options for speed and bpw */
transfer->effective_speed_hz =
- hisi_calc_effective_speed(master, chip, transfer->speed_hz);
+ hisi_calc_effective_speed(host, chip, transfer->speed_hz);
cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre);
cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post);
cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1);
@@ -409,10 +409,10 @@ static int hisi_spi_transfer_one(struct spi_controller *master,
return 1;
}
-static void hisi_spi_handle_err(struct spi_controller *master,
+static void hisi_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
hisi_spi_disable(hs);
@@ -452,7 +452,7 @@ static void hisi_spi_cleanup(struct spi_device *spi)
static int hisi_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_controller *master;
+ struct spi_controller *host;
struct hisi_spi *hs;
int ret, irq;
@@ -460,13 +460,13 @@ static int hisi_spi_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- master = devm_spi_alloc_master(dev, sizeof(*hs));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*hs));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- hs = spi_controller_get_devdata(master);
+ hs = spi_controller_get_devdata(host);
hs->dev = dev;
hs->irq = irq;
@@ -474,9 +474,9 @@ static int hisi_spi_probe(struct platform_device *pdev)
if (IS_ERR(hs->regs))
return PTR_ERR(hs->regs);
- /* Specify maximum SPI clocking speed (master only) by firmware */
+ /* Specify maximum SPI clocking speed (host only) by firmware */
ret = device_property_read_u32(dev, "spi-max-frequency",
- &master->max_speed_hz);
+ &host->max_speed_hz);
if (ret) {
dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n",
ret);
@@ -484,32 +484,32 @@ static int hisi_spi_probe(struct platform_device *pdev)
}
ret = device_property_read_u16(dev, "num-cs",
- &master->num_chipselect);
+ &host->num_chipselect);
if (ret)
- master->num_chipselect = DEFAULT_NUM_CS;
-
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->bus_num = pdev->id;
- master->setup = hisi_spi_setup;
- master->cleanup = hisi_spi_cleanup;
- master->transfer_one = hisi_spi_transfer_one;
- master->handle_err = hisi_spi_handle_err;
- master->dev.fwnode = dev->fwnode;
+ host->num_chipselect = DEFAULT_NUM_CS;
+
+ host->use_gpio_descriptors = true;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->bus_num = pdev->id;
+ host->setup = hisi_spi_setup;
+ host->cleanup = hisi_spi_cleanup;
+ host->transfer_one = hisi_spi_transfer_one;
+ host->handle_err = hisi_spi_handle_err;
+ host->dev.fwnode = dev->fwnode;
hisi_spi_hw_init(hs);
ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev),
- master);
+ host);
if (ret < 0) {
dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret);
return ret;
}
- ret = spi_register_controller(master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err(dev, "failed to register spi master, ret=%d\n", ret);
+ dev_err(dev, "failed to register spi host, ret=%d\n", ret);
return ret;
}
@@ -518,18 +518,18 @@ static int hisi_spi_probe(struct platform_device *pdev)
dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
readl(hs->regs + HISI_SPI_VERSION),
- master->max_speed_hz / 1000);
+ host->max_speed_hz / 1000);
return 0;
}
static void hisi_spi_remove(struct platform_device *pdev)
{
- struct spi_controller *master = platform_get_drvdata(pdev);
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
debugfs_remove_recursive(hs->debugfs);
- spi_unregister_controller(master);
+ spi_unregister_controller(host);
}
static const struct acpi_device_id hisi_spi_acpi_match[] = {
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c
index 7cbcb065bb44..9d22018f7985 100644
--- a/drivers/spi/spi-hisi-sfc-v3xx.c
+++ b/drivers/spi/spi-hisi-sfc-v3xx.c
@@ -152,7 +152,7 @@ static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
uintptr_t addr = (uintptr_t)op->data.buf.in;
int max_byte_count;
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
max_byte_count = host->max_cmd_dword * 4;
@@ -174,7 +174,7 @@ static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem,
struct spi_device *spi = mem->spi;
struct hisi_sfc_v3xx_host *host;
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
if (op->data.buswidth > 4 || op->dummy.buswidth > 4 ||
op->addr.buswidth > 4 || op->cmd.buswidth > 4)
@@ -363,7 +363,7 @@ static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem,
struct spi_device *spi = mem->spi;
u8 chip_select = spi_get_chipselect(spi, 0);
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select);
}
@@ -431,7 +431,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
u32 version, glb_config;
int ret;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*host));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*host));
if (!ctlr)
return -ENOMEM;
@@ -448,13 +448,13 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
host->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->regbase)) {
ret = PTR_ERR(host->regbase);
- goto err_put_master;
+ goto err_put_host;
}
host->irq = platform_get_irq_optional(pdev, 0);
if (host->irq == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_put_master;
+ goto err_put_host;
}
hisi_sfc_v3xx_disable_int(host);
@@ -496,15 +496,15 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(dev, ctlr);
if (ret)
- goto err_put_master;
+ goto err_put_host;
dev_info(&pdev->dev, "hw version 0x%x, %s mode.\n",
version, host->irq ? "irq" : "polling");
return 0;
-err_put_master:
- spi_master_put(ctlr);
+err_put_host:
+ spi_controller_put(ctlr);
return ret;
}
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index d775f87770e3..d8360f94d3b7 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -86,7 +86,7 @@
struct img_spfi {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
spinlock_t lock;
void __iomem *regs;
@@ -221,11 +221,11 @@ static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf,
return count;
}
-static int img_spfi_start_pio(struct spi_master *master,
+static int img_spfi_start_pio(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
unsigned int tx_bytes = 0, rx_bytes = 0;
const void *tx_buf = xfer->tx_buf;
void *rx_buf = xfer->rx_buf;
@@ -285,7 +285,7 @@ static void img_spfi_dma_rx_cb(void *data)
spin_lock_irqsave(&spfi->lock, flags);
spfi->rx_dma_busy = false;
if (!spfi->tx_dma_busy)
- spi_finalize_current_transfer(spfi->master);
+ spi_finalize_current_transfer(spfi->host);
spin_unlock_irqrestore(&spfi->lock, flags);
}
@@ -299,15 +299,15 @@ static void img_spfi_dma_tx_cb(void *data)
spin_lock_irqsave(&spfi->lock, flags);
spfi->tx_dma_busy = false;
if (!spfi->rx_dma_busy)
- spi_finalize_current_transfer(spfi->master);
+ spi_finalize_current_transfer(spfi->host);
spin_unlock_irqrestore(&spfi->lock, flags);
}
-static int img_spfi_start_dma(struct spi_master *master,
+static int img_spfi_start_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
struct dma_slave_config rxconf, txconf;
@@ -384,10 +384,10 @@ stop_dma:
return -EIO;
}
-static void img_spfi_handle_err(struct spi_master *master,
+static void img_spfi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
unsigned long flags;
/*
@@ -405,9 +405,9 @@ static void img_spfi_handle_err(struct spi_master *master,
spin_unlock_irqrestore(&spfi->lock, flags);
}
-static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
+static int img_spfi_prepare(struct spi_controller *host, struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
@@ -427,20 +427,20 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
return 0;
}
-static int img_spfi_unprepare(struct spi_master *master,
+static int img_spfi_unprepare(struct spi_controller *host,
struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
spfi_reset(spfi);
return 0;
}
-static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
+static void img_spfi_config(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
u32 val, div;
/*
@@ -476,11 +476,11 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
spfi_writel(spfi, val, SPFI_CONTROL);
}
-static int img_spfi_transfer_one(struct spi_master *master,
+static int img_spfi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
int ret;
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
@@ -490,16 +490,16 @@ static int img_spfi_transfer_one(struct spi_master *master,
return -EINVAL;
}
- img_spfi_config(master, spi, xfer);
- if (master->can_dma && master->can_dma(master, spi, xfer))
- ret = img_spfi_start_dma(master, spi, xfer);
+ img_spfi_config(host, spi, xfer);
+ if (host->can_dma && host->can_dma(host, spi, xfer))
+ ret = img_spfi_start_dma(host, spi, xfer);
else
- ret = img_spfi_start_pio(master, spi, xfer);
+ ret = img_spfi_start_pio(host, spi, xfer);
return ret;
}
-static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
+static bool img_spfi_can_dma(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
if (xfer->len > SPFI_32BIT_FIFO_SIZE)
@@ -524,20 +524,20 @@ static irqreturn_t img_spfi_irq(int irq, void *dev_id)
static int img_spfi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct img_spfi *spfi;
struct resource *res;
int ret;
u32 max_speed_hz;
- master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*spfi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- spfi = spi_master_get_devdata(master);
+ spfi = spi_controller_get_devdata(host);
spfi->dev = &pdev->dev;
- spfi->master = master;
+ spfi->host = host;
spin_lock_init(&spfi->lock);
spfi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
@@ -582,15 +582,15 @@ static int img_spfi_probe(struct platform_device *pdev)
*/
spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE);
- master->auto_runtime_pm = true;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
+ host->auto_runtime_pm = true;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
- master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
- master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
- master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
- master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
+ host->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
+ host->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
+ host->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
/*
* Maximum speed supported by spfi is limited to the lower value
@@ -601,15 +601,15 @@ static int img_spfi_probe(struct platform_device *pdev)
*/
if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency",
&max_speed_hz)) {
- if (master->max_speed_hz > max_speed_hz)
- master->max_speed_hz = max_speed_hz;
+ if (host->max_speed_hz > max_speed_hz)
+ host->max_speed_hz = max_speed_hz;
}
- master->transfer_one = img_spfi_transfer_one;
- master->prepare_message = img_spfi_prepare;
- master->unprepare_message = img_spfi_unprepare;
- master->handle_err = img_spfi_handle_err;
- master->use_gpio_descriptors = true;
+ host->transfer_one = img_spfi_transfer_one;
+ host->prepare_message = img_spfi_prepare;
+ host->unprepare_message = img_spfi_unprepare;
+ host->handle_err = img_spfi_handle_err;
+ host->use_gpio_descriptors = true;
spfi->tx_ch = dma_request_chan(spfi->dev, "tx");
if (IS_ERR(spfi->tx_ch)) {
@@ -636,15 +636,15 @@ static int img_spfi_probe(struct platform_device *pdev)
spfi->rx_ch = NULL;
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
} else {
- master->dma_tx = spfi->tx_ch;
- master->dma_rx = spfi->rx_ch;
- master->can_dma = img_spfi_can_dma;
+ host->dma_tx = spfi->tx_ch;
+ host->dma_rx = spfi->rx_ch;
+ host->can_dma = img_spfi_can_dma;
}
pm_runtime_set_active(spfi->dev);
pm_runtime_enable(spfi->dev);
- ret = devm_spi_register_master(spfi->dev, master);
+ ret = devm_spi_register_controller(spfi->dev, host);
if (ret)
goto disable_pm;
@@ -660,15 +660,15 @@ disable_pm:
disable_pclk:
clk_disable_unprepare(spfi->sys_clk);
put_spi:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void img_spfi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
if (spfi->tx_ch)
dma_release_channel(spfi->tx_ch);
@@ -685,8 +685,8 @@ static void img_spfi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int img_spfi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
clk_disable_unprepare(spfi->spfi_clk);
clk_disable_unprepare(spfi->sys_clk);
@@ -696,8 +696,8 @@ static int img_spfi_runtime_suspend(struct device *dev)
static int img_spfi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(spfi->sys_clk);
@@ -716,15 +716,15 @@ static int img_spfi_runtime_resume(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int img_spfi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int img_spfi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -733,7 +733,7 @@ static int img_spfi_resume(struct device *dev)
spfi_reset(spfi);
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 528ae46c087f..a8a74c7cb79f 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -20,7 +20,6 @@
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/dma/imx-dma.h>
@@ -53,7 +52,7 @@ MODULE_PARM_DESC(polling_limit_us,
/* The maximum bytes that a sdma BD can transfer. */
#define MAX_SDMA_BD_BYTES (1 << 15)
#define MX51_ECSPI_CTRL_MAX_BURST 512
-/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
+/* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
#define MX53_MAX_TRANSFER_BYTES 512
enum spi_imx_devtype {
@@ -78,7 +77,7 @@ struct spi_imx_devtype_data {
void (*setup_wml)(struct spi_imx_data *spi_imx);
void (*disable)(struct spi_imx_data *spi_imx);
bool has_dmamode;
- bool has_slavemode;
+ bool has_targetmode;
unsigned int fifo_size;
bool dynamic_burst;
/*
@@ -114,10 +113,10 @@ struct spi_imx_data {
unsigned int dynamic_burst;
bool rx_only;
- /* Slave mode */
- bool slave_mode;
- bool slave_aborted;
- unsigned int slave_burst;
+ /* Target mode */
+ bool target_mode;
+ bool target_aborted;
+ unsigned int target_burst;
/* DMA */
bool usedma;
@@ -241,7 +240,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
if (!controller->dma_rx)
return false;
- if (spi_imx->slave_mode)
+ if (spi_imx->target_mode)
return false;
if (transfer->len < spi_imx->devtype_data->fifo_size)
@@ -405,12 +404,12 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
writel(val, spi_imx->base + MXC_CSPITXDATA);
}
-static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
+static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx)
{
u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
if (spi_imx->rx_buf) {
- int n_bytes = spi_imx->slave_burst % sizeof(val);
+ int n_bytes = spi_imx->target_burst % sizeof(val);
if (!n_bytes)
n_bytes = sizeof(val);
@@ -419,13 +418,13 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
spi_imx->rx_buf += n_bytes;
- spi_imx->slave_burst -= n_bytes;
+ spi_imx->target_burst -= n_bytes;
}
spi_imx->remainder -= sizeof(u32);
}
-static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
+static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
{
u32 val = 0;
int n_bytes = spi_imx->count % sizeof(val);
@@ -536,8 +535,8 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
u32 current_cfg = cfg;
int channel = mx51_ecspi_channel(spi);
- /* set Master or Slave mode */
- if (spi_imx->slave_mode)
+ /* set Host or Target mode */
+ if (spi_imx->target_mode)
ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
else
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
@@ -565,11 +564,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
/*
- * eCSPI burst completion by Chip Select signal in Slave mode
+ * eCSPI burst completion by Chip Select signal in Target mode
* is not functional for imx53 Soc, config SPI burst completed when
* BURST_LENGTH + 1 bits are received
*/
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ if (spi_imx->target_mode && is_imx53_ecspi(spi_imx))
cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel);
else
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel);
@@ -656,12 +655,16 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
/* Clear BL field and set the right value */
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
- ctrl |= (spi_imx->slave_burst * 8 - 1)
- << MX51_ECSPI_CTRL_BL_OFFSET;
- else
- ctrl |= (spi_imx->bits_per_word - 1)
+ if (spi_imx->target_mode && is_imx53_ecspi(spi_imx))
+ ctrl |= (spi_imx->target_burst * 8 - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
+ else {
+ if (spi_imx->count >= 512)
+ ctrl |= 0xFFF << MX51_ECSPI_CTRL_BL_OFFSET;
+ else
+ ctrl |= (spi_imx->count*8 - 1)
+ << MX51_ECSPI_CTRL_BL_OFFSET;
+ }
/* set clock speed */
ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
@@ -718,7 +721,7 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx)
#define MX31_INTREG_RREN (1 << 3)
#define MX31_CSPICTRL_ENABLE (1 << 0)
-#define MX31_CSPICTRL_MASTER (1 << 1)
+#define MX31_CSPICTRL_HOST (1 << 1)
#define MX31_CSPICTRL_XCH (1 << 2)
#define MX31_CSPICTRL_SMC (1 << 3)
#define MX31_CSPICTRL_POL (1 << 4)
@@ -775,7 +778,7 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx,
static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
{
- unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
+ unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
@@ -845,7 +848,7 @@ static void mx31_reset(struct spi_imx_data *spi_imx)
#define MX21_CSPICTRL_SSPOL (1 << 8)
#define MX21_CSPICTRL_XCH (1 << 9)
#define MX21_CSPICTRL_ENABLE (1 << 10)
-#define MX21_CSPICTRL_MASTER (1 << 11)
+#define MX21_CSPICTRL_HOST (1 << 11)
#define MX21_CSPICTRL_DR_SHIFT 14
#define MX21_CSPICTRL_CS_SHIFT 19
@@ -879,7 +882,7 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx,
static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
{
- unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
+ unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST;
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
unsigned int clk;
@@ -921,7 +924,7 @@ static void mx21_reset(struct spi_imx_data *spi_imx)
#define MX1_CSPICTRL_PHA (1 << 5)
#define MX1_CSPICTRL_XCH (1 << 8)
#define MX1_CSPICTRL_ENABLE (1 << 9)
-#define MX1_CSPICTRL_MASTER (1 << 10)
+#define MX1_CSPICTRL_HOST (1 << 10)
#define MX1_CSPICTRL_DR_SHIFT 13
static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
@@ -954,7 +957,7 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx,
static int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
{
- unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
+ unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
@@ -993,7 +996,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX1_CSPI,
};
@@ -1007,7 +1010,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX21_CSPI,
};
@@ -1022,7 +1025,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX27_CSPI,
};
@@ -1036,7 +1039,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX31_CSPI,
};
@@ -1051,7 +1054,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = true,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX35_CSPI,
};
@@ -1066,7 +1069,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
};
@@ -1080,7 +1083,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX53_ECSPI,
};
@@ -1096,7 +1099,7 @@ static struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = {
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.tx_glitch_fixed = true,
.disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
@@ -1161,7 +1164,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
spi_imx->txfifo++;
}
- if (!spi_imx->slave_mode)
+ if (!spi_imx->target_mode)
spi_imx->devtype_data->trigger(spi_imx);
}
@@ -1258,13 +1261,14 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->spi_bus_clk = t->speed_hz;
spi_imx->bits_per_word = t->bits_per_word;
+ spi_imx->count = t->len;
/*
* Initialize the functions for transfer. To transfer non byte-aligned
* words, we have to use multiple word-size bursts, we can't use
* dynamic_burst in that case.
*/
- if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode &&
+ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode &&
!(spi->mode & SPI_CS_WORD) &&
(spi_imx->bits_per_word == 8 ||
spi_imx->bits_per_word == 16 ||
@@ -1296,10 +1300,10 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->rx_only = ((t->tx_buf == NULL)
|| (t->tx_buf == spi->controller->dummy_tx));
- if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
- spi_imx->rx = mx53_ecspi_rx_slave;
- spi_imx->tx = mx53_ecspi_tx_slave;
- spi_imx->slave_burst = t->len;
+ if (is_imx53_ecspi(spi_imx) && spi_imx->target_mode) {
+ spi_imx->rx = mx53_ecspi_rx_target;
+ spi_imx->tx = mx53_ecspi_tx_target;
+ spi_imx->target_burst = t->len;
}
spi_imx->devtype_data->prepare_transfer(spi_imx, spi);
@@ -1564,8 +1568,8 @@ static int spi_imx_poll_transfer(struct spi_device *spi,
return 0;
}
-static int spi_imx_pio_transfer_slave(struct spi_device *spi,
- struct spi_transfer *transfer)
+static int spi_imx_pio_transfer_target(struct spi_device *spi,
+ struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
int ret = 0;
@@ -1584,22 +1588,22 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
spi_imx->remainder = 0;
reinit_completion(&spi_imx->xfer_done);
- spi_imx->slave_aborted = false;
+ spi_imx->target_aborted = false;
spi_imx_push(spi_imx);
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
- spi_imx->slave_aborted) {
+ spi_imx->target_aborted) {
dev_dbg(&spi->dev, "interrupted\n");
ret = -EINTR;
}
- /* ecspi has a HW issue when works in Slave mode,
+ /* ecspi has a HW issue when works in Target mode,
* after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
* ECSPI_TXDATA keeps shift out the last word data,
- * so we have to disable ECSPI when in slave mode after the
+ * so we have to disable ECSPI when in target mode after the
* transfer completes
*/
if (spi_imx->devtype_data->disable)
@@ -1622,8 +1626,8 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
while (spi_imx->devtype_data->rx_available(spi_imx))
readl(spi_imx->base + MXC_CSPIRXDATA);
- if (spi_imx->slave_mode)
- return spi_imx_pio_transfer_slave(spi, transfer);
+ if (spi_imx->target_mode)
+ return spi_imx_pio_transfer_target(spi, transfer);
/*
* If we decided in spi_imx_can_dma() that we want to do a DMA
@@ -1689,11 +1693,11 @@ spi_imx_unprepare_message(struct spi_controller *controller, struct spi_message
return 0;
}
-static int spi_imx_slave_abort(struct spi_controller *controller)
+static int spi_imx_target_abort(struct spi_controller *controller)
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
- spi_imx->slave_aborted = true;
+ spi_imx->target_aborted = true;
complete(&spi_imx->xfer_done);
return 0;
@@ -1708,17 +1712,17 @@ static int spi_imx_probe(struct platform_device *pdev)
int ret, irq, spi_drctl;
const struct spi_imx_devtype_data *devtype_data =
of_device_get_match_data(&pdev->dev);
- bool slave_mode;
+ bool target_mode;
u32 val;
- slave_mode = devtype_data->has_slavemode &&
- of_property_read_bool(np, "spi-slave");
- if (slave_mode)
- controller = spi_alloc_slave(&pdev->dev,
- sizeof(struct spi_imx_data));
- else
- controller = spi_alloc_master(&pdev->dev,
+ target_mode = devtype_data->has_targetmode &&
+ of_property_read_bool(np, "spi-slave");
+ if (target_mode)
+ controller = spi_alloc_target(&pdev->dev,
sizeof(struct spi_imx_data));
+ else
+ controller = spi_alloc_host(&pdev->dev,
+ sizeof(struct spi_imx_data));
if (!controller)
return -ENOMEM;
@@ -1737,7 +1741,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_controller_get_devdata(controller);
spi_imx->controller = controller;
spi_imx->dev = &pdev->dev;
- spi_imx->slave_mode = slave_mode;
+ spi_imx->target_mode = target_mode;
spi_imx->devtype_data = devtype_data;
@@ -1757,7 +1761,7 @@ static int spi_imx_probe(struct platform_device *pdev)
controller->cleanup = spi_imx_cleanup;
controller->prepare_message = spi_imx_prepare_message;
controller->unprepare_message = spi_imx_unprepare_message;
- controller->slave_abort = spi_imx_slave_abort;
+ controller->target_abort = spi_imx_target_abort;
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
SPI_MOSI_IDLE_LOW;
@@ -1779,7 +1783,7 @@ static int spi_imx_probe(struct platform_device *pdev)
if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) {
controller->max_native_cs = 4;
- controller->flags |= SPI_MASTER_GPIO_SS;
+ controller->flags |= SPI_CONTROLLER_GPIO_SS;
}
spi_imx->spi_drctl = spi_drctl;
diff --git a/drivers/spi/spi-ingenic.c b/drivers/spi/spi-ingenic.c
index 7d4b515a160d..cc366936d72b 100644
--- a/drivers/spi/spi-ingenic.c
+++ b/drivers/spi/spi-ingenic.c
@@ -12,7 +12,7 @@
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -392,7 +392,7 @@ static int spi_ingenic_probe(struct platform_device *pdev)
return -EINVAL;
}
- ctlr = devm_spi_alloc_master(dev, sizeof(*priv));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*priv));
if (!ctlr) {
dev_err(dev, "Unable to allocate SPI controller.\n");
return -ENOMEM;
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index bc6d22149e7e..98ec4dc22b81 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -143,7 +143,7 @@
* @base: Beginning of MMIO space
* @pregs: Start of protection registers
* @sregs: Start of software sequencer registers
- * @master: Pointer to the SPI controller structure
+ * @host: Pointer to the SPI controller structure
* @nregions: Maximum number of regions
* @pr_num: Maximum number of protected range registers
* @chip0_size: Size of the first flash chip in bytes
@@ -161,7 +161,7 @@ struct intel_spi {
void __iomem *base;
void __iomem *pregs;
void __iomem *sregs;
- struct spi_controller *master;
+ struct spi_controller *host;
size_t nregions;
size_t pr_num;
size_t chip0_size;
@@ -747,7 +747,7 @@ intel_spi_match_mem_op(struct intel_spi *ispi, const struct spi_mem_op *op)
static bool intel_spi_supports_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, op);
@@ -778,7 +778,7 @@ static bool intel_spi_supports_mem_op(struct spi_mem *mem,
static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, op);
@@ -790,7 +790,7 @@ static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *o
static const char *intel_spi_get_name(struct spi_mem *mem)
{
- const struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ const struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
/*
* Return name of the flash controller device to be compatible
@@ -801,7 +801,7 @@ static const char *intel_spi_get_name(struct spi_mem *mem)
static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, &desc->info.op_tmpl);
@@ -815,7 +815,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs,
size_t len, void *buf)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop = desc->priv;
struct spi_mem_op op = desc->info.op_tmpl;
int ret;
@@ -832,7 +832,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs,
static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs,
size_t len, const void *buf)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop = desc->priv;
struct spi_mem_op op = desc->info.op_tmpl;
int ret;
@@ -1332,14 +1332,14 @@ static int intel_spi_read_desc(struct intel_spi *ispi)
nc = (buf[1] & FLMAP0_NC_MASK) >> FLMAP0_NC_SHIFT;
if (!nc)
- ispi->master->num_chipselect = 1;
+ ispi->host->num_chipselect = 1;
else if (nc == 1)
- ispi->master->num_chipselect = 2;
+ ispi->host->num_chipselect = 2;
else
return -EINVAL;
dev_dbg(ispi->dev, "%u flash components found\n",
- ispi->master->num_chipselect);
+ ispi->host->num_chipselect);
return 0;
}
@@ -1365,7 +1365,7 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
snprintf(chip.modalias, 8, "spi-nor");
chip.platform_data = pdata;
- if (!spi_new_device(ispi->master, &chip))
+ if (!spi_new_device(ispi->host, &chip))
return -ENODEV;
ret = intel_spi_read_desc(ispi);
@@ -1373,13 +1373,13 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
return ret;
/* Add the second chip if present */
- if (ispi->master->num_chipselect < 2)
+ if (ispi->host->num_chipselect < 2)
return 0;
chip.platform_data = NULL;
chip.chip_select = 1;
- if (!spi_new_device(ispi->master, &chip))
+ if (!spi_new_device(ispi->host, &chip))
return -ENODEV;
return 0;
}
@@ -1396,31 +1396,31 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
int intel_spi_probe(struct device *dev, struct resource *mem,
const struct intel_spi_boardinfo *info)
{
- struct spi_controller *master;
+ struct spi_controller *host;
struct intel_spi *ispi;
int ret;
- master = devm_spi_alloc_master(dev, sizeof(*ispi));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*ispi));
+ if (!host)
return -ENOMEM;
- master->mem_ops = &intel_spi_mem_ops;
+ host->mem_ops = &intel_spi_mem_ops;
- ispi = spi_master_get_devdata(master);
+ ispi = spi_controller_get_devdata(host);
ispi->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(ispi->base))
return PTR_ERR(ispi->base);
ispi->dev = dev;
- ispi->master = master;
+ ispi->host = host;
ispi->info = info;
ret = intel_spi_init(ispi);
if (ret)
return ret;
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
return ret;
diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c
index 5980a0dbbccb..39ee2b43a516 100644
--- a/drivers/spi/spi-iproc-qspi.c
+++ b/drivers/spi/spi-iproc-qspi.c
@@ -94,7 +94,6 @@ static int bcm_iproc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct bcm_iproc_intc *priv;
struct bcm_qspi_soc_intc *soc_intc;
- struct resource *res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -104,14 +103,12 @@ static int bcm_iproc_probe(struct platform_device *pdev)
spin_lock_init(&priv->soclock);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
- priv->int_reg = devm_ioremap_resource(dev, res);
+ priv->int_reg = devm_platform_ioremap_resource_byname(pdev, "intr_regs");
if (IS_ERR(priv->int_reg))
return PTR_ERR(priv->int_reg);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "intr_status_reg");
- priv->int_status_reg = devm_ioremap_resource(dev, res);
+ priv->int_status_reg = devm_platform_ioremap_resource_byname(pdev,
+ "intr_status_reg");
if (IS_ERR(priv->int_status_reg))
return PTR_ERR(priv->int_status_reg);
diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c
index c42a3358e8c9..e37ca22e04ba 100644
--- a/drivers/spi/spi-jcore.c
+++ b/drivers/spi/spi-jcore.c
@@ -33,7 +33,7 @@
#define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000
struct jcore_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
unsigned int cs_reg;
unsigned int speed_reg;
@@ -59,7 +59,7 @@ static void jcore_spi_program(struct jcore_spi *hw)
void __iomem *ctrl_reg = hw->base + CTRL_REG;
if (jcore_spi_wait(ctrl_reg))
- dev_err(hw->master->dev.parent,
+ dev_err(hw->host->dev.parent,
"timeout waiting to program ctrl reg.\n");
writel(hw->cs_reg | hw->speed_reg, ctrl_reg);
@@ -67,10 +67,10 @@ static void jcore_spi_program(struct jcore_spi *hw)
static void jcore_spi_chipsel(struct spi_device *spi, bool value)
{
- struct jcore_spi *hw = spi_master_get_devdata(spi->master);
+ struct jcore_spi *hw = spi_controller_get_devdata(spi->controller);
u32 csbit = 1U << (2 * spi_get_chipselect(spi, 0));
- dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi_get_chipselect(spi, 0));
+ dev_dbg(hw->host->dev.parent, "chipselect %d\n", spi_get_chipselect(spi, 0));
if (value)
hw->cs_reg |= csbit;
@@ -90,14 +90,14 @@ static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
else
hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27;
jcore_spi_program(hw);
- dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n",
+ dev_dbg(hw->host->dev.parent, "speed=%d reg=0x%x\n",
speed, hw->speed_reg);
}
-static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
+static int jcore_spi_txrx(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *t)
{
- struct jcore_spi *hw = spi_master_get_devdata(master);
+ struct jcore_spi *hw = spi_controller_get_devdata(host);
void __iomem *ctrl_reg = hw->base + CTRL_REG;
void __iomem *data_reg = hw->base + DATA_REG;
@@ -130,7 +130,7 @@ static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
*rx++ = readl(data_reg);
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
if (count < len)
return -EREMOTEIO;
@@ -142,26 +142,26 @@ static int jcore_spi_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct jcore_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
u32 clock_freq;
struct clk *clk;
int err = -ENODEV;
- master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct jcore_spi));
+ if (!host)
return err;
- /* Setup the master state. */
- master->num_chipselect = 3;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->transfer_one = jcore_spi_txrx;
- master->set_cs = jcore_spi_chipsel;
- master->dev.of_node = node;
- master->bus_num = pdev->id;
+ /* Setup the host state. */
+ host->num_chipselect = 3;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->transfer_one = jcore_spi_txrx;
+ host->set_cs = jcore_spi_chipsel;
+ host->dev.of_node = node;
+ host->bus_num = pdev->id;
- hw = spi_master_get_devdata(master);
- hw->master = master;
+ hw = spi_controller_get_devdata(host);
+ hw->host = host;
platform_set_drvdata(pdev, hw);
/* Find and map our resources */
@@ -200,7 +200,7 @@ static int jcore_spi_probe(struct platform_device *pdev)
jcore_spi_baudrate(hw, 400000);
/* Register our spi controller */
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err)
goto exit;
@@ -209,7 +209,7 @@ static int jcore_spi_probe(struct platform_device *pdev)
exit_busy:
err = -EBUSY;
exit:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c
index 8d6ecc5d6f70..938e9e577e4f 100644
--- a/drivers/spi/spi-lantiq-ssc.c
+++ b/drivers/spi/spi-lantiq-ssc.c
@@ -6,7 +6,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -91,7 +92,7 @@
#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
#define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */
-#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */
+#define LTQ_SPI_STAT_MS BIT(1) /* Host/target select bit */
#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
#define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \
LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \
@@ -109,8 +110,8 @@
#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
-#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
-#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
+#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set host select bit */
+#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear host select bit */
#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
#define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \
@@ -162,7 +163,7 @@ struct lantiq_ssc_hwcfg {
};
struct lantiq_ssc_spi {
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
void __iomem *regbase;
struct clk *spi_clk;
@@ -366,7 +367,7 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
hw_setup_bits_per_word(spi, spi->bits_per_word);
hw_setup_clock_mode(spi, SPI_MODE_0);
- /* Enable master mode and clear error flags */
+ /* Enable host mode and clear error flags */
lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS |
LTQ_SPI_WHBSTATE_CLR_ERRORS,
LTQ_SPI_WHBSTATE);
@@ -386,8 +387,8 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
static int lantiq_ssc_setup(struct spi_device *spidev)
{
- struct spi_master *master = spidev->master;
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = spidev->controller;
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
unsigned int cs = spi_get_chipselect(spidev, 0);
u32 gpocon;
@@ -415,10 +416,10 @@ static int lantiq_ssc_setup(struct spi_device *spidev)
return 0;
}
-static int lantiq_ssc_prepare_message(struct spi_master *master,
+static int lantiq_ssc_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
hw_enter_config_mode(spi);
hw_setup_clock_mode(spi, message->spi->mode);
@@ -460,10 +461,10 @@ static void hw_setup_transfer(struct lantiq_ssc_spi *spi,
lantiq_ssc_writel(spi, con, LTQ_SPI_CON);
}
-static int lantiq_ssc_unprepare_message(struct spi_master *master,
+static int lantiq_ssc_unprepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
flush_workqueue(spi->wq);
@@ -692,8 +693,8 @@ static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
/* set bad status so it can be retried */
- if (spi->master->cur_msg)
- spi->master->cur_msg->status = -EIO;
+ if (spi->host->cur_msg)
+ spi->host->cur_msg->status = -EIO;
queue_work(spi->wq, &spi->work);
spin_unlock(&spi->lock);
@@ -771,22 +772,22 @@ static void lantiq_ssc_bussy_work(struct work_struct *work)
u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
if (!(stat & LTQ_SPI_STAT_BSY)) {
- spi_finalize_current_transfer(spi->master);
+ spi_finalize_current_transfer(spi->host);
return;
}
cond_resched();
} while (!time_after_eq(jiffies, end));
- if (spi->master->cur_msg)
- spi->master->cur_msg->status = -EIO;
- spi_finalize_current_transfer(spi->master);
+ if (spi->host->cur_msg)
+ spi->host->cur_msg->status = -EIO;
+ spi_finalize_current_transfer(spi->host);
}
-static void lantiq_ssc_handle_err(struct spi_master *master,
+static void lantiq_ssc_handle_err(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
/* flush FIFOs on timeout */
rx_fifo_flush(spi);
@@ -795,7 +796,7 @@ static void lantiq_ssc_handle_err(struct spi_master *master,
static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(spidev->master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(spidev->controller);
unsigned int cs = spi_get_chipselect(spidev, 0);
u32 fgpo;
@@ -807,11 +808,11 @@ static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO);
}
-static int lantiq_ssc_transfer_one(struct spi_master *master,
+static int lantiq_ssc_transfer_one(struct spi_controller *host,
struct spi_device *spidev,
struct spi_transfer *t)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
hw_setup_transfer(spi, spidev, t);
@@ -903,7 +904,7 @@ MODULE_DEVICE_TABLE(of, lantiq_ssc_match);
static int lantiq_ssc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct lantiq_ssc_spi *spi;
const struct lantiq_ssc_hwcfg *hwcfg;
u32 id, supports_dma, revision;
@@ -912,33 +913,33 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
hwcfg = of_device_get_match_data(dev);
- master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi));
+ if (!host)
return -ENOMEM;
- spi = spi_master_get_devdata(master);
- spi->master = master;
+ spi = spi_controller_get_devdata(host);
+ spi->host = host;
spi->dev = dev;
spi->hwcfg = hwcfg;
platform_set_drvdata(pdev, spi);
spi->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->regbase)) {
err = PTR_ERR(spi->regbase);
- goto err_master_put;
+ goto err_host_put;
}
err = hwcfg->cfg_irq(pdev, spi);
if (err)
- goto err_master_put;
+ goto err_host_put;
spi->spi_clk = devm_clk_get(dev, "gate");
if (IS_ERR(spi->spi_clk)) {
err = PTR_ERR(spi->spi_clk);
- goto err_master_put;
+ goto err_host_put;
}
err = clk_prepare_enable(spi->spi_clk);
if (err)
- goto err_master_put;
+ goto err_host_put;
/*
* Use the old clk_get_fpi() function on Lantiq platform, till it
@@ -964,19 +965,19 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
spi->bits_per_word = 8;
spi->speed_hz = 0;
- master->dev.of_node = pdev->dev.of_node;
- master->num_chipselect = num_cs;
- master->use_gpio_descriptors = true;
- master->setup = lantiq_ssc_setup;
- master->set_cs = lantiq_ssc_set_cs;
- master->handle_err = lantiq_ssc_handle_err;
- master->prepare_message = lantiq_ssc_prepare_message;
- master->unprepare_message = lantiq_ssc_unprepare_message;
- master->transfer_one = lantiq_ssc_transfer_one;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
- SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
- SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+ host->dev.of_node = pdev->dev.of_node;
+ host->num_chipselect = num_cs;
+ host->use_gpio_descriptors = true;
+ host->setup = lantiq_ssc_setup;
+ host->set_cs = lantiq_ssc_set_cs;
+ host->handle_err = lantiq_ssc_handle_err;
+ host->prepare_message = lantiq_ssc_prepare_message;
+ host->unprepare_message = lantiq_ssc_unprepare_message;
+ host->transfer_one = lantiq_ssc_transfer_one;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
+ SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
+ SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
spi->wq = alloc_ordered_workqueue(dev_name(dev), WQ_MEM_RECLAIM);
if (!spi->wq) {
@@ -997,9 +998,9 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
"Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
- err = devm_spi_register_master(dev, master);
+ err = devm_spi_register_controller(dev, host);
if (err) {
- dev_err(dev, "failed to register spi_master\n");
+ dev_err(dev, "failed to register spi host\n");
goto err_wq_destroy;
}
@@ -1011,8 +1012,8 @@ err_clk_put:
clk_put(spi->fpi_clk);
err_clk_disable:
clk_disable_unprepare(spi->spi_clk);
-err_master_put:
- spi_master_put(master);
+err_host_put:
+ spi_controller_put(host);
return err;
}
diff --git a/drivers/spi/spi-loongson-core.c b/drivers/spi/spi-loongson-core.c
new file mode 100644
index 000000000000..f97800b6fd65
--- /dev/null
+++ b/drivers/spi/spi-loongson-core.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "spi-loongson.h"
+
+static inline void loongson_spi_write_reg(struct loongson_spi *spi, unsigned char reg,
+ unsigned char data)
+{
+ writeb(data, spi->base + reg);
+}
+
+static inline char loongson_spi_read_reg(struct loongson_spi *spi, unsigned char reg)
+{
+ return readb(spi->base + reg);
+}
+
+static void loongson_spi_set_cs(struct spi_device *spi, bool en)
+{
+ int cs;
+ unsigned char mask = (BIT(4) | BIT(0)) << spi_get_chipselect(spi, 0);
+ unsigned char val = en ? mask : (BIT(0) << spi_get_chipselect(spi, 0));
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ cs = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SFCS_REG) & ~mask;
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SFCS_REG, val | cs);
+}
+
+static void loongson_spi_set_clk(struct loongson_spi *loongson_spi, unsigned int hz)
+{
+ unsigned char val;
+ unsigned int div, div_tmp;
+ static const char rdiv[12] = {0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10, 11};
+
+ div = clamp_val(DIV_ROUND_UP_ULL(loongson_spi->clk_rate, hz), 2, 4096);
+ div_tmp = rdiv[fls(div - 1)];
+ loongson_spi->spcr = (div_tmp & GENMASK(1, 0)) >> 0;
+ loongson_spi->sper = (div_tmp & GENMASK(3, 2)) >> 2;
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ val &= ~GENMASK(1, 0);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, val |
+ loongson_spi->spcr);
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPER_REG);
+ val &= ~GENMASK(1, 0);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPER_REG, val |
+ loongson_spi->sper);
+ loongson_spi->hz = hz;
+}
+
+static void loongson_spi_set_mode(struct loongson_spi *loongson_spi,
+ struct spi_device *spi)
+{
+ unsigned char val;
+
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ val &= ~(LOONGSON_SPI_SPCR_CPOL | LOONGSON_SPI_SPCR_CPHA);
+ if (spi->mode & SPI_CPOL)
+ val |= LOONGSON_SPI_SPCR_CPOL;
+ if (spi->mode & SPI_CPHA)
+ val |= LOONGSON_SPI_SPCR_CPHA;
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, val);
+ loongson_spi->mode |= spi->mode;
+}
+
+static int loongson_spi_update_state(struct loongson_spi *loongson_spi,
+ struct spi_device *spi, struct spi_transfer *t)
+{
+ if (t && loongson_spi->hz != t->speed_hz)
+ loongson_spi_set_clk(loongson_spi, t->speed_hz);
+
+ if ((spi->mode ^ loongson_spi->mode) & SPI_MODE_X_MASK)
+ loongson_spi_set_mode(loongson_spi, spi);
+
+ return 0;
+}
+
+static int loongson_spi_setup(struct spi_device *spi)
+{
+ struct loongson_spi *loongson_spi;
+
+ loongson_spi = spi_controller_get_devdata(spi->controller);
+ if (spi->bits_per_word % 8)
+ return -EINVAL;
+
+ if (spi_get_chipselect(spi, 0) >= spi->controller->num_chipselect)
+ return -EINVAL;
+
+ loongson_spi->hz = 0;
+ loongson_spi_set_cs(spi, true);
+
+ return 0;
+}
+
+static int loongson_spi_write_read_8bit(struct spi_device *spi, const u8 **tx_buf,
+ u8 **rx_buf, unsigned int num)
+{
+ int ret;
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ if (tx_buf && *tx_buf)
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_FIFO_REG, *((*tx_buf)++));
+ else
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_FIFO_REG, 0);
+
+ ret = readb_poll_timeout(loongson_spi->base + LOONGSON_SPI_SPSR_REG,
+ loongson_spi->spsr, (loongson_spi->spsr &
+ LOONGSON_SPI_SPSR_RFEMPTY) != LOONGSON_SPI_SPSR_RFEMPTY,
+ 1, USEC_PER_MSEC);
+
+ if (rx_buf && *rx_buf)
+ *(*rx_buf)++ = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_FIFO_REG);
+ else
+ loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_FIFO_REG);
+
+ return ret;
+}
+
+static int loongson_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ int ret;
+ unsigned int count;
+ const u8 *tx = xfer->tx_buf;
+ u8 *rx = xfer->rx_buf;
+
+ count = xfer->len;
+ do {
+ ret = loongson_spi_write_read_8bit(spi, &tx, &rx, count);
+ if (ret)
+ break;
+ } while (--count);
+
+ return ret;
+}
+
+static int loongson_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *m)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(ctlr);
+
+ loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para &
+ ~LOONGSON_SPI_PARA_MEM_EN);
+
+ return 0;
+}
+
+static int loongson_spi_transfer_one(struct spi_controller *ctrl, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ loongson_spi_update_state(loongson_spi, spi, xfer);
+ if (xfer->len)
+ return loongson_spi_write_read(spi, xfer);
+
+ return 0;
+}
+
+static int loongson_spi_unprepare_message(struct spi_controller *ctrl, struct spi_message *m)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(ctrl);
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para);
+
+ return 0;
+}
+
+static void loongson_spi_reginit(struct loongson_spi *loongson_spi_dev)
+{
+ unsigned char val;
+
+ val = loongson_spi_read_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG);
+ val &= ~LOONGSON_SPI_SPCR_SPE;
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG, val);
+
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPSR_REG,
+ (LOONGSON_SPI_SPSR_SPIF | LOONGSON_SPI_SPSR_WCOL));
+
+ val = loongson_spi_read_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG);
+ val |= LOONGSON_SPI_SPCR_SPE;
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG, val);
+}
+
+int loongson_spi_init_controller(struct device *dev, void __iomem *regs)
+{
+ struct spi_controller *controller;
+ struct loongson_spi *spi;
+ struct clk *clk;
+
+ controller = devm_spi_alloc_host(dev, sizeof(struct loongson_spi));
+ if (controller == NULL)
+ return -ENOMEM;
+
+ controller->mode_bits = SPI_MODE_X_MASK | SPI_CS_HIGH;
+ controller->setup = loongson_spi_setup;
+ controller->prepare_message = loongson_spi_prepare_message;
+ controller->transfer_one = loongson_spi_transfer_one;
+ controller->unprepare_message = loongson_spi_unprepare_message;
+ controller->set_cs = loongson_spi_set_cs;
+ controller->num_chipselect = 4;
+ device_set_node(&controller->dev, dev_fwnode(dev));
+ dev_set_drvdata(dev, controller);
+
+ spi = spi_controller_get_devdata(controller);
+ spi->base = regs;
+ spi->controller = controller;
+
+ clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "unable to get clock\n");
+
+ spi->clk_rate = clk_get_rate(clk);
+ loongson_spi_reginit(spi);
+
+ spi->mode = 0;
+
+ return devm_spi_register_controller(dev, controller);
+}
+EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, SPI_LOONGSON_CORE);
+
+static int __maybe_unused loongson_spi_suspend(struct device *dev)
+{
+ struct loongson_spi *loongson_spi;
+ struct spi_controller *controller;
+
+ controller = dev_get_drvdata(dev);
+ spi_controller_suspend(controller);
+
+ loongson_spi = spi_controller_get_devdata(controller);
+
+ loongson_spi->spcr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ loongson_spi->sper = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPER_REG);
+ loongson_spi->spsr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPSR_REG);
+ loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG);
+ loongson_spi->sfcs = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SFCS_REG);
+ loongson_spi->timi = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_TIMI_REG);
+
+ return 0;
+}
+
+static int __maybe_unused loongson_spi_resume(struct device *dev)
+{
+ struct loongson_spi *loongson_spi;
+ struct spi_controller *controller;
+
+ controller = dev_get_drvdata(dev);
+ loongson_spi = spi_controller_get_devdata(controller);
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, loongson_spi->spcr);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPER_REG, loongson_spi->sper);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPSR_REG, loongson_spi->spsr);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SFCS_REG, loongson_spi->sfcs);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_TIMI_REG, loongson_spi->timi);
+
+ spi_controller_resume(controller);
+
+ return 0;
+}
+
+const struct dev_pm_ops loongson_spi_dev_pm_ops = {
+ .suspend = loongson_spi_suspend,
+ .resume = loongson_spi_resume,
+};
+EXPORT_SYMBOL_NS_GPL(loongson_spi_dev_pm_ops, SPI_LOONGSON_CORE);
+
+MODULE_DESCRIPTION("Loongson SPI core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-loongson-pci.c b/drivers/spi/spi-loongson-pci.c
new file mode 100644
index 000000000000..134cda0c13a5
--- /dev/null
+++ b/drivers/spi/spi-loongson-pci.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+// PCI interface driver for Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/mod_devicetable.h>
+#include <linux/pci.h>
+
+#include "spi-loongson.h"
+
+static int loongson_spi_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ void __iomem *reg_base;
+ struct device *dev = &pdev->dev;
+ int pci_bar = 0;
+
+ ret = pcim_enable_device(pdev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot enable pci device\n");
+
+ ret = pcim_iomap_regions(pdev, BIT(pci_bar), pci_name(pdev));
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request and remap memory\n");
+
+ reg_base = pcim_iomap_table(pdev)[pci_bar];
+
+ ret = loongson_spi_init_controller(dev, reg_base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize controller\n");
+
+ return 0;
+}
+
+static struct pci_device_id loongson_spi_devices[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a0b) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a1b) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, loongson_spi_devices);
+
+static struct pci_driver loongson_spi_pci_driver = {
+ .name = "loongson-spi-pci",
+ .id_table = loongson_spi_devices,
+ .probe = loongson_spi_pci_register,
+ .driver = {
+ .bus = &pci_bus_type,
+ .pm = &loongson_spi_dev_pm_ops,
+ },
+};
+module_pci_driver(loongson_spi_pci_driver);
+
+MODULE_DESCRIPTION("Loongson spi pci driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SPI_LOONGSON_CORE);
diff --git a/drivers/spi/spi-loongson-plat.c b/drivers/spi/spi-loongson-plat.c
new file mode 100644
index 000000000000..c066e5f5891e
--- /dev/null
+++ b/drivers/spi/spi-loongson-plat.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Platform driver for Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "spi-loongson.h"
+
+static int loongson_spi_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *reg_base;
+ struct device *dev = &pdev->dev;
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ ret = loongson_spi_init_controller(dev, reg_base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize controller\n");
+
+ return 0;
+}
+
+static const struct of_device_id loongson_spi_id_table[] = {
+ { .compatible = "loongson,ls2k1000-spi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, loongson_spi_id_table);
+
+static struct platform_driver loongson_spi_plat_driver = {
+ .probe = loongson_spi_platform_probe,
+ .driver = {
+ .name = "loongson-spi",
+ .bus = &platform_bus_type,
+ .pm = &loongson_spi_dev_pm_ops,
+ .of_match_table = loongson_spi_id_table,
+ },
+};
+module_platform_driver(loongson_spi_plat_driver);
+
+MODULE_DESCRIPTION("Loongson spi platform driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SPI_LOONGSON_CORE);
diff --git a/drivers/spi/spi-loongson.h b/drivers/spi/spi-loongson.h
new file mode 100644
index 000000000000..35f95b161842
--- /dev/null
+++ b/drivers/spi/spi-loongson.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Header File for Loongson SPI Driver. */
+/* Copyright (C) 2023 Loongson Technology Corporation Limited */
+
+#ifndef __LINUX_SPI_LOONGSON_H
+#define __LINUX_SPI_LOONGSON_H
+
+#include <linux/bits.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+
+#define LOONGSON_SPI_SPCR_REG 0x00
+#define LOONGSON_SPI_SPSR_REG 0x01
+#define LOONGSON_SPI_FIFO_REG 0x02
+#define LOONGSON_SPI_SPER_REG 0x03
+#define LOONGSON_SPI_PARA_REG 0x04
+#define LOONGSON_SPI_SFCS_REG 0x05
+#define LOONGSON_SPI_TIMI_REG 0x06
+
+/* Bits definition for Loongson SPI register */
+#define LOONGSON_SPI_PARA_MEM_EN BIT(0)
+#define LOONGSON_SPI_SPCR_CPHA BIT(2)
+#define LOONGSON_SPI_SPCR_CPOL BIT(3)
+#define LOONGSON_SPI_SPCR_SPE BIT(6)
+#define LOONGSON_SPI_SPSR_RFEMPTY BIT(0)
+#define LOONGSON_SPI_SPSR_WCOL BIT(6)
+#define LOONGSON_SPI_SPSR_SPIF BIT(7)
+
+struct device;
+struct spi_controller;
+
+struct loongson_spi {
+ struct spi_controller *controller;
+ void __iomem *base;
+ int cs_active;
+ unsigned int hz;
+ unsigned char spcr;
+ unsigned char sper;
+ unsigned char spsr;
+ unsigned char para;
+ unsigned char sfcs;
+ unsigned char timi;
+ unsigned int mode;
+ u64 clk_rate;
+};
+
+int loongson_spi_init_controller(struct device *dev, void __iomem *reg);
+extern const struct dev_pm_ops loongson_spi_dev_pm_ops;
+#endif /* __LINUX_SPI_LOONGSON_H */
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index 675a73cf1579..bbf2015d8e5c 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -14,8 +14,8 @@
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/list_sort.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/spi/spi.h>
diff --git a/drivers/spi/spi-lp8841-rtc.c b/drivers/spi/spi-lp8841-rtc.c
index 2d436541d6c2..b357461f1b8b 100644
--- a/drivers/spi/spi-lp8841-rtc.c
+++ b/drivers/spi/spi-lp8841-rtc.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#define DRIVER_NAME "spi_lp8841_rtc"
@@ -75,14 +74,14 @@ bitbang_txrx_be_cpha0_lsb(struct spi_lp8841_rtc *data,
for (; likely(bits); bits--) {
/* setup LSB (to slave) on leading edge */
- if ((flags & SPI_MASTER_NO_TX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0)
setmosi(data, (word & 1));
usleep_range(usecs, usecs + 1); /* T(setup) */
/* sample LSB (from slave) on trailing edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= (getmiso(data) << 31);
setsck(data, !cpol);
@@ -113,7 +112,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
while (likely(count > 0)) {
word = *tx++;
bitbang_txrx_be_cpha0_lsb(data, 1, 0,
- SPI_MASTER_NO_RX, word, 8);
+ SPI_CONTROLLER_NO_RX, word, 8);
count--;
}
} else if (rx) {
@@ -121,7 +120,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
writeb(data->state, data->iomem);
while (likely(count > 0)) {
word = bitbang_txrx_be_cpha0_lsb(data, 1, 0,
- SPI_MASTER_NO_TX, word, 8);
+ SPI_CONTROLLER_NO_TX, word, 8);
*rx++ = word;
count--;
}
@@ -191,7 +190,7 @@ spi_lp8841_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, master);
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->mode_bits = SPI_CS_HIGH | SPI_3WIRE | SPI_LSB_FIRST;
master->bus_num = pdev->id;
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index 141562c882f1..43d134f4b42b 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
@@ -864,7 +863,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
SPI_BPW_MASK(24) |
SPI_BPW_MASK(16) |
SPI_BPW_MASK(8);
- master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
+ master->flags = (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX);
master->min_speed_hz = spicc->data->min_speed_hz;
master->max_speed_hz = spicc->data->max_speed_hz;
master->setup = meson_spicc_setup;
diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c
index b59e8a0c5b97..b451cd4860ec 100644
--- a/drivers/spi/spi-microchip-core.c
+++ b/drivers/spi/spi-microchip-core.c
@@ -530,10 +530,8 @@ static int mchp_corespi_probe(struct platform_device *pdev)
return PTR_ERR(spi->regs);
spi->irq = platform_get_irq(pdev, 0);
- if (spi->irq <= 0)
- return dev_err_probe(&pdev->dev, -ENXIO,
- "invalid IRQ %d for SPI controller\n",
- spi->irq);
+ if (spi->irq < 0)
+ return spi->irq;
ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt,
IRQF_SHARED, dev_name(&pdev->dev), master);
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 99aeef28a477..5cecca1bef02 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -53,7 +53,7 @@ struct mpc512x_psc_spi {
int type;
void __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo;
- unsigned int irq;
+ int irq;
u8 bits_per_word;
u32 mclk_rate;
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 9a1a080fb688..795c08594a4d 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -29,7 +29,7 @@ struct mpc52xx_psc_spi {
/* driver internal data */
struct mpc52xx_psc __iomem *psc;
struct mpc52xx_psc_fifo __iomem *fifo;
- unsigned int irq;
+ int irq;
u8 bits_per_word;
struct completion done;
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 39272ad6641b..0757985947dd 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -1142,7 +1142,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
master->mode_bits |= SPI_CS_HIGH;
if (mdata->dev_comp->must_tx)
- master->flags = SPI_MASTER_MUST_TX;
+ master->flags = SPI_CONTROLLER_MUST_TX;
if (mdata->dev_comp->ipm_design)
master->mode_bits |= SPI_LOOP | SPI_RX_DUAL | SPI_TX_DUAL |
SPI_RX_QUAD | SPI_TX_QUAD;
diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c
index 3e9d396b33bd..91600e5c22e4 100644
--- a/drivers/spi/spi-mt7621.c
+++ b/drivers/spi/spi-mt7621.c
@@ -14,7 +14,9 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index baa7a5353987..cf4ee8b19e42 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -13,7 +13,8 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index bed8317cd205..4433a8a9299f 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -76,7 +76,8 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/mtd/nand-ecc-mtk.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 963a53dd680b..cd0e7ae07162 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -572,7 +572,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->num_chipselect = 3;
master->dev.of_node = np;
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->auto_runtime_pm = true;
spi = spi_master_get_devdata(master);
diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c
index eb353561509a..0ca21ff0e9cc 100644
--- a/drivers/spi/spi-npcm-fiu.c
+++ b/drivers/spi/spi-npcm-fiu.c
@@ -12,7 +12,7 @@
#include <linux/io.h>
#include <linux/vmalloc.h>
#include <linux/regmap.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/spi/spi-mem.h>
#include <linux/mfd/syscon.h>
@@ -287,7 +287,7 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
offs);
@@ -314,7 +314,7 @@ static ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, const void *buf)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
offs);
@@ -335,7 +335,7 @@ static int npcm_fiu_uma_read(struct spi_mem *mem,
bool is_address_size, u8 *data, u32 data_size)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u32 uma_cfg = BIT(10);
u32 data_reg[4];
int ret;
@@ -390,7 +390,7 @@ static int npcm_fiu_uma_write(struct spi_mem *mem,
bool is_address_size, u8 *data, u32 data_size)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u32 uma_cfg = BIT(10);
u32 data_reg[4] = {0};
u32 val;
@@ -439,7 +439,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u8 *data = (u8 *)op->data.buf.out;
u32 num_data_chunks;
u32 remain_data;
@@ -544,7 +544,7 @@ static void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(mem->spi, 0)];
int ret = 0;
u8 *buf;
@@ -604,7 +604,7 @@ static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
struct regmap *gcr_regmap;
@@ -665,7 +665,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
static int npcm_fiu_setup(struct spi_device *spi)
{
- struct spi_controller *ctrl = spi->master;
+ struct spi_controller *ctrl = spi->controller;
struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
struct npcm_fiu_chip *chip;
@@ -701,7 +701,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
void __iomem *regbase;
int id, ret;
- ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
+ ctrl = devm_spi_alloc_host(dev, sizeof(*fiu));
if (!ctrl)
return -ENOMEM;
@@ -755,7 +755,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
ctrl->num_chipselect = fiu->info->max_cs;
ctrl->dev.of_node = dev->of_node;
- ret = devm_spi_register_master(dev, ctrl);
+ ret = devm_spi_register_controller(dev, ctrl);
if (ret)
clk_disable_unprepare(fiu->clk);
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 544017655787..45a4acc95661 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/regmap.h>
@@ -1157,12 +1156,10 @@ static int nxp_fspi_probe(struct platform_device *pdev)
/* find the resources - configuration register address space */
if (is_acpi_node(dev_fwnode(f->dev)))
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ f->iobase = devm_platform_ioremap_resource(pdev, 0);
else
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "fspi_base");
+ f->iobase = devm_platform_ioremap_resource_byname(pdev, "fspi_base");
- f->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(f->iobase)) {
ret = PTR_ERR(f->iobase);
goto err_put_ctrl;
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 902d2e0c1f2f..f89aa9e52c23 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -486,7 +486,7 @@ static int uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
master->num_chipselect = 4;
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 8331e247bf5c..e5cd82eb9e54 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -1508,10 +1508,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
}
status = platform_get_irq(pdev, 0);
- if (status < 0) {
- dev_err_probe(&pdev->dev, status, "no irq resource found\n");
+ if (status < 0)
goto free_master;
- }
init_completion(&mcspi->txdone);
status = devm_request_irq(&pdev->dev, status,
omap2_mcspi_irq_handler, 0, pdev->name,
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index ad9e83e34297..1f10f5c8e34d 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -16,7 +16,6 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/sizes.h>
#include <asm/unaligned.h>
@@ -91,7 +90,7 @@ struct orion_child_options {
};
struct orion_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
struct clk *clk;
struct clk *axi_clk;
@@ -142,7 +141,7 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
struct orion_spi *orion_spi;
const struct orion_spi_dev *devdata;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
devdata = orion_spi->devdata;
tclk_hz = clk_get_rate(orion_spi->clk);
@@ -236,7 +235,7 @@ orion_spi_mode_set(struct spi_device *spi)
u32 reg;
struct orion_spi *orion_spi;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
reg &= ~ORION_SPI_MODE_MASK;
@@ -258,7 +257,7 @@ orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
u32 reg;
struct orion_spi *orion_spi;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
/*
* Erratum description: (Erratum NO. FE-9144572) The device
@@ -298,7 +297,7 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
unsigned int bits_per_word = spi->bits_per_word;
int rc;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
if ((t != NULL) && t->speed_hz)
speed = t->speed_hz;
@@ -331,7 +330,7 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
void __iomem *ctrl_reg;
u32 val;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
ctrl_reg = spi_reg(orion_spi, ORION_SPI_IF_CTRL_REG);
val = readl(ctrl_reg);
@@ -389,7 +388,7 @@ orion_spi_write_read_8bit(struct spi_device *spi,
cs_single_byte = spi->mode & SPI_CS_WORD;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
if (cs_single_byte)
orion_spi_set_cs(spi, 0);
@@ -440,7 +439,7 @@ orion_spi_write_read_16bit(struct spi_device *spi,
return -1;
}
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
@@ -476,7 +475,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
word_len = spi->bits_per_word;
count = xfer->len;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
/*
* Use SPI direct write mode if base address is available
@@ -529,7 +528,7 @@ out:
return xfer->len - count;
}
-static int orion_spi_transfer_one(struct spi_master *master,
+static int orion_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
@@ -549,7 +548,7 @@ static int orion_spi_setup(struct spi_device *spi)
{
int ret;
#ifdef CONFIG_PM
- struct orion_spi *orion_spi = spi_master_get_devdata(spi->master);
+ struct orion_spi *orion_spi = spi_controller_get_devdata(spi->controller);
struct device *dev = orion_spi->dev;
orion_spi_runtime_resume(dev);
@@ -645,44 +644,44 @@ MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
static int orion_spi_probe(struct platform_device *pdev)
{
const struct orion_spi_dev *devdata;
- struct spi_master *master;
+ struct spi_controller *host;
struct orion_spi *spi;
struct resource *r;
unsigned long tclk_hz;
int status = 0;
struct device_node *np;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi));
- if (master == NULL) {
- dev_dbg(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*spi));
+ if (host == NULL) {
+ dev_dbg(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
- master->bus_num = pdev->id;
+ host->bus_num = pdev->id;
if (pdev->dev.of_node) {
u32 cell_index;
if (!of_property_read_u32(pdev->dev.of_node, "cell-index",
&cell_index))
- master->bus_num = cell_index;
+ host->bus_num = cell_index;
}
/* we support all 4 SPI modes and LSB first option */
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_CS_WORD;
- master->set_cs = orion_spi_set_cs;
- master->transfer_one = orion_spi_transfer_one;
- master->num_chipselect = ORION_NUM_CHIPSELECTS;
- master->setup = orion_spi_setup;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
- master->auto_runtime_pm = true;
- master->use_gpio_descriptors = true;
- master->flags = SPI_MASTER_GPIO_SS;
-
- platform_set_drvdata(pdev, master);
-
- spi = spi_master_get_devdata(master);
- spi->master = master;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_CS_WORD;
+ host->set_cs = orion_spi_set_cs;
+ host->transfer_one = orion_spi_transfer_one;
+ host->num_chipselect = ORION_NUM_CHIPSELECTS;
+ host->setup = orion_spi_setup;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ host->auto_runtime_pm = true;
+ host->use_gpio_descriptors = true;
+ host->flags = SPI_CONTROLLER_GPIO_SS;
+
+ platform_set_drvdata(pdev, host);
+
+ spi = spi_controller_get_devdata(host);
+ spi->host = host;
spi->dev = &pdev->dev;
devdata = device_get_match_data(&pdev->dev);
@@ -719,14 +718,14 @@ static int orion_spi_probe(struct platform_device *pdev)
*/
if (of_device_is_compatible(pdev->dev.of_node,
"marvell,armada-370-spi"))
- master->max_speed_hz = min(devdata->max_hz,
+ host->max_speed_hz = min(devdata->max_hz,
DIV_ROUND_UP(tclk_hz, devdata->min_divisor));
else if (devdata->min_divisor)
- master->max_speed_hz =
+ host->max_speed_hz =
DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
else
- master->max_speed_hz = devdata->max_hz;
- master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
+ host->max_speed_hz = devdata->max_hz;
+ host->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(spi->base)) {
@@ -785,8 +784,8 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
goto out_rel_pm;
- master->dev.of_node = pdev->dev.of_node;
- status = spi_register_master(master);
+ host->dev.of_node = pdev->dev.of_node;
+ status = spi_register_controller(host);
if (status < 0)
goto out_rel_pm;
@@ -799,21 +798,21 @@ out_rel_axi_clk:
out_rel_clk:
clk_disable_unprepare(spi->clk);
out:
- spi_master_put(master);
+ spi_controller_put(host);
return status;
}
static void orion_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct orion_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(spi->axi_clk);
clk_disable_unprepare(spi->clk);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
}
@@ -822,8 +821,8 @@ MODULE_ALIAS("platform:" DRIVER_NAME);
#ifdef CONFIG_PM
static int orion_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct orion_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
clk_disable_unprepare(spi->axi_clk);
clk_disable_unprepare(spi->clk);
@@ -832,8 +831,8 @@ static int orion_spi_runtime_suspend(struct device *dev)
static int orion_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct orion_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
if (!IS_ERR(spi->axi_clk))
clk_prepare_enable(spi->axi_clk);
diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c
index 4445d82409d6..3638e974f5d4 100644
--- a/drivers/spi/spi-pci1xxxx.c
+++ b/drivers/spi/spi-pci1xxxx.c
@@ -65,7 +65,7 @@ struct pci1xxxx_spi_internal {
bool spi_xfer_in_progress;
int irq;
struct completion spi_xfer_done;
- struct spi_master *spi_host;
+ struct spi_controller *spi_host;
struct pci1xxxx_spi *parent;
struct {
unsigned int dev_sel : 3;
@@ -250,7 +250,7 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
struct pci1xxxx_spi_internal *spi_sub_ptr;
struct device *dev = &pdev->dev;
struct pci1xxxx_spi *spi_bus;
- struct spi_master *spi_host;
+ struct spi_controller *spi_host;
u32 regval;
int ret;
@@ -276,7 +276,7 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
sizeof(struct pci1xxxx_spi_internal),
GFP_KERNEL);
spi_sub_ptr = spi_bus->spi_int[iter];
- spi_sub_ptr->spi_host = devm_spi_alloc_master(dev, sizeof(struct spi_master));
+ spi_sub_ptr->spi_host = devm_spi_alloc_host(dev, sizeof(struct spi_controller));
if (!spi_sub_ptr->spi_host)
return -ENOMEM;
@@ -365,9 +365,9 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
spi_host->bits_per_word_mask = SPI_BPW_MASK(8);
spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ;
spi_host->min_speed_hz = PCI1XXXX_SPI_MIN_CLOCK_HZ;
- spi_host->flags = SPI_MASTER_MUST_TX;
- spi_master_set_devdata(spi_host, spi_sub_ptr);
- ret = devm_spi_register_master(dev, spi_host);
+ spi_host->flags = SPI_CONTROLLER_MUST_TX;
+ spi_controller_set_devdata(spi_host, spi_sub_ptr);
+ ret = devm_spi_register_controller(dev, spi_host);
if (ret)
goto error;
}
@@ -415,7 +415,7 @@ static int pci1xxxx_spi_resume(struct device *dev)
for (iter = 0; iter < spi_ptr->total_hw_instances; iter++) {
spi_sub_ptr = spi_ptr->spi_int[iter];
- spi_master_resume(spi_sub_ptr->spi_host);
+ spi_controller_resume(spi_sub_ptr->spi_host);
writel(regval, spi_ptr->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(iter));
@@ -441,7 +441,7 @@ static int pci1xxxx_spi_suspend(struct device *dev)
/* Store existing config before suspend */
store_restore_config(spi_ptr, spi_sub_ptr, iter, 1);
- spi_master_suspend(spi_sub_ptr->spi_host);
+ spi_controller_suspend(spi_sub_ptr->spi_host);
writel(reg1, spi_ptr->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(iter));
}
diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c
index 51dfb49523f3..883354d0ff52 100644
--- a/drivers/spi/spi-pic32-sqi.c
+++ b/drivers/spi/spi-pic32-sqi.c
@@ -139,7 +139,7 @@ struct pic32_sqi {
void __iomem *regs;
struct clk *sys_clk;
struct clk *base_clk; /* drives spi clock */
- struct spi_master *master;
+ struct spi_controller *host;
int irq;
struct completion xfer_done;
struct ring_desc *ring;
@@ -316,9 +316,9 @@ static int pic32_sqi_one_transfer(struct pic32_sqi *sqi,
return 0;
}
-static int pic32_sqi_prepare_hardware(struct spi_master *master)
+static int pic32_sqi_prepare_hardware(struct spi_controller *host)
{
- struct pic32_sqi *sqi = spi_master_get_devdata(master);
+ struct pic32_sqi *sqi = spi_controller_get_devdata(host);
/* enable spi interface */
pic32_setbits(sqi->regs + PESQI_CONF_REG, PESQI_EN);
@@ -328,7 +328,7 @@ static int pic32_sqi_prepare_hardware(struct spi_master *master)
return 0;
}
-static bool pic32_sqi_can_dma(struct spi_master *master,
+static bool pic32_sqi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *x)
{
@@ -336,7 +336,7 @@ static bool pic32_sqi_can_dma(struct spi_master *master,
return true;
}
-static int pic32_sqi_one_message(struct spi_master *master,
+static int pic32_sqi_one_message(struct spi_controller *host,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
@@ -347,7 +347,7 @@ static int pic32_sqi_one_message(struct spi_master *master,
unsigned long timeout;
u32 val;
- sqi = spi_master_get_devdata(master);
+ sqi = spi_controller_get_devdata(host);
reinit_completion(&sqi->xfer_done);
msg->actual_length = 0;
@@ -412,7 +412,7 @@ static int pic32_sqi_one_message(struct spi_master *master,
/* wait for xfer completion */
timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
if (timeout == 0) {
- dev_err(&sqi->master->dev, "wait timedout/interrupted\n");
+ dev_err(&sqi->host->dev, "wait timedout/interrupted\n");
ret = -ETIMEDOUT;
msg->status = ret;
} else {
@@ -434,14 +434,14 @@ xfer_out:
/* release ring descr */
ring_desc_put(sqi, rdesc);
}
- spi_finalize_current_message(spi->master);
+ spi_finalize_current_message(spi->controller);
return ret;
}
-static int pic32_sqi_unprepare_hardware(struct spi_master *master)
+static int pic32_sqi_unprepare_hardware(struct spi_controller *host)
{
- struct pic32_sqi *sqi = spi_master_get_devdata(master);
+ struct pic32_sqi *sqi = spi_controller_get_devdata(host);
/* disable clk */
pic32_clrbits(sqi->regs + PESQI_CLK_CTRL_REG, PESQI_CLK_EN);
@@ -458,18 +458,18 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
int i;
/* allocate coherent DMAable memory for hardware buffer descriptors. */
- sqi->bd = dma_alloc_coherent(&sqi->master->dev,
+ sqi->bd = dma_alloc_coherent(&sqi->host->dev,
sizeof(*bd) * PESQI_BD_COUNT,
&sqi->bd_dma, GFP_KERNEL);
if (!sqi->bd) {
- dev_err(&sqi->master->dev, "failed allocating dma buffer\n");
+ dev_err(&sqi->host->dev, "failed allocating dma buffer\n");
return -ENOMEM;
}
/* allocate software ring descriptors */
sqi->ring = kcalloc(PESQI_BD_COUNT, sizeof(*rdesc), GFP_KERNEL);
if (!sqi->ring) {
- dma_free_coherent(&sqi->master->dev,
+ dma_free_coherent(&sqi->host->dev,
sizeof(*bd) * PESQI_BD_COUNT,
sqi->bd, sqi->bd_dma);
return -ENOMEM;
@@ -498,7 +498,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
static void ring_desc_ring_free(struct pic32_sqi *sqi)
{
- dma_free_coherent(&sqi->master->dev,
+ dma_free_coherent(&sqi->host->dev,
sizeof(struct buf_desc) * PESQI_BD_COUNT,
sqi->bd, sqi->bd_dma);
kfree(sqi->ring);
@@ -568,28 +568,28 @@ static void pic32_sqi_hw_init(struct pic32_sqi *sqi)
static int pic32_sqi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct pic32_sqi *sqi;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*sqi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*sqi));
+ if (!host)
return -ENOMEM;
- sqi = spi_master_get_devdata(master);
- sqi->master = master;
+ sqi = spi_controller_get_devdata(host);
+ sqi->host = host;
sqi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sqi->regs)) {
ret = PTR_ERR(sqi->regs);
- goto err_free_master;
+ goto err_free_host;
}
/* irq */
sqi->irq = platform_get_irq(pdev, 0);
if (sqi->irq < 0) {
ret = sqi->irq;
- goto err_free_master;
+ goto err_free_host;
}
/* clocks */
@@ -597,27 +597,27 @@ static int pic32_sqi_probe(struct platform_device *pdev)
if (IS_ERR(sqi->sys_clk)) {
ret = PTR_ERR(sqi->sys_clk);
dev_err(&pdev->dev, "no sys_clk ?\n");
- goto err_free_master;
+ goto err_free_host;
}
sqi->base_clk = devm_clk_get(&pdev->dev, "spi_ck");
if (IS_ERR(sqi->base_clk)) {
ret = PTR_ERR(sqi->base_clk);
dev_err(&pdev->dev, "no base clk ?\n");
- goto err_free_master;
+ goto err_free_host;
}
ret = clk_prepare_enable(sqi->sys_clk);
if (ret) {
dev_err(&pdev->dev, "sys clk enable failed\n");
- goto err_free_master;
+ goto err_free_host;
}
ret = clk_prepare_enable(sqi->base_clk);
if (ret) {
dev_err(&pdev->dev, "base clk enable failed\n");
clk_disable_unprepare(sqi->sys_clk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sqi->xfer_done);
@@ -640,24 +640,24 @@ static int pic32_sqi_probe(struct platform_device *pdev)
goto err_free_ring;
}
- /* register master */
- master->num_chipselect = 2;
- master->max_speed_hz = clk_get_rate(sqi->base_clk);
- master->dma_alignment = 32;
- master->max_dma_len = PESQI_BD_BUF_LEN_MAX;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
+ /* register host */
+ host->num_chipselect = 2;
+ host->max_speed_hz = clk_get_rate(sqi->base_clk);
+ host->dma_alignment = 32;
+ host->max_dma_len = PESQI_BD_BUF_LEN_MAX;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->can_dma = pic32_sqi_can_dma;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
- master->transfer_one_message = pic32_sqi_one_message;
- master->prepare_transfer_hardware = pic32_sqi_prepare_hardware;
- master->unprepare_transfer_hardware = pic32_sqi_unprepare_hardware;
-
- ret = devm_spi_register_master(&pdev->dev, master);
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->can_dma = pic32_sqi_can_dma;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ host->transfer_one_message = pic32_sqi_one_message;
+ host->prepare_transfer_hardware = pic32_sqi_prepare_hardware;
+ host->unprepare_transfer_hardware = pic32_sqi_unprepare_hardware;
+
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&master->dev, "failed registering spi master\n");
+ dev_err(&host->dev, "failed registering spi host\n");
free_irq(sqi->irq, sqi);
goto err_free_ring;
}
@@ -673,8 +673,8 @@ err_disable_clk:
clk_disable_unprepare(sqi->base_clk);
clk_disable_unprepare(sqi->sys_clk);
-err_free_master:
- spi_master_put(master);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c
index f2af5e653f3d..52b788dac10a 100644
--- a/drivers/spi/spi-pic32.c
+++ b/drivers/spi/spi-pic32.c
@@ -100,7 +100,7 @@ struct pic32_spi {
int tx_irq;
u32 fifo_n_byte; /* FIFO depth in bytes */
struct clk *clk;
- struct spi_master *master;
+ struct spi_controller *host;
/* Current controller setting */
u32 speed_hz; /* spi-clk rate */
u32 mode;
@@ -224,9 +224,9 @@ static void pic32_err_stop(struct pic32_spi *pic32s, const char *msg)
disable_irq_nosync(pic32s->tx_irq);
/* Show err message and abort xfer with err */
- dev_err(&pic32s->master->dev, "%s\n", msg);
- if (pic32s->master->cur_msg)
- pic32s->master->cur_msg->status = -EIO;
+ dev_err(&pic32s->host->dev, "%s\n", msg);
+ if (pic32s->host->cur_msg)
+ pic32s->host->cur_msg->status = -EIO;
complete(&pic32s->xfer_done);
}
@@ -250,7 +250,7 @@ static irqreturn_t pic32_spi_fault_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
- if (!pic32s->master->cur_msg) {
+ if (!pic32s->host->cur_msg) {
pic32_err_stop(pic32s, "err_irq: no mesg");
return IRQ_NONE;
}
@@ -300,16 +300,16 @@ static void pic32_spi_dma_rx_notify(void *data)
static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
struct spi_transfer *xfer)
{
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
struct dma_async_tx_descriptor *desc_rx;
struct dma_async_tx_descriptor *desc_tx;
dma_cookie_t cookie;
int ret;
- if (!master->dma_rx || !master->dma_tx)
+ if (!host->dma_rx || !host->dma_tx)
return -ENODEV;
- desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+ desc_rx = dmaengine_prep_slave_sg(host->dma_rx,
xfer->rx_sg.sgl,
xfer->rx_sg.nents,
DMA_DEV_TO_MEM,
@@ -319,7 +319,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
goto err_dma;
}
- desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+ desc_tx = dmaengine_prep_slave_sg(host->dma_tx,
xfer->tx_sg.sgl,
xfer->tx_sg.nents,
DMA_MEM_TO_DEV,
@@ -343,13 +343,13 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
if (ret)
goto err_dma_tx;
- dma_async_issue_pending(master->dma_rx);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_rx);
+ dma_async_issue_pending(host->dma_tx);
return 0;
err_dma_tx:
- dmaengine_terminate_all(master->dma_rx);
+ dmaengine_terminate_all(host->dma_rx);
err_dma:
return ret;
}
@@ -357,7 +357,7 @@ err_dma:
static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width)
{
int buf_offset = offsetof(struct pic32_spi_regs, buf);
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
struct dma_slave_config cfg;
int ret;
@@ -371,16 +371,16 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width)
cfg.dst_addr_width = dma_width;
/* tx channel */
cfg.direction = DMA_MEM_TO_DEV;
- ret = dmaengine_slave_config(master->dma_tx, &cfg);
+ ret = dmaengine_slave_config(host->dma_tx, &cfg);
if (ret) {
- dev_err(&master->dev, "tx channel setup failed\n");
+ dev_err(&host->dev, "tx channel setup failed\n");
return ret;
}
/* rx channel */
cfg.direction = DMA_DEV_TO_MEM;
- ret = dmaengine_slave_config(master->dma_rx, &cfg);
+ ret = dmaengine_slave_config(host->dma_rx, &cfg);
if (ret)
- dev_err(&master->dev, "rx channel setup failed\n");
+ dev_err(&host->dev, "rx channel setup failed\n");
return ret;
}
@@ -430,19 +430,19 @@ static int pic32_spi_set_word_size(struct pic32_spi *pic32s, u8 bits_per_word)
return 0;
}
-static int pic32_spi_prepare_hardware(struct spi_master *master)
+static int pic32_spi_prepare_hardware(struct spi_controller *host)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
pic32_spi_enable(pic32s);
return 0;
}
-static int pic32_spi_prepare_message(struct spi_master *master,
+static int pic32_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
u32 val;
@@ -481,18 +481,18 @@ static int pic32_spi_prepare_message(struct spi_master *master,
return 0;
}
-static bool pic32_spi_can_dma(struct spi_master *master,
+static bool pic32_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
/* skip using DMA on small size transfer to avoid overhead.*/
return (xfer->len >= PIC32_DMA_LEN_MIN) &&
test_bit(PIC32F_DMA_PREP, &pic32s->flags);
}
-static int pic32_spi_one_transfer(struct spi_master *master,
+static int pic32_spi_one_transfer(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *transfer)
{
@@ -501,7 +501,7 @@ static int pic32_spi_one_transfer(struct spi_master *master,
unsigned long timeout;
int ret;
- pic32s = spi_master_get_devdata(master);
+ pic32s = spi_controller_get_devdata(host);
/* handle transfer specific word size change */
if (transfer->bits_per_word &&
@@ -549,8 +549,8 @@ static int pic32_spi_one_transfer(struct spi_master *master,
if (timeout == 0) {
dev_err(&spi->dev, "wait error/timedout\n");
if (dma_issued) {
- dmaengine_terminate_all(master->dma_rx);
- dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(host->dma_rx);
+ dmaengine_terminate_all(host->dma_tx);
}
ret = -ETIMEDOUT;
} else {
@@ -560,16 +560,16 @@ static int pic32_spi_one_transfer(struct spi_master *master,
return ret;
}
-static int pic32_spi_unprepare_message(struct spi_master *master,
+static int pic32_spi_unprepare_message(struct spi_controller *host,
struct spi_message *msg)
{
/* nothing to do */
return 0;
}
-static int pic32_spi_unprepare_hardware(struct spi_master *master)
+static int pic32_spi_unprepare_hardware(struct spi_controller *host)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
pic32_spi_disable(pic32s);
@@ -605,28 +605,28 @@ static void pic32_spi_cleanup(struct spi_device *spi)
static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
{
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
int ret = 0;
- master->dma_rx = dma_request_chan(dev, "spi-rx");
- if (IS_ERR(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER)
+ host->dma_rx = dma_request_chan(dev, "spi-rx");
+ if (IS_ERR(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
dev_warn(dev, "RX channel not found.\n");
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
goto out_err;
}
- master->dma_tx = dma_request_chan(dev, "spi-tx");
- if (IS_ERR(master->dma_tx)) {
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER)
+ host->dma_tx = dma_request_chan(dev, "spi-tx");
+ if (IS_ERR(host->dma_tx)) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
dev_warn(dev, "TX channel not found.\n");
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
goto out_err;
}
@@ -639,14 +639,14 @@ static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
return 0;
out_err:
- if (master->dma_rx) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (host->dma_rx) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
}
- if (master->dma_tx) {
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (host->dma_tx) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
}
return ret;
@@ -658,11 +658,11 @@ static void pic32_spi_dma_unprep(struct pic32_spi *pic32s)
return;
clear_bit(PIC32F_DMA_PREP, &pic32s->flags);
- if (pic32s->master->dma_rx)
- dma_release_channel(pic32s->master->dma_rx);
+ if (pic32s->host->dma_rx)
+ dma_release_channel(pic32s->host->dma_rx);
- if (pic32s->master->dma_tx)
- dma_release_channel(pic32s->master->dma_tx);
+ if (pic32s->host->dma_tx)
+ dma_release_channel(pic32s->host->dma_tx);
}
static void pic32_spi_hw_init(struct pic32_spi *pic32s)
@@ -680,7 +680,7 @@ static void pic32_spi_hw_init(struct pic32_spi *pic32s)
/* disable framing mode */
ctrl &= ~CTRL_FRMEN;
- /* enable master mode while disabled */
+ /* enable host mode while disabled */
ctrl |= CTRL_MSTEN;
/* set tx fifo threshold interrupt */
@@ -752,36 +752,36 @@ err_unmap_mem:
static int pic32_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct pic32_spi *pic32s;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*pic32s));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*pic32s));
+ if (!host)
return -ENOMEM;
- pic32s = spi_master_get_devdata(master);
- pic32s->master = master;
+ pic32s = spi_controller_get_devdata(host);
+ pic32s->host = host;
ret = pic32_spi_hw_probe(pdev, pic32s);
if (ret)
- goto err_master;
-
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
- master->num_chipselect = 1; /* single chip-select */
- master->max_speed_hz = clk_get_rate(pic32s->clk);
- master->setup = pic32_spi_setup;
- master->cleanup = pic32_spi_cleanup;
- master->flags = SPI_MASTER_MUST_TX | SPI_MASTER_MUST_RX;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ goto err_host;
+
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
+ host->num_chipselect = 1; /* single chip-select */
+ host->max_speed_hz = clk_get_rate(pic32s->clk);
+ host->setup = pic32_spi_setup;
+ host->cleanup = pic32_spi_cleanup;
+ host->flags = SPI_CONTROLLER_MUST_TX | SPI_CONTROLLER_MUST_RX;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(32);
- master->transfer_one = pic32_spi_one_transfer;
- master->prepare_message = pic32_spi_prepare_message;
- master->unprepare_message = pic32_spi_unprepare_message;
- master->prepare_transfer_hardware = pic32_spi_prepare_hardware;
- master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
- master->use_gpio_descriptors = true;
+ host->transfer_one = pic32_spi_one_transfer;
+ host->prepare_message = pic32_spi_prepare_message;
+ host->unprepare_message = pic32_spi_unprepare_message;
+ host->prepare_transfer_hardware = pic32_spi_prepare_hardware;
+ host->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
+ host->use_gpio_descriptors = true;
/* optional DMA support */
ret = pic32_spi_dma_prep(pic32s, &pdev->dev);
@@ -789,7 +789,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
goto err_bailout;
if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
- master->can_dma = pic32_spi_can_dma;
+ host->can_dma = pic32_spi_can_dma;
init_completion(&pic32s->xfer_done);
pic32s->mode = -1;
@@ -824,10 +824,10 @@ static int pic32_spi_probe(struct platform_device *pdev)
goto err_bailout;
}
- /* register master */
- ret = devm_spi_register_master(&pdev->dev, master);
+ /* register host */
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&master->dev, "failed registering spi master\n");
+ dev_err(&host->dev, "failed registering spi host\n");
goto err_bailout;
}
@@ -838,8 +838,8 @@ static int pic32_spi_probe(struct platform_device *pdev)
err_bailout:
pic32_spi_dma_unprep(pic32s);
clk_disable_unprepare(pic32s->clk);
-err_master:
- spi_master_put(master);
+err_host:
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 1af75eff26b6..bb347b6bb6f3 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -336,8 +336,8 @@ struct vendor_data {
* @phybase: the physical memory where the SSP device resides
* @virtbase: the virtual memory where the SSP is mapped
* @clk: outgoing clock "SPICLK" for the SPI bus
- * @master: SPI framework hookup
- * @master_info: controller-specific data from machine setup
+ * @host: SPI framework hookup
+ * @host_info: controller-specific data from machine setup
* @pump_transfers: Tasklet used in Interrupt Transfer mode
* @cur_msg: Pointer to current spi_message being processed
* @cur_transfer: Pointer to current spi_transfer
@@ -370,8 +370,8 @@ struct pl022 {
resource_size_t phybase;
void __iomem *virtbase;
struct clk *clk;
- struct spi_master *master;
- struct pl022_ssp_controller *master_info;
+ struct spi_controller *host;
+ struct pl022_ssp_controller *host_info;
/* Message per-transfer pump */
struct tasklet_struct pump_transfers;
struct spi_message *cur_msg;
@@ -500,7 +500,7 @@ static void giveback(struct pl022 *pl022)
* could invalidate the cs_control() callback...
*/
/* get a pointer to the next message, if any */
- next_msg = spi_get_next_queued_message(pl022->master);
+ next_msg = spi_get_next_queued_message(pl022->host);
/*
* see if the next and current messages point
@@ -523,7 +523,7 @@ static void giveback(struct pl022 *pl022)
writew((readw(SSP_CR1(pl022->virtbase)) &
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
- spi_finalize_current_message(pl022->master);
+ spi_finalize_current_message(pl022->host);
}
/**
@@ -1110,16 +1110,16 @@ static int pl022_dma_probe(struct pl022 *pl022)
* of them.
*/
pl022->dma_rx_channel = dma_request_channel(mask,
- pl022->master_info->dma_filter,
- pl022->master_info->dma_rx_param);
+ pl022->host_info->dma_filter,
+ pl022->host_info->dma_rx_param);
if (!pl022->dma_rx_channel) {
dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n");
goto err_no_rxchan;
}
pl022->dma_tx_channel = dma_request_channel(mask,
- pl022->master_info->dma_filter,
- pl022->master_info->dma_tx_param);
+ pl022->host_info->dma_filter,
+ pl022->host_info->dma_tx_param);
if (!pl022->dma_tx_channel) {
dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n");
goto err_no_txchan;
@@ -1573,10 +1573,10 @@ out:
return;
}
-static int pl022_transfer_one_message(struct spi_master *master,
+static int pl022_transfer_one_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct pl022 *pl022 = spi_master_get_devdata(master);
+ struct pl022 *pl022 = spi_controller_get_devdata(host);
/* Initial message state */
pl022->cur_msg = msg;
@@ -1602,9 +1602,9 @@ static int pl022_transfer_one_message(struct spi_master *master,
return 0;
}
-static int pl022_unprepare_transfer_hardware(struct spi_master *master)
+static int pl022_unprepare_transfer_hardware(struct spi_controller *host)
{
- struct pl022 *pl022 = spi_master_get_devdata(master);
+ struct pl022 *pl022 = spi_controller_get_devdata(host);
/* nothing more to do - disable spi/ssp and power off */
writew((readw(SSP_CR1(pl022->virtbase)) &
@@ -1826,10 +1826,10 @@ static const struct pl022_config_chip pl022_default_chip_info = {
};
/**
- * pl022_setup - setup function registered to SPI master framework
+ * pl022_setup - setup function registered to SPI host framework
* @spi: spi device which is requesting setup
*
- * This function is registered to the SPI framework for this SPI master
+ * This function is registered to the SPI framework for this SPI host
* controller. If it is the first time when setup is called by this device,
* this function will initialize the runtime state for this chip and save
* the same in the device structure. Else it will update the runtime info
@@ -1844,7 +1844,7 @@ static int pl022_setup(struct spi_device *spi)
struct chip_data *chip;
struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
int status = 0;
- struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+ struct pl022 *pl022 = spi_controller_get_devdata(spi->controller);
unsigned int bits = spi->bits_per_word;
u32 tmp;
struct device_node *np = spi->dev.of_node;
@@ -1964,7 +1964,7 @@ static int pl022_setup(struct spi_device *spi)
chip->dmacr = 0;
chip->cpsr = 0;
if ((chip_info->com_mode == DMA_TRANSFER)
- && ((pl022->master_info)->enable_dma)) {
+ && ((pl022->host_info)->enable_dma)) {
chip->enable_dma = true;
dev_dbg(&spi->dev, "DMA mode set in controller state\n");
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
@@ -2061,10 +2061,10 @@ static int pl022_setup(struct spi_device *spi)
}
/**
- * pl022_cleanup - cleanup function registered to SPI master framework
+ * pl022_cleanup - cleanup function registered to SPI host framework
* @spi: spi device which is requesting cleanup
*
- * This function is registered to the SPI framework for this SPI master
+ * This function is registered to the SPI framework for this SPI host
* controller. It will free the runtime state of chip.
*/
static void pl022_cleanup(struct spi_device *spi)
@@ -2103,7 +2103,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
struct device *dev = &adev->dev;
struct pl022_ssp_controller *platform_info =
dev_get_platdata(&adev->dev);
- struct spi_master *master;
+ struct spi_controller *host;
struct pl022 *pl022 = NULL; /*Data for this driver */
int status = 0;
@@ -2117,16 +2117,16 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
return -ENODEV;
}
- /* Allocate master with space for data */
- master = spi_alloc_master(dev, sizeof(struct pl022));
- if (master == NULL) {
- dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
+ /* Allocate host with space for data */
+ host = spi_alloc_host(dev, sizeof(struct pl022));
+ if (host == NULL) {
+ dev_err(&adev->dev, "probe - cannot alloc SPI host\n");
return -ENOMEM;
}
- pl022 = spi_master_get_devdata(master);
- pl022->master = master;
- pl022->master_info = platform_info;
+ pl022 = spi_controller_get_devdata(host);
+ pl022->host = host;
+ pl022->host_info = platform_info;
pl022->adev = adev;
pl022->vendor = id->data;
@@ -2134,25 +2134,25 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
* Bus Number Which has been Assigned to this SSP controller
* on this board
*/
- master->bus_num = platform_info->bus_id;
- master->cleanup = pl022_cleanup;
- master->setup = pl022_setup;
- master->auto_runtime_pm = true;
- master->transfer_one_message = pl022_transfer_one_message;
- master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
- master->rt = platform_info->rt;
- master->dev.of_node = dev->of_node;
- master->use_gpio_descriptors = true;
+ host->bus_num = platform_info->bus_id;
+ host->cleanup = pl022_cleanup;
+ host->setup = pl022_setup;
+ host->auto_runtime_pm = true;
+ host->transfer_one_message = pl022_transfer_one_message;
+ host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
+ host->rt = platform_info->rt;
+ host->dev.of_node = dev->of_node;
+ host->use_gpio_descriptors = true;
/*
* Supports mode 0-3, loopback, and active low CS. Transfers are
* always MS bit first on the original pl022.
*/
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
if (pl022->vendor->extended_cr)
- master->mode_bits |= SPI_LSB_FIRST;
+ host->mode_bits |= SPI_LSB_FIRST;
- dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
+ dev_dbg(&adev->dev, "BUSNO: %d\n", host->bus_num);
status = amba_request_regions(adev, NULL);
if (status)
@@ -2215,10 +2215,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
/* Register with the SPI framework */
amba_set_drvdata(adev, pl022);
- status = devm_spi_register_master(&adev->dev, master);
+ status = devm_spi_register_controller(&adev->dev, host);
if (status != 0) {
dev_err_probe(&adev->dev, status,
- "problem registering spi master\n");
+ "problem registering spi host\n");
goto err_spi_register;
}
dev_dbg(dev, "probe succeeded\n");
@@ -2246,7 +2246,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
err_no_ioremap:
amba_release_regions(adev);
err_no_ioregion:
- spi_master_put(master);
+ spi_controller_put(host);
return status;
}
@@ -2265,7 +2265,7 @@ pl022_remove(struct amba_device *adev)
pm_runtime_get_noresume(&adev->dev);
load_ssp_default_config(pl022);
- if (pl022->master_info->enable_dma)
+ if (pl022->host_info->enable_dma)
pl022_dma_remove(pl022);
clk_disable_unprepare(pl022->clk);
@@ -2279,13 +2279,13 @@ static int pl022_suspend(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(pl022->master);
+ ret = spi_controller_suspend(pl022->host);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);
if (ret) {
- spi_master_resume(pl022->master);
+ spi_controller_resume(pl022->host);
return ret;
}
@@ -2305,7 +2305,7 @@ static int pl022_resume(struct device *dev)
dev_err(dev, "problem resuming\n");
/* Start the queue running */
- ret = spi_master_resume(pl022->master);
+ ret = spi_controller_resume(pl022->host);
if (!ret)
dev_dbg(dev, "resumed\n");
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index d725e915025d..03aab661be9d 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -126,7 +126,7 @@ struct ppc4xx_spi {
unsigned char *rx;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
};
@@ -143,7 +143,7 @@ static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
- hw = spi_master_get_devdata(spi->master);
+ hw = spi_controller_get_devdata(spi->controller);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -161,7 +161,7 @@ static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
- struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ struct ppc4xx_spi *hw = spi_controller_get_devdata(spi->controller);
struct spi_ppc4xx_cs *cs = spi->controller_state;
int scr;
u8 cdm = 0;
@@ -340,7 +340,7 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
static int spi_ppc4xx_of_probe(struct platform_device *op)
{
struct ppc4xx_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_bitbang *bbp;
struct resource resource;
struct device_node *np = op->dev.of_node;
@@ -349,20 +349,20 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
int ret;
const unsigned int *clk;
- master = spi_alloc_master(dev, sizeof(*hw));
- if (master == NULL)
+ host = spi_alloc_host(dev, sizeof(*hw));
+ if (host == NULL)
return -ENOMEM;
- master->dev.of_node = np;
- platform_set_drvdata(op, master);
- hw = spi_master_get_devdata(master);
- hw->master = master;
+ host->dev.of_node = np;
+ platform_set_drvdata(op, host);
+ hw = spi_controller_get_devdata(host);
+ hw->host = host;
hw->dev = dev;
init_completion(&hw->done);
/* Setup the state for the bitbang driver */
bbp = &hw->bitbang;
- bbp->master = hw->master;
+ bbp->master = hw->host;
bbp->setup_transfer = spi_ppc4xx_setupxfer;
bbp->txrx_bufs = spi_ppc4xx_txrx;
bbp->use_dma = 0;
@@ -385,7 +385,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (opbnp == NULL) {
dev_err(dev, "OPB: cannot find node\n");
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
/* Get the clock (Hz) for the OPB */
clk = of_get_property(opbnp, "clock-frequency", NULL);
@@ -393,7 +393,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev_err(dev, "OPB: no clock-frequency property set\n");
of_node_put(opbnp);
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
hw->opb_freq = *clk;
hw->opb_freq >>= 2;
@@ -402,7 +402,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_err(dev, "error while parsing device node resource\n");
- goto free_master;
+ goto free_host;
}
hw->mapbase = resource.start;
hw->mapsize = resource_size(&resource);
@@ -411,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
dev_err(dev, "too small to map registers\n");
ret = -EINVAL;
- goto free_master;
+ goto free_host;
}
/* Request IRQ */
@@ -420,7 +420,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
0, "spi_ppc4xx_of", (void *)hw);
if (ret) {
dev_err(dev, "unable to allocate interrupt\n");
- goto free_master;
+ goto free_host;
}
if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
@@ -443,7 +443,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev->dma_mask = 0;
ret = spi_bitbang_start(bbp);
if (ret) {
- dev_err(dev, "failed to register SPI master\n");
+ dev_err(dev, "failed to register SPI host\n");
goto unmap_regs;
}
@@ -457,8 +457,8 @@ map_io_error:
release_mem_region(hw->mapbase, hw->mapsize);
request_mem_error:
free_irq(hw->irqnum, hw);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
dev_err(dev, "initialization failed\n");
return ret;
@@ -466,14 +466,14 @@ free_master:
static void spi_ppc4xx_of_remove(struct platform_device *op)
{
- struct spi_master *master = platform_get_drvdata(op);
- struct ppc4xx_spi *hw = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(op);
+ struct ppc4xx_spi *hw = spi_controller_get_devdata(host);
spi_bitbang_stop(&hw->bitbang);
release_mem_region(hw->mapbase, hw->mapsize);
free_irq(hw->irqnum, hw);
iounmap(hw->regs);
- spi_master_put(master);
+ spi_controller_put(host);
}
static const struct of_device_id spi_ppc4xx_of_match[] = {
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 1bab18a0f262..f2a856f6a99e 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1102,7 +1102,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
}
}
- if (spi_controller_is_slave(controller)) {
+ if (spi_controller_is_target(controller)) {
while (drv_data->write(drv_data))
;
if (drv_data->gpiod_ready) {
@@ -1121,7 +1121,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
return 1;
}
-static int pxa2xx_spi_slave_abort(struct spi_controller *controller)
+static int pxa2xx_spi_target_abort(struct spi_controller *controller)
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
@@ -1199,7 +1199,7 @@ static int setup(struct spi_device *spi)
break;
default:
tx_hi_thres = 0;
- if (spi_controller_is_slave(drv_data->controller)) {
+ if (spi_controller_is_target(drv_data->controller)) {
tx_thres = 1;
rx_thres = 2;
} else {
@@ -1248,7 +1248,7 @@ static int setup(struct spi_device *spi)
}
chip->cr1 = 0;
- if (spi_controller_is_slave(drv_data->controller)) {
+ if (spi_controller_is_target(drv_data->controller)) {
chip->cr1 |= SSCR1_SCFR;
chip->cr1 |= SSCR1_SCLKDIR;
chip->cr1 |= SSCR1_SFRMDIR;
@@ -1344,7 +1344,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
match = device_get_match_data(dev);
if (match)
- type = (enum pxa_ssp_type)match;
+ type = (uintptr_t)match;
else if (is_lpss_priv) {
u32 value;
@@ -1395,7 +1395,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
else
ssp->port_id = uid;
- pdata->is_slave = device_property_read_bool(dev, "spi-slave");
+ pdata->is_target = device_property_read_bool(dev, "spi-slave");
pdata->num_chipselect = 1;
pdata->enable_dma = true;
pdata->dma_burst_size = 1;
@@ -1461,10 +1461,10 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (platform_info->is_slave)
- controller = devm_spi_alloc_slave(dev, sizeof(*drv_data));
+ if (platform_info->is_target)
+ controller = devm_spi_alloc_target(dev, sizeof(*drv_data));
else
- controller = devm_spi_alloc_master(dev, sizeof(*drv_data));
+ controller = devm_spi_alloc_host(dev, sizeof(*drv_data));
if (!controller) {
dev_err(&pdev->dev, "cannot alloc spi_controller\n");
@@ -1487,7 +1487,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller->setup = setup;
controller->set_cs = pxa2xx_spi_set_cs;
controller->transfer_one = pxa2xx_spi_transfer_one;
- controller->slave_abort = pxa2xx_spi_slave_abort;
+ controller->target_abort = pxa2xx_spi_target_abort;
controller->handle_err = pxa2xx_spi_handle_err;
controller->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
controller->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
@@ -1579,7 +1579,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
break;
default:
- if (spi_controller_is_slave(controller)) {
+ if (spi_controller_is_target(controller)) {
tmp = SSCR1_SCFR |
SSCR1_SCLKDIR |
SSCR1_SFRMDIR |
@@ -1592,7 +1592,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
}
pxa2xx_spi_write(drv_data, SSCR1, tmp);
tmp = SSCR0_Motorola | SSCR0_DataSize(8);
- if (!spi_controller_is_slave(controller))
+ if (!spi_controller_is_target(controller))
tmp |= SSCR0_SCR(2);
pxa2xx_spi_write(drv_data, SSCR0, tmp);
break;
@@ -1620,7 +1620,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller->num_chipselect = platform_info->num_chipselect;
controller->use_gpio_descriptors = true;
- if (platform_info->is_slave) {
+ if (platform_info->is_target) {
drv_data->gpiod_ready = devm_gpiod_get_optional(dev,
"ready", GPIOD_OUT_LOW);
if (IS_ERR(drv_data->gpiod_ready)) {
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
index 1954c39b3d08..49b775134485 100644
--- a/drivers/spi/spi-qcom-qspi.c
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -9,7 +9,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/pm_opp.h>
@@ -247,11 +247,11 @@ static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl)
qcom_qspi_pio_xfer_ctrl(ctrl);
}
-static void qcom_qspi_handle_err(struct spi_master *master,
+static void qcom_qspi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
u32 int_status;
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
unsigned long flags;
int i;
@@ -411,11 +411,11 @@ static bool qcom_qspi_can_dma(struct spi_controller *ctlr,
return xfer->len > QSPI_MAX_BYTES_FIFO;
}
-static int qcom_qspi_transfer_one(struct spi_master *master,
+static int qcom_qspi_transfer_one(struct spi_controller *host,
struct spi_device *slv,
struct spi_transfer *xfer)
{
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
unsigned long speed_hz;
unsigned long flags;
@@ -443,7 +443,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
ctrl->xfer.tx_buf = xfer->tx_buf;
}
ctrl->xfer.is_last = list_is_last(&xfer->transfer_list,
- &master->cur_msg->transfers);
+ &host->cur_msg->transfers);
ctrl->xfer.rem_bytes = xfer->len;
if (xfer->rx_sg.nents || xfer->tx_sg.nents) {
@@ -481,7 +481,7 @@ exit:
return 1;
}
-static int qcom_qspi_prepare_message(struct spi_master *master,
+static int qcom_qspi_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
u32 mstr_cfg;
@@ -490,7 +490,7 @@ static int qcom_qspi_prepare_message(struct spi_master *master,
int tx_data_delay = 1;
unsigned long flags;
- ctrl = spi_master_get_devdata(master);
+ ctrl = spi_controller_get_devdata(host);
spin_lock_irqsave(&ctrl->lock, flags);
mstr_cfg = readl(ctrl->base + MSTR_CONFIG);
@@ -694,18 +694,18 @@ static int qcom_qspi_probe(struct platform_device *pdev)
{
int ret;
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct qcom_qspi *ctrl;
dev = &pdev->dev;
- master = devm_spi_alloc_master(dev, sizeof(*ctrl));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*ctrl));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- ctrl = spi_master_get_devdata(master);
+ ctrl = spi_controller_get_devdata(host);
spin_lock_init(&ctrl->lock);
ctrl->dev = dev;
@@ -758,23 +758,23 @@ static int qcom_qspi_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "could not set DMA mask\n");
- master->max_speed_hz = 300000000;
- master->max_dma_len = 65536; /* as per HPG */
- master->dma_alignment = QSPI_ALIGN_REQ;
- master->num_chipselect = QSPI_NUM_CS;
- master->bus_num = -1;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_0 |
- SPI_TX_DUAL | SPI_RX_DUAL |
- SPI_TX_QUAD | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->prepare_message = qcom_qspi_prepare_message;
- master->transfer_one = qcom_qspi_transfer_one;
- master->handle_err = qcom_qspi_handle_err;
+ host->max_speed_hz = 300000000;
+ host->max_dma_len = 65536; /* as per HPG */
+ host->dma_alignment = QSPI_ALIGN_REQ;
+ host->num_chipselect = QSPI_NUM_CS;
+ host->bus_num = -1;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_0 |
+ SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->prepare_message = qcom_qspi_prepare_message;
+ host->transfer_one = qcom_qspi_transfer_one;
+ host->handle_err = qcom_qspi_handle_err;
if (of_property_read_bool(pdev->dev.of_node, "iommus"))
- master->can_dma = qcom_qspi_can_dma;
- master->auto_runtime_pm = true;
- master->mem_ops = &qcom_qspi_mem_ops;
+ host->can_dma = qcom_qspi_can_dma;
+ host->auto_runtime_pm = true;
+ host->mem_ops = &qcom_qspi_mem_ops;
ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
if (ret)
@@ -794,7 +794,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(dev, 250);
pm_runtime_enable(dev);
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (!ret)
return 0;
@@ -805,18 +805,18 @@ static int qcom_qspi_probe(struct platform_device *pdev)
static void qcom_qspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_controller *host = platform_get_drvdata(pdev);
/* Unregister _before_ disabling pm_runtime() so we stop transfers */
- spi_unregister_master(master);
+ spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
}
static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
/* Drop the performance state vote */
@@ -837,8 +837,8 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
pinctrl_pm_select_default_state(dev);
@@ -859,30 +859,30 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
static int __maybe_unused qcom_qspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
- spi_master_resume(master);
+ spi_controller_resume(host);
return ret;
}
static int __maybe_unused qcom_qspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
pm_runtime_force_suspend(dev);
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 00e5e88e72c4..4b6f6b25219b 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -11,7 +11,6 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -386,20 +385,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+static int spi_qup_prep_sg(struct spi_controller *host, struct scatterlist *sgl,
unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_qup *qup = spi_controller_get_devdata(host);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan;
dma_cookie_t cookie;
if (dir == DMA_MEM_TO_DEV)
- chan = master->dma_tx;
+ chan = host->dma_tx;
else
- chan = master->dma_rx;
+ chan = host->dma_rx;
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -413,13 +412,13 @@ static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
return dma_submit_error(cookie);
}
-static void spi_qup_dma_terminate(struct spi_master *master,
+static void spi_qup_dma_terminate(struct spi_controller *host,
struct spi_transfer *xfer)
{
if (xfer->tx_buf)
- dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(host->dma_tx);
if (xfer->rx_buf)
- dmaengine_terminate_all(master->dma_rx);
+ dmaengine_terminate_all(host->dma_rx);
}
static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
@@ -446,8 +445,8 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
- struct spi_master *master = spi->master;
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct spi_qup *qup = spi_controller_get_devdata(host);
struct scatterlist *tx_sgl, *rx_sgl;
int ret;
@@ -482,20 +481,20 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
return ret;
}
if (rx_sgl) {
- ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
+ ret = spi_qup_prep_sg(host, rx_sgl, rx_nents,
DMA_DEV_TO_MEM, rx_done);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (tx_sgl) {
- ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
+ ret = spi_qup_prep_sg(host, tx_sgl, tx_nents,
DMA_MEM_TO_DEV, tx_done);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
if (!wait_for_completion_timeout(&qup->done, timeout))
@@ -514,8 +513,8 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
- struct spi_master *master = spi->master;
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct spi_qup *qup = spi_controller_get_devdata(host);
int ret, n_words, iterations, offset = 0;
n_words = qup->n_words;
@@ -659,7 +658,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
/* set clock freq ... bits per word, determine mode */
static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
int ret;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -680,9 +679,9 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
controller->mode = QUP_IO_M_MODE_FIFO;
- else if (spi->master->can_dma &&
- spi->master->can_dma(spi->master, spi, xfer) &&
- spi->master->cur_msg_mapped)
+ else if (spi->controller->can_dma &&
+ spi->controller->can_dma(spi->controller, spi, xfer) &&
+ spi->controller->cur_msg_mapped)
controller->mode = QUP_IO_M_MODE_BAM;
else
controller->mode = QUP_IO_M_MODE_BLOCK;
@@ -693,7 +692,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
/* prep qup for another spi transaction of specific type */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
u32 config, iomode, control;
unsigned long flags;
@@ -841,11 +840,11 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
return 0;
}
-static int spi_qup_transfer_one(struct spi_master *master,
+static int spi_qup_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
unsigned long timeout, flags;
int ret;
@@ -879,21 +878,21 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (ret && spi_qup_is_dma_xfer(controller->mode))
- spi_qup_dma_terminate(master, xfer);
+ spi_qup_dma_terminate(host, xfer);
return ret;
}
-static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
+static bool spi_qup_can_dma(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_qup *qup = spi_controller_get_devdata(host);
size_t dma_align = dma_get_cache_alignment();
int n_words;
if (xfer->rx_buf) {
if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
- IS_ERR_OR_NULL(master->dma_rx))
+ IS_ERR_OR_NULL(host->dma_rx))
return false;
if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
return false;
@@ -901,7 +900,7 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
if (xfer->tx_buf) {
if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
- IS_ERR_OR_NULL(master->dma_tx))
+ IS_ERR_OR_NULL(host->dma_tx))
return false;
if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
return false;
@@ -914,30 +913,30 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
return true;
}
-static void spi_qup_release_dma(struct spi_master *master)
+static void spi_qup_release_dma(struct spi_controller *host)
{
- if (!IS_ERR_OR_NULL(master->dma_rx))
- dma_release_channel(master->dma_rx);
- if (!IS_ERR_OR_NULL(master->dma_tx))
- dma_release_channel(master->dma_tx);
+ if (!IS_ERR_OR_NULL(host->dma_rx))
+ dma_release_channel(host->dma_rx);
+ if (!IS_ERR_OR_NULL(host->dma_tx))
+ dma_release_channel(host->dma_tx);
}
-static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
+static int spi_qup_init_dma(struct spi_controller *host, resource_size_t base)
{
- struct spi_qup *spi = spi_master_get_devdata(master);
+ struct spi_qup *spi = spi_controller_get_devdata(host);
struct dma_slave_config *rx_conf = &spi->rx_conf,
*tx_conf = &spi->tx_conf;
struct device *dev = spi->dev;
int ret;
/* allocate dma resources, if available */
- master->dma_rx = dma_request_chan(dev, "rx");
- if (IS_ERR(master->dma_rx))
- return PTR_ERR(master->dma_rx);
+ host->dma_rx = dma_request_chan(dev, "rx");
+ if (IS_ERR(host->dma_rx))
+ return PTR_ERR(host->dma_rx);
- master->dma_tx = dma_request_chan(dev, "tx");
- if (IS_ERR(master->dma_tx)) {
- ret = PTR_ERR(master->dma_tx);
+ host->dma_tx = dma_request_chan(dev, "tx");
+ if (IS_ERR(host->dma_tx)) {
+ ret = PTR_ERR(host->dma_tx);
goto err_tx;
}
@@ -952,13 +951,13 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
tx_conf->dst_addr = base + QUP_OUTPUT_FIFO;
tx_conf->dst_maxburst = spi->out_blk_sz;
- ret = dmaengine_slave_config(master->dma_rx, rx_conf);
+ ret = dmaengine_slave_config(host->dma_rx, rx_conf);
if (ret) {
dev_err(dev, "failed to configure RX channel\n");
goto err;
}
- ret = dmaengine_slave_config(master->dma_tx, tx_conf);
+ ret = dmaengine_slave_config(host->dma_tx, tx_conf);
if (ret) {
dev_err(dev, "failed to configure TX channel\n");
goto err;
@@ -967,9 +966,9 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
return 0;
err:
- dma_release_channel(master->dma_tx);
+ dma_release_channel(host->dma_tx);
err_tx:
- dma_release_channel(master->dma_rx);
+ dma_release_channel(host->dma_rx);
return ret;
}
@@ -979,7 +978,7 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
u32 spi_ioc;
u32 spi_ioc_orig;
- controller = spi_master_get_devdata(spi->master);
+ controller = spi_controller_get_devdata(spi->controller);
spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
spi_ioc_orig = spi_ioc;
if (!val)
@@ -993,7 +992,7 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
static int spi_qup_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *iclk, *cclk;
struct spi_qup *controller;
struct resource *res;
@@ -1028,34 +1027,34 @@ static int spi_qup_probe(struct platform_device *pdev)
return -ENXIO;
}
- master = spi_alloc_master(dev, sizeof(struct spi_qup));
- if (!master) {
- dev_err(dev, "cannot allocate master\n");
+ host = spi_alloc_host(dev, sizeof(struct spi_qup));
+ if (!host) {
+ dev_err(dev, "cannot allocate host\n");
return -ENOMEM;
}
/* use num-cs unless not present or out of range */
if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
num_cs > SPI_NUM_CHIPSELECTS)
- master->num_chipselect = SPI_NUM_CHIPSELECTS;
+ host->num_chipselect = SPI_NUM_CHIPSELECTS;
else
- master->num_chipselect = num_cs;
+ host->num_chipselect = num_cs;
- master->use_gpio_descriptors = true;
- master->max_native_cs = SPI_NUM_CHIPSELECTS;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->max_speed_hz = max_freq;
- master->transfer_one = spi_qup_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_XFER;
+ host->use_gpio_descriptors = true;
+ host->max_native_cs = SPI_NUM_CHIPSELECTS;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->max_speed_hz = max_freq;
+ host->transfer_one = spi_qup_transfer_one;
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->dma_alignment = dma_get_cache_alignment();
+ host->max_dma_len = SPI_MAX_XFER;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- controller = spi_master_get_devdata(master);
+ controller = spi_controller_get_devdata(host);
controller->dev = dev;
controller->base = base;
@@ -1063,16 +1062,16 @@ static int spi_qup_probe(struct platform_device *pdev)
controller->cclk = cclk;
controller->irq = irq;
- ret = spi_qup_init_dma(master, res->start);
+ ret = spi_qup_init_dma(host, res->start);
if (ret == -EPROBE_DEFER)
goto error;
else if (!ret)
- master->can_dma = spi_qup_can_dma;
+ host->can_dma = spi_qup_can_dma;
controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev);
if (!controller->qup_v1)
- master->set_cs = spi_qup_set_cs;
+ host->set_cs = spi_qup_set_cs;
spin_lock_init(&controller->lock);
init_completion(&controller->done);
@@ -1150,7 +1149,7 @@ static int spi_qup_probe(struct platform_device *pdev)
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto disable_pm;
@@ -1162,17 +1161,17 @@ error_clk:
clk_disable_unprepare(cclk);
clk_disable_unprepare(iclk);
error_dma:
- spi_qup_release_dma(master);
+ spi_qup_release_dma(host);
error:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
#ifdef CONFIG_PM
static int spi_qup_pm_suspend_runtime(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
u32 config;
/* Enable clocks auto gaiting */
@@ -1188,8 +1187,8 @@ static int spi_qup_pm_suspend_runtime(struct device *device)
static int spi_qup_pm_resume_runtime(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
u32 config;
int ret;
@@ -1214,8 +1213,8 @@ static int spi_qup_pm_resume_runtime(struct device *device)
#ifdef CONFIG_PM_SLEEP
static int spi_qup_suspend(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
if (pm_runtime_suspended(device)) {
@@ -1223,7 +1222,7 @@ static int spi_qup_suspend(struct device *device)
if (ret)
return ret;
}
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1238,8 +1237,8 @@ static int spi_qup_suspend(struct device *device)
static int spi_qup_resume(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(controller->iclk);
@@ -1256,7 +1255,7 @@ static int spi_qup_resume(struct device *device)
if (ret)
goto disable_clk;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
goto disable_clk;
@@ -1271,8 +1270,8 @@ disable_clk:
static void spi_qup_remove(struct platform_device *pdev)
{
- struct spi_master *master = dev_get_drvdata(&pdev->dev);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(&pdev->dev);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
@@ -1290,7 +1289,7 @@ static void spi_qup_remove(struct platform_device *pdev)
ERR_PTR(ret));
}
- spi_qup_release_dma(master);
+ spi_qup_release_dma(host);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
index 5073736d3d1f..225f75550780 100644
--- a/drivers/spi/spi-rb4xx.c
+++ b/drivers/spi/spi-rb4xx.c
@@ -80,7 +80,7 @@ static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
static void rb4xx_set_cs(struct spi_device *spi, bool enable)
{
- struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
+ struct rb4xx_spi *rbspi = spi_controller_get_devdata(spi->controller);
/*
* Setting CS is done along with bitbanging the actual values,
@@ -92,10 +92,10 @@ static void rb4xx_set_cs(struct spi_device *spi, bool enable)
AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1);
}
-static int rb4xx_transfer_one(struct spi_master *master,
+static int rb4xx_transfer_one(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *t)
{
- struct rb4xx_spi *rbspi = spi_master_get_devdata(master);
+ struct rb4xx_spi *rbspi = spi_controller_get_devdata(host);
int i;
u32 spi_ioc;
u8 *rx_buf;
@@ -126,14 +126,14 @@ static int rb4xx_transfer_one(struct spi_master *master,
continue;
rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return 0;
}
static int rb4xx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *ahb_clk;
struct rb4xx_spi *rbspi;
int err;
@@ -143,31 +143,31 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(spi_base))
return PTR_ERR(spi_base);
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*rbspi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*rbspi));
+ if (!host)
return -ENOMEM;
ahb_clk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(ahb_clk))
return PTR_ERR(ahb_clk);
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = 0;
- master->num_chipselect = 3;
- master->mode_bits = SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_MASTER_MUST_TX;
- master->transfer_one = rb4xx_transfer_one;
- master->set_cs = rb4xx_set_cs;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = 0;
+ host->num_chipselect = 3;
+ host->mode_bits = SPI_TX_DUAL;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_MUST_TX;
+ host->transfer_one = rb4xx_transfer_one;
+ host->set_cs = rb4xx_set_cs;
- rbspi = spi_master_get_devdata(master);
+ rbspi = spi_controller_get_devdata(host);
rbspi->base = spi_base;
rbspi->clk = ahb_clk;
platform_set_drvdata(pdev, rbspi);
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err) {
- dev_err(&pdev->dev, "failed to register SPI master\n");
+ dev_err(&pdev->dev, "failed to register SPI host\n");
return err;
}
diff --git a/drivers/spi/spi-realtek-rtl.c b/drivers/spi/spi-realtek-rtl.c
index 866b0477dbd7..0b0123e20b54 100644
--- a/drivers/spi/spi-realtek-rtl.c
+++ b/drivers/spi/spi-realtek-rtl.c
@@ -153,7 +153,7 @@ static int realtek_rtl_spi_probe(struct platform_device *pdev)
struct rtspi *rtspi;
int err;
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*rtspi));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*rtspi));
if (!ctrl) {
dev_err(&pdev->dev, "Error allocating SPI controller\n");
return -ENOMEM;
diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c
index 583f4187f030..0d7fadcd4ed3 100644
--- a/drivers/spi/spi-rockchip-sfc.c
+++ b/drivers/spi/spi-rockchip-sfc.c
@@ -487,7 +487,7 @@ static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us)
static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
+ struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller);
u32 len = op->data.nbytes;
int ret;
@@ -523,7 +523,7 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op
static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
+ struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller);
op->data.nbytes = min(op->data.nbytes, sfc->max_iosize);
@@ -557,22 +557,22 @@ static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
static int rockchip_sfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct rockchip_sfc *sfc;
int ret;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*sfc));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*sfc));
+ if (!host)
return -ENOMEM;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->mem_ops = &rockchip_sfc_mem_ops;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL;
- master->max_speed_hz = SFC_MAX_SPEED;
- master->num_chipselect = SFC_MAX_CHIPSELECT_NUM;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->mem_ops = &rockchip_sfc_mem_ops;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL;
+ host->max_speed_hz = SFC_MAX_SPEED;
+ host->num_chipselect = SFC_MAX_CHIPSELECT_NUM;
- sfc = spi_master_get_devdata(master);
+ sfc = spi_controller_get_devdata(host);
sfc->dev = dev;
sfc->regbase = devm_platform_ioremap_resource(pdev, 0);
@@ -640,7 +640,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);
sfc->version = rockchip_sfc_get_version(sfc);
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret)
goto err_irq;
@@ -656,10 +656,10 @@ err_hclk:
static void rockchip_sfc_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_controller *host = platform_get_drvdata(pdev);
struct rockchip_sfc *sfc = platform_get_drvdata(pdev);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
clk_disable_unprepare(sfc->clk);
clk_disable_unprepare(sfc->hclk);
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 143ede958ac1..5b010094dace 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -104,8 +104,8 @@
#define CR0_XFM_RO 0x2
#define CR0_OPM_OFFSET 20
-#define CR0_OPM_MASTER 0x0
-#define CR0_OPM_SLAVE 0x1
+#define CR0_OPM_HOST 0x0
+#define CR0_OPM_TARGET 0x1
#define CR0_SOI_OFFSET 23
@@ -125,7 +125,7 @@
#define SR_TF_EMPTY (1 << 2)
#define SR_RF_EMPTY (1 << 3)
#define SR_RF_FULL (1 << 4)
-#define SR_SLAVE_TX_BUSY (1 << 5)
+#define SR_TARGET_TX_BUSY (1 << 5)
/* Bit fields in ISR, IMR, ISR, RISR, 5bit */
#define INT_MASK 0x1f
@@ -151,7 +151,7 @@
#define RXDMA (1 << 0)
#define TXDMA (1 << 1)
-/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
+/* sclk_out: spi host internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000U
/*
@@ -194,8 +194,8 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
- bool slave_abort;
- bool cs_inactive; /* spi slave tansmition stop when cs inactive */
+ bool target_abort;
+ bool cs_inactive; /* spi target tansmition stop when cs inactive */
bool cs_high_supported; /* native CS supports active-high polarity */
struct spi_transfer *xfer; /* Store xfer temporarily */
@@ -206,13 +206,13 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}
-static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode)
+static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool target_mode)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
do {
- if (slave_mode) {
- if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) &&
+ if (target_mode) {
+ if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_TARGET_TX_BUSY) &&
!((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
return;
} else {
@@ -351,9 +351,9 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
struct spi_controller *ctlr = dev_id;
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
- /* When int_cs_inactive comes, spi slave abort */
+ /* When int_cs_inactive comes, spi target abort */
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) {
- ctlr->slave_abort(ctlr);
+ ctlr->target_abort(ctlr);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR);
@@ -405,7 +405,7 @@ static void rockchip_spi_dma_rxcb(void *data)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
int state = atomic_fetch_andnot(RXDMA, &rs->state);
- if (state & TXDMA && !rs->slave_abort)
+ if (state & TXDMA && !rs->target_abort)
return;
if (rs->cs_inactive)
@@ -421,11 +421,11 @@ static void rockchip_spi_dma_txcb(void *data)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
int state = atomic_fetch_andnot(TXDMA, &rs->state);
- if (state & RXDMA && !rs->slave_abort)
+ if (state & RXDMA && !rs->target_abort)
return;
/* Wait until the FIFO data completely. */
- wait_for_tx_idle(rs, ctlr->slave);
+ wait_for_tx_idle(rs, ctlr->target);
spi_enable_chip(rs, false);
spi_finalize_current_transfer(ctlr);
@@ -525,7 +525,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
static int rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
- bool use_dma, bool slave_mode)
+ bool use_dma, bool target_mode)
{
u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
@@ -534,9 +534,9 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
u32 cr1;
u32 dmacr = 0;
- if (slave_mode)
- cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET;
- rs->slave_abort = false;
+ if (target_mode)
+ cr0 |= CR0_OPM_TARGET << CR0_OPM_OFFSET;
+ rs->target_abort = false;
cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
@@ -614,7 +614,7 @@ static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
return ROCKCHIP_SPI_MAX_TRANLEN;
}
-static int rockchip_spi_slave_abort(struct spi_controller *ctlr)
+static int rockchip_spi_target_abort(struct spi_controller *ctlr)
{
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
u32 rx_fifo_left;
@@ -659,7 +659,7 @@ out:
dmaengine_terminate_sync(ctlr->dma_tx);
atomic_set(&rs->state, 0);
spi_enable_chip(rs, false);
- rs->slave_abort = true;
+ rs->target_abort = true;
spi_finalize_current_transfer(ctlr);
return 0;
@@ -697,7 +697,7 @@ static int rockchip_spi_transfer_one(
rs->xfer = xfer;
use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false;
- ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave);
+ ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->target);
if (ret)
return ret;
@@ -757,15 +757,15 @@ static int rockchip_spi_probe(struct platform_device *pdev)
struct resource *mem;
struct device_node *np = pdev->dev.of_node;
u32 rsd_nsecs, num_cs;
- bool slave_mode;
+ bool target_mode;
- slave_mode = of_property_read_bool(np, "spi-slave");
+ target_mode = of_property_read_bool(np, "spi-slave");
- if (slave_mode)
- ctlr = spi_alloc_slave(&pdev->dev,
+ if (target_mode)
+ ctlr = spi_alloc_target(&pdev->dev,
sizeof(struct rockchip_spi));
else
- ctlr = spi_alloc_master(&pdev->dev,
+ ctlr = spi_alloc_host(&pdev->dev,
sizeof(struct rockchip_spi));
if (!ctlr)
@@ -854,11 +854,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ctlr->auto_runtime_pm = true;
ctlr->bus_num = pdev->id;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
- if (slave_mode) {
+ if (target_mode) {
ctlr->mode_bits |= SPI_NO_CS;
- ctlr->slave_abort = rockchip_spi_slave_abort;
+ ctlr->target_abort = rockchip_spi_target_abort;
} else {
- ctlr->flags = SPI_MASTER_GPIO_SS;
+ ctlr->flags = SPI_CONTROLLER_GPIO_SS;
ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM;
/*
* rk spi0 has two native cs, spi1..5 one cs only
@@ -911,7 +911,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
case ROCKCHIP_SPI_VER2_TYPE2:
rs->cs_high_supported = true;
ctlr->mode_bits |= SPI_CS_HIGH;
- if (ctlr->can_dma && slave_mode)
+ if (ctlr->can_dma && target_mode)
rs->cs_inactive = true;
else
rs->cs_inactive = false;
diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
index 2f78124a1b59..e11146932828 100644
--- a/drivers/spi/spi-rpc-if.c
+++ b/drivers/spi/spi-rpc-if.c
@@ -134,7 +134,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
struct rpcif *rpc;
int error;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*rpc));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*rpc));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 08ceebbaf69b..8e81f1a8623f 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -19,7 +19,7 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/sh_dma.h>
@@ -1294,7 +1294,7 @@ static int rspi_probe(struct platform_device *pdev)
const struct spi_ops *ops;
unsigned long clksrc;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rspi_data));
if (ctlr == NULL)
return -ENOMEM;
@@ -1317,8 +1317,7 @@ static int rspi_probe(struct platform_device *pdev)
rspi->ops = ops;
rspi->ctlr = ctlr;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rspi->addr = devm_ioremap_resource(&pdev->dev, res);
+ rspi->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(rspi->addr)) {
ret = PTR_ERR(rspi->addr);
goto error1;
diff --git a/drivers/spi/spi-rzv2m-csi.c b/drivers/spi/spi-rzv2m-csi.c
index 14ad65da930d..d0f51b17aa7c 100644
--- a/drivers/spi/spi-rzv2m-csi.c
+++ b/drivers/spi/spi-rzv2m-csi.c
@@ -5,13 +5,17 @@
* Copyright (C) 2023 Renesas Electronics Corporation
*/
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/count_zeros.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
+#include <linux/log2.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
/* Registers */
#define CSI_MODE 0x00 /* CSI mode control */
@@ -36,6 +40,7 @@
/* CSI_CLKSEL */
#define CSI_CLKSEL_CKP BIT(17)
#define CSI_CLKSEL_DAP BIT(16)
+#define CSI_CLKSEL_MODE (CSI_CLKSEL_CKP|CSI_CLKSEL_DAP)
#define CSI_CLKSEL_SLAVE BIT(15)
#define CSI_CLKSEL_CKS GENMASK(14, 1)
@@ -60,17 +65,22 @@
/* CSI_FIFOTRG */
#define CSI_FIFOTRG_R_TRG GENMASK(2, 0)
-#define CSI_FIFO_SIZE_BYTES 32
-#define CSI_FIFO_HALF_SIZE 16
+#define CSI_FIFO_SIZE_BYTES 32U
+#define CSI_FIFO_HALF_SIZE 16U
#define CSI_EN_DIS_TIMEOUT_US 100
-#define CSI_CKS_MAX 0x3FFF
+/*
+ * Clock "csiclk" gets divided by 2 * CSI_CLKSEL_CKS in order to generate the
+ * serial clock (output from master), with CSI_CLKSEL_CKS ranging from 0x1 (that
+ * means "csiclk" is divided by 2) to 0x3FFF ("csiclk" is divided by 32766).
+ */
+#define CSI_CKS_MAX GENMASK(13, 0)
#define UNDERRUN_ERROR BIT(0)
#define OVERFLOW_ERROR BIT(1)
#define TX_TIMEOUT_ERROR BIT(2)
#define RX_TIMEOUT_ERROR BIT(3)
-#define CSI_MAX_SPI_SCKO 8000000
+#define CSI_MAX_SPI_SCKO (8 * HZ_PER_MHZ)
struct rzv2m_csi_priv {
void __iomem *base;
@@ -78,33 +88,19 @@ struct rzv2m_csi_priv {
struct clk *pclk;
struct device *dev;
struct spi_controller *controller;
- const u8 *txbuf;
- u8 *rxbuf;
- int buffer_len;
- int bytes_sent;
- int bytes_received;
- int bytes_to_transfer;
- int words_to_transfer;
- unsigned char bytes_per_word;
+ const void *txbuf;
+ void *rxbuf;
+ unsigned int buffer_len;
+ unsigned int bytes_sent;
+ unsigned int bytes_received;
+ unsigned int bytes_to_transfer;
+ unsigned int words_to_transfer;
+ unsigned int bytes_per_word;
wait_queue_head_t wait;
- u8 errors;
+ u32 errors;
u32 status;
};
-static const unsigned char x_trg[] = {
- 0, 1, 1, 2, 2, 2, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5
-};
-
-static const unsigned char x_trg_words[] = {
- 1, 2, 2, 4, 4, 4, 4, 8,
- 8, 8, 8, 8, 8, 8, 8, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 32
-};
-
static void rzv2m_csi_reg_write_bit(const struct rzv2m_csi_priv *csi,
int reg_offs, int bit_mask, u32 value)
{
@@ -124,13 +120,12 @@ static int rzv2m_csi_sw_reset(struct rzv2m_csi_priv *csi, int assert)
rzv2m_csi_reg_write_bit(csi, CSI_CNT, CSI_CNT_CSIRST, assert);
- if (assert) {
- return readl_poll_timeout(csi->base + CSI_MODE, reg,
- !(reg & CSI_MODE_CSOT), 0,
- CSI_EN_DIS_TIMEOUT_US);
- }
+ if (!assert)
+ return 0;
- return 0;
+ return readl_poll_timeout(csi->base + CSI_MODE, reg,
+ !(reg & CSI_MODE_CSOT), 0,
+ CSI_EN_DIS_TIMEOUT_US);
}
static int rzv2m_csi_start_stop_operation(const struct rzv2m_csi_priv *csi,
@@ -140,28 +135,28 @@ static int rzv2m_csi_start_stop_operation(const struct rzv2m_csi_priv *csi,
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_CSIE, enable);
- if (!enable && wait)
- return readl_poll_timeout(csi->base + CSI_MODE, reg,
- !(reg & CSI_MODE_CSOT), 0,
- CSI_EN_DIS_TIMEOUT_US);
+ if (enable || !wait)
+ return 0;
- return 0;
+ return readl_poll_timeout(csi->base + CSI_MODE, reg,
+ !(reg & CSI_MODE_CSOT), 0,
+ CSI_EN_DIS_TIMEOUT_US);
}
static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
{
- int i;
+ unsigned int i;
if (readl(csi->base + CSI_OFIFOL))
return -EIO;
if (csi->bytes_per_word == 2) {
- u16 *buf = (u16 *)csi->txbuf;
+ const u16 *buf = csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
} else {
- u8 *buf = (u8 *)csi->txbuf;
+ const u8 *buf = csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
@@ -175,18 +170,18 @@ static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
{
- int i;
+ unsigned int i;
if (readl(csi->base + CSI_IFIFOL) != csi->bytes_to_transfer)
return -EIO;
if (csi->bytes_per_word == 2) {
- u16 *buf = (u16 *)csi->rxbuf;
+ u16 *buf = csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u16)readl(csi->base + CSI_IFIFO);
} else {
- u8 *buf = (u8 *)csi->rxbuf;
+ u8 *buf = csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u8)readl(csi->base + CSI_IFIFO);
@@ -200,9 +195,9 @@ static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
{
- int bytes_transferred = max_t(int, csi->bytes_received, csi->bytes_sent);
- int bytes_remaining = csi->buffer_len - bytes_transferred;
- int to_transfer;
+ unsigned int bytes_transferred = max(csi->bytes_received, csi->bytes_sent);
+ unsigned int bytes_remaining = csi->buffer_len - bytes_transferred;
+ unsigned int to_transfer;
if (csi->txbuf)
/*
@@ -210,9 +205,9 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
* hard to raise an overflow error (which is only possible
* when IP transmits and receives at the same time).
*/
- to_transfer = min_t(int, CSI_FIFO_HALF_SIZE, bytes_remaining);
+ to_transfer = min(CSI_FIFO_HALF_SIZE, bytes_remaining);
else
- to_transfer = min_t(int, CSI_FIFO_SIZE_BYTES, bytes_remaining);
+ to_transfer = min(CSI_FIFO_SIZE_BYTES, bytes_remaining);
if (csi->bytes_per_word == 2)
to_transfer >>= 1;
@@ -223,7 +218,7 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
* less than or equal to the number of bytes we need to transfer.
* This may result in multiple smaller transfers.
*/
- csi->words_to_transfer = x_trg_words[to_transfer - 1];
+ csi->words_to_transfer = rounddown_pow_of_two(to_transfer);
if (csi->bytes_per_word == 2)
csi->bytes_to_transfer = csi->words_to_transfer << 1;
@@ -234,7 +229,7 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
static inline void rzv2m_csi_set_rx_fifo_trigger_level(struct rzv2m_csi_priv *csi)
{
rzv2m_csi_reg_write_bit(csi, CSI_FIFOTRG, CSI_FIFOTRG_R_TRG,
- x_trg[csi->words_to_transfer - 1]);
+ ilog2(csi->words_to_transfer));
}
static inline void rzv2m_csi_enable_rx_trigger(struct rzv2m_csi_priv *csi,
@@ -307,7 +302,6 @@ static int rzv2m_csi_wait_for_tx_empty(struct rzv2m_csi_priv *csi)
return 0;
ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_TREND, CSI_CNT_TREND_E);
-
if (ret == -ETIMEDOUT)
csi->errors |= TX_TIMEOUT_ERROR;
@@ -323,7 +317,6 @@ static inline int rzv2m_csi_wait_for_rx_ready(struct rzv2m_csi_priv *csi)
ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_R_TRGR,
CSI_CNT_R_TRGR_E);
-
if (ret == -ETIMEDOUT)
csi->errors |= RX_TIMEOUT_ERROR;
@@ -332,7 +325,7 @@ static inline int rzv2m_csi_wait_for_rx_ready(struct rzv2m_csi_priv *csi)
static irqreturn_t rzv2m_csi_irq_handler(int irq, void *data)
{
- struct rzv2m_csi_priv *csi = (struct rzv2m_csi_priv *)data;
+ struct rzv2m_csi_priv *csi = data;
csi->status = readl(csi->base + CSI_INT);
rzv2m_csi_disable_irqs(csi, csi->status);
@@ -402,10 +395,8 @@ static int rzv2m_csi_setup(struct spi_device *spi)
writel(CSI_MODE_SETUP, csi->base + CSI_MODE);
/* Setup clock polarity and phase timing */
- rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_CKP,
- !(spi->mode & SPI_CPOL));
- rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_DAP,
- !(spi->mode & SPI_CPHA));
+ rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_MODE,
+ ~spi->mode & SPI_MODE_X_MASK);
/* Setup serial data order */
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_DIR,
@@ -433,8 +424,8 @@ static int rzv2m_csi_setup(struct spi_device *spi)
static int rzv2m_csi_pio_transfer(struct rzv2m_csi_priv *csi)
{
- bool tx_completed = csi->txbuf ? false : true;
- bool rx_completed = csi->rxbuf ? false : true;
+ bool tx_completed = !csi->txbuf;
+ bool rx_completed = !csi->rxbuf;
int ret = 0;
/* Make sure the TX FIFO is empty */
@@ -564,7 +555,7 @@ static int rzv2m_csi_probe(struct platform_device *pdev)
int irq;
int ret;
- controller = devm_spi_alloc_master(dev, sizeof(*csi));
+ controller = devm_spi_alloc_host(dev, sizeof(*csi));
if (!controller)
return -ENOMEM;
@@ -599,12 +590,13 @@ static int rzv2m_csi_probe(struct platform_device *pdev)
init_waitqueue_head(&csi->wait);
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- controller->dev.of_node = pdev->dev.of_node;
controller->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
controller->setup = rzv2m_csi_setup;
controller->transfer_one = rzv2m_csi_transfer_one;
controller->use_gpio_descriptors = true;
+ device_set_node(&controller->dev, dev_fwnode(dev));
+
ret = devm_request_irq(dev, irq, rzv2m_csi_irq_handler, 0,
dev_name(dev), csi);
if (ret)
@@ -635,15 +627,13 @@ static int rzv2m_csi_probe(struct platform_device *pdev)
return 0;
}
-static int rzv2m_csi_remove(struct platform_device *pdev)
+static void rzv2m_csi_remove(struct platform_device *pdev)
{
struct rzv2m_csi_priv *csi = platform_get_drvdata(pdev);
spi_unregister_controller(csi->controller);
rzv2m_csi_sw_reset(csi, 1);
clk_disable_unprepare(csi->csiclk);
-
- return 0;
}
static const struct of_device_id rzv2m_csi_match[] = {
@@ -654,7 +644,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_csi_match);
static struct platform_driver rzv2m_csi_drv = {
.probe = rzv2m_csi_probe,
- .remove = rzv2m_csi_remove,
+ .remove_new = rzv2m_csi_remove,
.driver = {
.name = "rzv2m_csi",
.of_match_table = rzv2m_csi_match,
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index b6c2659a66ca..0e48ffd499b9 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -14,7 +14,6 @@
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_data/spi-s3c64xx.h>
@@ -164,9 +163,9 @@ struct s3c64xx_spi_port_config {
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
* @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals.
- * @ioclk: Pointer to the i/o clock between master and slave
+ * @ioclk: Pointer to the i/o clock between host and target
* @pdev: Pointer to device's platform device data
- * @master: Pointer to the SPI Protocol master.
+ * @host: Pointer to the SPI Protocol host.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @lock: Controller specific lock.
* @state: Set of FLAGS to indicate status.
@@ -187,7 +186,7 @@ struct s3c64xx_spi_driver_data {
struct clk *src_clk;
struct clk *ioclk;
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct s3c64xx_spi_info *cntrlr_info;
spinlock_t lock;
unsigned long sfr_start;
@@ -330,7 +329,7 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
{
struct s3c64xx_spi_driver_data *sdd =
- spi_master_get_devdata(spi->master);
+ spi_controller_get_devdata(spi->controller);
if (sdd->cntrlr_info->no_cs)
return;
@@ -352,9 +351,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
}
}
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
+static int s3c64xx_spi_prepare_transfer(struct spi_controller *spi)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi);
if (is_polling(sdd))
return 0;
@@ -382,9 +381,9 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
return 0;
}
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
+static int s3c64xx_spi_unprepare_transfer(struct spi_controller *spi)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi);
if (is_polling(sdd))
return 0;
@@ -400,11 +399,11 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
-static bool s3c64xx_spi_can_dma(struct spi_master *master,
+static bool s3c64xx_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
@@ -713,10 +712,10 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
-static int s3c64xx_spi_prepare_message(struct spi_master *master,
+static int s3c64xx_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
@@ -737,11 +736,11 @@ static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi)
return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX;
}
-static int s3c64xx_spi_transfer_one(struct spi_master *master,
+static int s3c64xx_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1;
const void *tx_buf = NULL;
void *rx_buf = NULL;
@@ -891,15 +890,15 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
-static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
+static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata(
struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs;
- struct device_node *slave_np, *data_np = NULL;
+ struct device_node *target_np, *data_np = NULL;
u32 fb_delay = 0;
- slave_np = spi->dev.of_node;
- if (!slave_np) {
+ target_np = spi->dev.of_node;
+ if (!target_np) {
dev_err(&spi->dev, "device node not found\n");
return ERR_PTR(-EINVAL);
}
@@ -908,7 +907,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
if (!cs)
return ERR_PTR(-ENOMEM);
- data_np = of_get_child_by_name(slave_np, "controller-data");
+ data_np = of_get_child_by_name(target_np, "controller-data");
if (!data_np) {
dev_info(&spi->dev, "feedback delay set to default (0)\n");
return cs;
@@ -933,9 +932,9 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
int err;
int div;
- sdd = spi_master_get_devdata(spi->master);
+ sdd = spi_controller_get_devdata(spi->controller);
if (spi->dev.of_node) {
- cs = s3c64xx_get_slave_ctrldata(spi);
+ cs = s3c64xx_get_target_ctrldata(spi);
spi->controller_data = cs;
}
@@ -1023,7 +1022,7 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
{
struct s3c64xx_spi_driver_data *sdd = data;
- struct spi_master *spi = sdd->master;
+ struct spi_controller *spi = sdd->host;
unsigned int val, clr = 0;
val = readl(sdd->regs + S3C64XX_SPI_STATUS);
@@ -1152,7 +1151,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
struct resource *mem_res;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
- struct spi_master *master;
+ struct spi_controller *host;
int ret, irq;
char clk_name[16];
@@ -1166,28 +1165,22 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, -ENODEV,
"Platform_data missing!\n");
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res)
- return dev_err_probe(&pdev->dev, -ENXIO,
- "Unable to get SPI MEM resource\n");
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return dev_err_probe(&pdev->dev, irq, "Failed to get IRQ\n");
+ return irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*sdd));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*sdd));
+ if (!host)
return dev_err_probe(&pdev->dev, -ENOMEM,
- "Unable to allocate SPI Master\n");
+ "Unable to allocate SPI Host\n");
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- sdd = spi_master_get_devdata(master);
+ sdd = spi_controller_get_devdata(host);
sdd->port_conf = s3c64xx_spi_get_port_config(pdev);
- sdd->master = master;
+ sdd->host = host;
sdd->cntrlr_info = sci;
sdd->pdev = pdev;
- sdd->sfr_start = mem_res->start;
if (pdev->dev.of_node) {
ret = of_alias_get_id(pdev->dev.of_node, "spi");
if (ret < 0)
@@ -1203,31 +1196,32 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
sdd->tx_dma.direction = DMA_MEM_TO_DEV;
sdd->rx_dma.direction = DMA_DEV_TO_MEM;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = sdd->port_id;
- master->setup = s3c64xx_spi_setup;
- master->cleanup = s3c64xx_spi_cleanup;
- master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
- master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
- master->prepare_message = s3c64xx_spi_prepare_message;
- master->transfer_one = s3c64xx_spi_transfer_one;
- master->max_transfer_size = s3c64xx_spi_max_transfer_size;
- master->num_chipselect = sci->num_cs;
- master->use_gpio_descriptors = true;
- master->dma_alignment = 8;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
- SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = sdd->port_id;
+ host->setup = s3c64xx_spi_setup;
+ host->cleanup = s3c64xx_spi_cleanup;
+ host->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
+ host->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
+ host->prepare_message = s3c64xx_spi_prepare_message;
+ host->transfer_one = s3c64xx_spi_transfer_one;
+ host->max_transfer_size = s3c64xx_spi_max_transfer_size;
+ host->num_chipselect = sci->num_cs;
+ host->use_gpio_descriptors = true;
+ host->dma_alignment = 8;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
if (sdd->port_conf->has_loopback)
- master->mode_bits |= SPI_LOOP;
- master->auto_runtime_pm = true;
+ host->mode_bits |= SPI_LOOP;
+ host->auto_runtime_pm = true;
if (!is_polling(sdd))
- master->can_dma = s3c64xx_spi_can_dma;
+ host->can_dma = s3c64xx_spi_can_dma;
- sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ sdd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
if (IS_ERR(sdd->regs))
return PTR_ERR(sdd->regs);
+ sdd->sfr_start = mem_res->start;
if (sci->cfg_gpio && sci->cfg_gpio())
return dev_err_probe(&pdev->dev, -EBUSY,
@@ -1277,14 +1271,14 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
sdd->regs + S3C64XX_SPI_INT_EN);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret != 0) {
- dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
+ dev_err(&pdev->dev, "cannot register SPI host: %d\n", ret);
goto err_pm_put;
}
- dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
- sdd->port_id, master->num_chipselect);
+ dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Targets attached\n",
+ sdd->port_id, host->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n",
mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1);
@@ -1303,8 +1297,8 @@ err_pm_put:
static void s3c64xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
pm_runtime_get_sync(&pdev->dev);
@@ -1323,10 +1317,10 @@ static void s3c64xx_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int s3c64xx_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
- int ret = spi_master_suspend(master);
+ int ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1341,8 +1335,8 @@ static int s3c64xx_spi_suspend(struct device *dev)
static int s3c64xx_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
int ret;
@@ -1353,15 +1347,15 @@ static int s3c64xx_spi_resume(struct device *dev)
if (ret < 0)
return ret;
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int s3c64xx_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
clk_disable_unprepare(sdd->clk);
clk_disable_unprepare(sdd->src_clk);
@@ -1372,8 +1366,8 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
static int s3c64xx_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
int ret;
if (sdd->port_conf->clk_ioclk) {
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index d52ed67243f7..eecf9ea95ae3 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -12,7 +12,6 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/sc18is602.h>
#include <linux/gpio/consumer.h>
@@ -31,7 +30,7 @@ enum chips { sc18is602, sc18is602b, sc18is603 };
#define SC18IS602_MODE_CLOCK_DIV_128 0x3
struct sc18is602 {
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
u8 ctrl;
u32 freq;
@@ -180,10 +179,10 @@ static int sc18is602_check_transfer(struct spi_device *spi,
return 0;
}
-static int sc18is602_transfer_one(struct spi_master *master,
+static int sc18is602_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct sc18is602 *hw = spi_master_get_devdata(master);
+ struct sc18is602 *hw = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
struct spi_transfer *t;
int status = 0;
@@ -214,7 +213,7 @@ static int sc18is602_transfer_one(struct spi_master *master,
spi_transfer_delay_exec(t);
}
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
@@ -226,7 +225,7 @@ static size_t sc18is602_max_transfer_size(struct spi_device *spi)
static int sc18is602_setup(struct spi_device *spi)
{
- struct sc18is602 *hw = spi_master_get_devdata(spi->master);
+ struct sc18is602 *hw = spi_controller_get_devdata(spi->controller);
/* SC18IS602 does not support CS2 */
if (hw->id == sc18is602 && (spi_get_chipselect(spi, 0) == 2))
@@ -242,17 +241,17 @@ static int sc18is602_probe(struct i2c_client *client)
struct device_node *np = dev->of_node;
struct sc18is602_platform_data *pdata = dev_get_platdata(dev);
struct sc18is602 *hw;
- struct spi_master *master;
+ struct spi_controller *host;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EINVAL;
- master = devm_spi_alloc_master(dev, sizeof(struct sc18is602));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(struct sc18is602));
+ if (!host)
return -ENOMEM;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
i2c_set_clientdata(client, hw);
/* assert reset and then release */
@@ -261,24 +260,24 @@ static int sc18is602_probe(struct i2c_client *client)
return PTR_ERR(hw->reset);
gpiod_set_value_cansleep(hw->reset, 0);
- hw->master = master;
+ hw->host = host;
hw->client = client;
hw->dev = dev;
hw->ctrl = 0xff;
if (client->dev.of_node)
- hw->id = (enum chips)of_device_get_match_data(&client->dev);
+ hw->id = (uintptr_t)of_device_get_match_data(&client->dev);
else
hw->id = id->driver_data;
switch (hw->id) {
case sc18is602:
case sc18is602b:
- master->num_chipselect = 4;
+ host->num_chipselect = 4;
hw->freq = SC18IS602_CLOCK;
break;
case sc18is603:
- master->num_chipselect = 2;
+ host->num_chipselect = 2;
if (pdata) {
hw->freq = pdata->clock_frequency;
} else {
@@ -293,18 +292,18 @@ static int sc18is602_probe(struct i2c_client *client)
hw->freq = SC18IS602_CLOCK;
break;
}
- master->bus_num = np ? -1 : client->adapter->nr;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->setup = sc18is602_setup;
- master->transfer_one_message = sc18is602_transfer_one;
- master->max_transfer_size = sc18is602_max_transfer_size;
- master->max_message_size = sc18is602_max_transfer_size;
- master->dev.of_node = np;
- master->min_speed_hz = hw->freq / 128;
- master->max_speed_hz = hw->freq / 4;
-
- return devm_spi_register_master(dev, master);
+ host->bus_num = np ? -1 : client->adapter->nr;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->setup = sc18is602_setup;
+ host->transfer_one_message = sc18is602_transfer_one;
+ host->max_transfer_size = sc18is602_max_transfer_size;
+ host->max_message_size = sc18is602_max_transfer_size;
+ host->dev.of_node = np;
+ host->min_speed_hz = hw->freq / 128;
+ host->max_speed_hz = hw->freq / 4;
+
+ return devm_spi_register_controller(dev, host);
}
static const struct i2c_device_id sc18is602_id[] = {
@@ -343,6 +342,6 @@ static struct i2c_driver sc18is602_driver = {
module_i2c_driver(sc18is602_driver);
-MODULE_DESCRIPTION("SC18IS602/603 SPI Master Driver");
+MODULE_DESCRIPTION("SC18IS602/603 SPI Host Driver");
MODULE_AUTHOR("Guenter Roeck");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index d6ffeae66ed3..5d63aa1d28e2 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -82,7 +82,7 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
}
/*
- * spi master function
+ * spi host function
*/
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
@@ -224,7 +224,7 @@ static int hspi_probe(struct platform_device *pdev)
return -EINVAL;
}
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*hspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*hspi));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 9e90b4f8b357..fb452bc78372 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
@@ -55,7 +54,7 @@ struct sh_msiof_spi_priv {
dma_addr_t rx_dma_addr;
bool native_cs_inited;
bool native_cs_high;
- bool slave_aborted;
+ bool target_aborted;
};
#define MAX_SS 3 /* Maximum number of native chip selects */
@@ -362,7 +361,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
tmp |= !cs_high << SIMDR1_SYNCAC_SHIFT;
tmp |= lsb_first << SIMDR1_BITLSB_SHIFT;
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
- if (spi_controller_is_slave(p->ctlr)) {
+ if (spi_controller_is_target(p->ctlr)) {
sh_msiof_write(p, SITMDR1, tmp | SITMDR1_PCON);
} else {
sh_msiof_write(p, SITMDR1,
@@ -554,7 +553,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
spi_controller_get_devdata(spi->controller);
u32 clr, set, tmp;
- if (spi_get_csgpiod(spi, 0) || spi_controller_is_slave(p->ctlr))
+ if (spi_get_csgpiod(spi, 0) || spi_controller_is_target(p->ctlr))
return 0;
if (p->native_cs_inited &&
@@ -603,11 +602,11 @@ static int sh_msiof_prepare_message(struct spi_controller *ctlr,
static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
{
- bool slave = spi_controller_is_slave(p->ctlr);
+ bool target = spi_controller_is_target(p->ctlr);
int ret = 0;
/* setup clock and rx/tx signals */
- if (!slave)
+ if (!target)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TSCKE);
if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_RXE);
@@ -615,7 +614,7 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TXE);
/* start by setting frame bit */
- if (!ret && !slave)
+ if (!ret && !target)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TFSE);
return ret;
@@ -623,27 +622,27 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf)
{
- bool slave = spi_controller_is_slave(p->ctlr);
+ bool target = spi_controller_is_target(p->ctlr);
int ret = 0;
/* shut down frame, rx/tx and clock signals */
- if (!slave)
+ if (!target)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TFSE, 0);
if (!ret)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TXE, 0);
if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, SICTR_RXE, 0);
- if (!ret && !slave)
+ if (!ret && !target)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TSCKE, 0);
return ret;
}
-static int sh_msiof_slave_abort(struct spi_controller *ctlr)
+static int sh_msiof_target_abort(struct spi_controller *ctlr)
{
struct sh_msiof_spi_priv *p = spi_controller_get_devdata(ctlr);
- p->slave_aborted = true;
+ p->target_aborted = true;
complete(&p->done);
complete(&p->done_txdma);
return 0;
@@ -652,9 +651,9 @@ static int sh_msiof_slave_abort(struct spi_controller *ctlr)
static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p,
struct completion *x)
{
- if (spi_controller_is_slave(p->ctlr)) {
+ if (spi_controller_is_target(p->ctlr)) {
if (wait_for_completion_interruptible(x) ||
- p->slave_aborted) {
+ p->target_aborted) {
dev_dbg(&p->pdev->dev, "interrupted\n");
return -EINTR;
}
@@ -700,7 +699,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
tx_fifo(p, tx_buf, words, fifo_shift);
reinit_completion(&p->done);
- p->slave_aborted = false;
+ p->target_aborted = false;
ret = sh_msiof_spi_start(p, rx_buf);
if (ret) {
@@ -797,7 +796,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
reinit_completion(&p->done);
if (tx)
reinit_completion(&p->done_txdma);
- p->slave_aborted = false;
+ p->target_aborted = false;
/* Now start DMA */
if (rx)
@@ -926,7 +925,7 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,
sh_msiof_spi_reset_regs(p);
/* setup clocks (clock already enabled in chipselect()) */
- if (!spi_controller_is_slave(p->ctlr))
+ if (!spi_controller_is_target(p->ctlr))
sh_msiof_spi_set_clk_regs(p, t);
while (ctlr->dma_tx && len > 15) {
@@ -1102,11 +1101,11 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
if (!info)
return NULL;
- info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_SLAVE
- : MSIOF_SPI_MASTER;
+ info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_TARGET
+ : MSIOF_SPI_HOST;
/* Parse the MSIOF properties */
- if (info->mode == MSIOF_SPI_MASTER)
+ if (info->mode == MSIOF_SPI_HOST)
of_property_read_u32(np, "num-cs", &num_cs);
of_property_read_u32(np, "renesas,tx-fifo-size",
&info->tx_fifo_override);
@@ -1280,12 +1279,12 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
return -ENXIO;
}
- if (info->mode == MSIOF_SPI_SLAVE)
- ctlr = spi_alloc_slave(&pdev->dev,
- sizeof(struct sh_msiof_spi_priv));
+ if (info->mode == MSIOF_SPI_TARGET)
+ ctlr = spi_alloc_target(&pdev->dev,
+ sizeof(struct sh_msiof_spi_priv));
else
- ctlr = spi_alloc_master(&pdev->dev,
- sizeof(struct sh_msiof_spi_priv));
+ ctlr = spi_alloc_host(&pdev->dev,
+ sizeof(struct sh_msiof_spi_priv));
if (ctlr == NULL)
return -ENOMEM;
@@ -1348,7 +1347,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->setup = sh_msiof_spi_setup;
ctlr->prepare_message = sh_msiof_prepare_message;
- ctlr->slave_abort = sh_msiof_slave_abort;
+ ctlr->target_abort = sh_msiof_target_abort;
ctlr->bits_per_word_mask = chipdata->bits_per_word_mask;
ctlr->auto_runtime_pm = true;
ctlr->transfer_one = sh_msiof_transfer_one;
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 92ca3f2d61ba..148d615d2f38 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -56,17 +56,17 @@ static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
static inline void setsck(struct spi_device *dev, int on)
{
- setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+ setbits(spi_controller_get_devdata(dev->controller), PIN_SCK, on);
}
static inline void setmosi(struct spi_device *dev, int on)
{
- setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+ setbits(spi_controller_get_devdata(dev->controller), PIN_TXD, on);
}
static inline u32 getmiso(struct spi_device *dev)
{
- struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+ struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
}
@@ -105,7 +105,7 @@ static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
- struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+ struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, spi_get_chipselect(dev, 0), value);
@@ -114,18 +114,18 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
static int sh_sci_spi_probe(struct platform_device *dev)
{
struct resource *r;
- struct spi_master *master;
+ struct spi_controller *host;
struct sh_sci_spi *sp;
int ret;
- master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
- if (master == NULL) {
- dev_err(&dev->dev, "failed to allocate spi master\n");
+ host = spi_alloc_host(&dev->dev, sizeof(struct sh_sci_spi));
+ if (host == NULL) {
+ dev_err(&dev->dev, "failed to allocate spi host\n");
ret = -ENOMEM;
goto err0;
}
- sp = spi_master_get_devdata(master);
+ sp = spi_controller_get_devdata(host);
platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev);
@@ -136,7 +136,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
}
/* setup spi bitbang adaptor */
- sp->bitbang.master = master;
+ sp->bitbang.master = host;
sp->bitbang.master->bus_num = sp->info->bus_num;
sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
sp->bitbang.chipselect = sh_sci_spi_chipselect;
@@ -166,7 +166,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
setbits(sp, PIN_INIT, 0);
iounmap(sp->membase);
err1:
- spi_master_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.master);
err0:
return ret;
}
@@ -178,7 +178,7 @@ static void sh_sci_spi_remove(struct platform_device *dev)
spi_bitbang_stop(&sp->bitbang);
setbits(sp, PIN_INIT, 0);
iounmap(sp->membase);
- spi_master_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.master);
}
static struct platform_driver sh_sci_spi_drv = {
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index d358a2a9c3f5..4b873d9a7602 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -72,7 +72,7 @@
struct spi_sh_data {
void __iomem *addr;
int irq;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned long cr1;
wait_queue_head_t wait;
int width;
@@ -327,7 +327,7 @@ static int spi_sh_transfer_one_message(struct spi_controller *ctlr,
static int spi_sh_setup(struct spi_device *spi)
{
- struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
+ struct spi_sh_data *ss = spi_controller_get_devdata(spi->controller);
pr_debug("%s: enter\n", __func__);
@@ -346,7 +346,7 @@ static int spi_sh_setup(struct spi_device *spi)
static void spi_sh_cleanup(struct spi_device *spi)
{
- struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
+ struct spi_sh_data *ss = spi_controller_get_devdata(spi->controller);
pr_debug("%s: enter\n", __func__);
@@ -381,14 +381,14 @@ static void spi_sh_remove(struct platform_device *pdev)
{
struct spi_sh_data *ss = platform_get_drvdata(pdev);
- spi_unregister_master(ss->master);
+ spi_unregister_controller(ss->host);
free_irq(ss->irq, ss);
}
static int spi_sh_probe(struct platform_device *pdev)
{
struct resource *res;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_sh_data *ss;
int ret, irq;
@@ -403,13 +403,13 @@ static int spi_sh_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));
- if (master == NULL) {
- dev_err(&pdev->dev, "spi_alloc_master error.\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(struct spi_sh_data));
+ if (host == NULL) {
+ dev_err(&pdev->dev, "devm_spi_alloc_host error.\n");
return -ENOMEM;
}
- ss = spi_master_get_devdata(master);
+ ss = spi_controller_get_devdata(host);
platform_set_drvdata(pdev, ss);
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
@@ -424,7 +424,7 @@ static int spi_sh_probe(struct platform_device *pdev)
return -ENODEV;
}
ss->irq = irq;
- ss->master = master;
+ ss->host = host;
ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (ss->addr == NULL) {
dev_err(&pdev->dev, "ioremap error.\n");
@@ -438,15 +438,15 @@ static int spi_sh_probe(struct platform_device *pdev)
return ret;
}
- master->num_chipselect = 2;
- master->bus_num = pdev->id;
- master->setup = spi_sh_setup;
- master->transfer_one_message = spi_sh_transfer_one_message;
- master->cleanup = spi_sh_cleanup;
+ host->num_chipselect = 2;
+ host->bus_num = pdev->id;
+ host->setup = spi_sh_setup;
+ host->transfer_one_message = spi_sh_transfer_one_message;
+ host->cleanup = spi_sh_cleanup;
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret < 0) {
- printk(KERN_ERR "spi_register_master error.\n");
+ printk(KERN_ERR "spi_register_controller error.\n");
goto error3;
}
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index dae9e097c333..cfd17bbb2202 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -128,9 +128,9 @@ static void sifive_spi_init(struct sifive_spi *spi)
}
static int
-sifive_spi_prepare_message(struct spi_master *master, struct spi_message *msg)
+sifive_spi_prepare_message(struct spi_controller *host, struct spi_message *msg)
{
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
struct spi_device *device = msg->spi;
/* Update the chip select polarity */
@@ -152,7 +152,7 @@ sifive_spi_prepare_message(struct spi_master *master, struct spi_message *msg)
static void sifive_spi_set_cs(struct spi_device *device, bool is_high)
{
- struct sifive_spi *spi = spi_master_get_devdata(device->master);
+ struct sifive_spi *spi = spi_controller_get_devdata(device->controller);
/* Reverse polarity is handled by SCMR/CPOL. Not inverted CS. */
if (device->mode & SPI_CS_HIGH)
@@ -252,10 +252,10 @@ static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
}
static int
-sifive_spi_transfer_one(struct spi_master *master, struct spi_device *device,
+sifive_spi_transfer_one(struct spi_controller *host, struct spi_device *device,
struct spi_transfer *t)
{
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int poll = sifive_spi_prep_transfer(spi, device, t);
const u8 *tx_ptr = t->tx_buf;
u8 *rx_ptr = t->rx_buf;
@@ -294,35 +294,35 @@ static int sifive_spi_probe(struct platform_device *pdev)
struct sifive_spi *spi;
int ret, irq, num_cs;
u32 cs_bits, max_bits_per_word;
- struct spi_master *master;
+ struct spi_controller *host;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sifive_spi));
- if (!master) {
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sifive_spi));
+ if (!host) {
dev_err(&pdev->dev, "out of memory\n");
return -ENOMEM;
}
- spi = spi_master_get_devdata(master);
+ spi = spi_controller_get_devdata(host);
init_completion(&spi->done);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
spi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->regs)) {
ret = PTR_ERR(spi->regs);
- goto put_master;
+ goto put_host;
}
spi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) {
dev_err(&pdev->dev, "Unable to find bus clock\n");
ret = PTR_ERR(spi->clk);
- goto put_master;
+ goto put_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto put_master;
+ goto put_host;
}
/* Optional parameters */
@@ -339,14 +339,14 @@ static int sifive_spi_probe(struct platform_device *pdev)
if (!ret && max_bits_per_word < 8) {
dev_err(&pdev->dev, "Only 8bit SPI words supported by the driver\n");
ret = -EINVAL;
- goto put_master;
+ goto put_host;
}
/* Spin up the bus clock before hitting registers */
ret = clk_prepare_enable(spi->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable bus clock\n");
- goto put_master;
+ goto put_host;
}
/* probe the number of CS lines */
@@ -362,30 +362,30 @@ static int sifive_spi_probe(struct platform_device *pdev)
num_cs = ilog2(cs_bits) + 1;
if (num_cs > SIFIVE_SPI_MAX_CS) {
- dev_err(&pdev->dev, "Invalid number of spi slaves\n");
+ dev_err(&pdev->dev, "Invalid number of spi targets\n");
ret = -EINVAL;
goto disable_clk;
}
- /* Define our master */
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
- master->mode_bits = SPI_CPHA | SPI_CPOL
+ /* Define our host */
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = num_cs;
+ host->mode_bits = SPI_CPHA | SPI_CPOL
| SPI_CS_HIGH | SPI_LSB_FIRST
| SPI_TX_DUAL | SPI_TX_QUAD
| SPI_RX_DUAL | SPI_RX_QUAD;
/* TODO: add driver support for bits_per_word < 8
* we need to "left-align" the bits (unless SPI_LSB_FIRST)
*/
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_CONTROLLER_MUST_TX | SPI_MASTER_GPIO_SS;
- master->prepare_message = sifive_spi_prepare_message;
- master->set_cs = sifive_spi_set_cs;
- master->transfer_one = sifive_spi_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_MUST_TX | SPI_CONTROLLER_GPIO_SS;
+ host->prepare_message = sifive_spi_prepare_message;
+ host->set_cs = sifive_spi_set_cs;
+ host->transfer_one = sifive_spi_transfer_one;
pdev->dev.dma_mask = NULL;
- /* Configure the SPI master hardware */
+ /* Configure the SPI host hardware */
sifive_spi_init(spi);
/* Register for SPI Interrupt */
@@ -397,11 +397,11 @@ static int sifive_spi_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
- irq, master->num_chipselect);
+ irq, host->num_chipselect);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "spi_register_master failed\n");
+ dev_err(&pdev->dev, "spi_register_host failed\n");
goto disable_clk;
}
@@ -409,16 +409,16 @@ static int sifive_spi_probe(struct platform_device *pdev)
disable_clk:
clk_disable_unprepare(spi->clk);
-put_master:
- spi_master_put(master);
+put_host:
+ spi_controller_put(host);
return ret;
}
static void sifive_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
/* Disable all the interrupts just in case */
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
@@ -427,11 +427,11 @@ static void sifive_spi_remove(struct platform_device *pdev)
static int sifive_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -445,14 +445,14 @@ static int sifive_spi_suspend(struct device *dev)
static int sifive_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(spi->clk);
if (ret)
return ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
clk_disable_unprepare(spi->clk);
diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c
index 4e4d426bfb43..6d6772974783 100644
--- a/drivers/spi/spi-slave-mt27xx.c
+++ b/drivers/spi/spi-slave-mt27xx.c
@@ -414,7 +414,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
mdata->dev_comp = of_id->data;
if (mdata->dev_comp->must_rx)
- ctlr->flags = SPI_MASTER_MUST_RX;
+ ctlr->flags = SPI_CONTROLLER_MUST_RX;
platform_set_drvdata(pdev, ctlr);
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index d64d3f75c726..a7c3b3923b4a 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -10,7 +10,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -501,7 +501,7 @@ out:
static int f_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->master);
+ struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
int err = 0;
switch (op->data.dir) {
@@ -606,7 +606,7 @@ static int f_ospi_probe(struct platform_device *pdev)
u32 num_cs = OSPI_NUM_CS;
int ret;
- ctlr = spi_alloc_master(dev, sizeof(*ospi));
+ ctlr = spi_alloc_host(dev, sizeof(*ospi));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c
index 22e39c4c12c4..bf01feedbf93 100644
--- a/drivers/spi/spi-sprd-adi.c
+++ b/drivers/spi/spi-sprd-adi.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/spi/spi.h>
@@ -580,7 +579,7 @@ static int sprd_adi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = num_chipselect;
- ctlr->flags = SPI_MASTER_HALF_DUPLEX;
+ ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
ctlr->bits_per_word_mask = 0;
ctlr->transfer_one = sprd_adi_transfer_one;
diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c
index 518c7eaca84e..95377cf748c0 100644
--- a/drivers/spi/spi-sprd.c
+++ b/drivers/spi/spi-sprd.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index 2b6804aa6901..def74ae9b5f6 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 6d10fa4ab783..b6d66caba4c0 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -238,6 +238,7 @@ struct stm32_spi;
* @baud_rate_div_min: minimum baud rate divisor
* @baud_rate_div_max: maximum baud rate divisor
* @has_fifo: boolean to know if fifo is used for driver
+ * @has_device_mode: is this compatible capable to switch on device mode
* @flags: compatible specific SPI controller flags used at registration time
*/
struct stm32_spi_cfg {
@@ -259,6 +260,7 @@ struct stm32_spi_cfg {
unsigned int baud_rate_div_min;
unsigned int baud_rate_div_max;
bool has_fifo;
+ bool has_device_mode;
u16 flags;
};
@@ -1001,9 +1003,9 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
if (spi->cfg->set_number_of_data) {
int ret;
- ret = spi_split_transfers_maxsize(ctrl, msg,
- STM32H7_SPI_TSIZE_MAX,
- GFP_KERNEL | GFP_DMA);
+ ret = spi_split_transfers_maxwords(ctrl, msg,
+ STM32H7_SPI_TSIZE_MAX,
+ GFP_KERNEL | GFP_DMA);
if (ret)
return ret;
}
@@ -1750,7 +1752,8 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
.baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
.baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
.has_fifo = false,
- .flags = SPI_MASTER_MUST_TX,
+ .has_device_mode = false,
+ .flags = SPI_CONTROLLER_MUST_TX,
};
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
@@ -1774,6 +1777,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
.has_fifo = true,
+ .has_device_mode = true,
};
static const struct of_device_id stm32_spi_of_match[] = {
@@ -1798,8 +1802,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
bool device_mode;
int ret;
+ const struct stm32_spi_cfg *cfg = of_device_get_match_data(&pdev->dev);
device_mode = of_property_read_bool(np, "spi-slave");
+ if (!cfg->has_device_mode && device_mode) {
+ dev_err(&pdev->dev, "spi-slave not supported\n");
+ return -EPERM;
+ }
if (device_mode)
ctrl = devm_spi_alloc_slave(&pdev->dev, sizeof(struct stm32_spi));
@@ -1817,9 +1826,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
spi->device_mode = device_mode;
spin_lock_init(&spi->lock);
- spi->cfg = (const struct stm32_spi_cfg *)
- of_match_device(pdev->dev.driver->of_match_table,
- &pdev->dev)->data;
+ spi->cfg = cfg;
spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(spi->base))
@@ -1829,8 +1836,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
spi->irq = platform_get_irq(pdev, 0);
if (spi->irq <= 0)
- return dev_err_probe(&pdev->dev, spi->irq,
- "failed to get irq\n");
+ return spi->irq;
ret = devm_request_threaded_irq(&pdev->dev, spi->irq,
spi->cfg->irq_handler_event,
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 30d541612253..3f5b1556ece0 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -83,6 +83,9 @@
#define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC_MASK GENMASK(23, 0)
+#define SUN6I_BURST_CTL_CNT_DRM BIT(28)
+#define SUN6I_BURST_CTL_CNT_QUAD_EN BIT(29)
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
@@ -90,6 +93,7 @@
struct sun6i_spi_cfg {
unsigned long fifo_depth;
bool has_clk_ctl;
+ u32 mode_bits;
};
struct sun6i_spi {
@@ -266,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
unsigned int div, div_cdr1, div_cdr2, timeout;
unsigned int start, end, tx_time;
unsigned int trig_level;
- unsigned int tx_len = 0, rx_len = 0;
+ unsigned int tx_len = 0, rx_len = 0, nbits = 0;
bool use_dma;
int ret = 0;
u32 reg;
@@ -418,13 +422,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
/* Setup the transfer now... */
- if (sspi->tx_buf)
+ if (sspi->tx_buf) {
tx_len = tfr->len;
+ nbits = tfr->tx_nbits;
+ } else if (tfr->rx_buf) {
+ nbits = tfr->rx_nbits;
+ }
+
+ switch (nbits) {
+ case SPI_NBITS_DUAL:
+ reg = SUN6I_BURST_CTL_CNT_DRM;
+ break;
+ case SPI_NBITS_QUAD:
+ reg = SUN6I_BURST_CTL_CNT_QUAD_EN;
+ break;
+ case SPI_NBITS_SINGLE:
+ default:
+ reg = FIELD_PREP(SUN6I_BURST_CTL_CNT_STC_MASK, tx_len);
+ }
/* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg);
sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
- sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
if (!use_dma) {
/* Fill the TX FIFO */
@@ -623,7 +643,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ sspi->cfg->mode_bits;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
@@ -740,6 +761,7 @@ static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
.fifo_depth = SUN8I_FIFO_DEPTH,
+ .mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD,
};
static const struct of_device_id sun6i_spi_match[] = {
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 488df681eaef..460f232dad50 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
@@ -723,27 +722,23 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
struct spi_delay *setup = &spi->cs_setup;
struct spi_delay *hold = &spi->cs_hold;
struct spi_delay *inactive = &spi->cs_inactive;
- u8 setup_dly, hold_dly, inactive_dly;
+ u8 setup_dly, hold_dly;
u32 setup_hold;
u32 spi_cs_timing;
u32 inactive_cycles;
u8 cs_state;
- if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
- (hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
- (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
+ if (setup->unit != SPI_DELAY_UNIT_SCK ||
+ hold->unit != SPI_DELAY_UNIT_SCK ||
+ inactive->unit != SPI_DELAY_UNIT_SCK) {
dev_err(&spi->dev,
"Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
SPI_DELAY_UNIT_SCK);
return -EINVAL;
}
- setup_dly = setup ? setup->value : 0;
- hold_dly = hold ? hold->value : 0;
- inactive_dly = inactive ? inactive->value : 0;
-
- setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
- hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
+ setup_dly = min_t(u8, setup->value, MAX_SETUP_HOLD_CYCLES);
+ hold_dly = min_t(u8, hold->value, MAX_SETUP_HOLD_CYCLES);
if (setup_dly && hold_dly) {
setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
@@ -755,7 +750,7 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
}
}
- inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+ inactive_cycles = min_t(u8, inactive->value, MAX_INACTIVE_CYCLES);
if (inactive_cycles)
inactive_cycles--;
cs_state = inactive_cycles ? 0 : 1;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 4286310628a2..0c5507473f97 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -455,7 +455,11 @@ static int tegra_sflash_probe(struct platform_device *pdev)
goto exit_free_master;
}
- tsd->irq = platform_get_irq(pdev, 0);
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto exit_free_master;
+ tsd->irq = ret;
+
ret = request_irq(tsd->irq, tegra_sflash_isr, 0,
dev_name(&pdev->dev), tsd);
if (ret < 0) {
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index c2915f7672cc..4d6db6182c5e 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -21,7 +21,6 @@
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
@@ -1034,18 +1033,12 @@ static int tegra_slink_probe(struct platform_device *pdev)
&master->max_speed_hz))
master->max_speed_hz = 25000000; /* 25MHz */
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "No IO memory resource\n");
- ret = -ENODEV;
- goto exit_free_master;
- }
- tspi->phys = r->start;
- tspi->base = devm_ioremap_resource(&pdev->dev, r);
+ tspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(tspi->base)) {
ret = PTR_ERR(tspi->base);
goto exit_free_master;
}
+ tspi->phys = r->start;
/* disabled clock may cause interrupt storm upon request */
tspi->clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index fbd14dd7be44..e9ad9b0b598b 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -18,7 +18,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 5914335ff63d..4c81516b67db 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -770,7 +769,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->setup = ti_qspi_setup;
master->auto_runtime_pm = true;
master->transfer_one_message = ti_qspi_start_transfer_one;
diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c
index f15312fdcdaf..852ffe013d32 100644
--- a/drivers/spi/spi-wpcm-fiu.c
+++ b/drivers/spi/spi-wpcm-fiu.c
@@ -3,9 +3,8 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi-mem.h>
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index ae6218bcd02a..a3d57554f5ba 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -218,7 +218,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c)
master->num_chipselect = 16;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->transfer_one_message = spi_xcomm_transfer_one;
master->dev.of_node = i2c->dev.of_node;
i2c_set_clientdata(i2c, master);
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
index 24dc845b940e..dbd85d7a1526 100644
--- a/drivers/spi/spi-xtensa-xtfpga.c
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -87,7 +87,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
if (!master)
return -ENOMEM;
- master->flags = SPI_MASTER_NO_RX;
+ master->flags = SPI_CONTROLLER_NO_RX;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->bus_num = pdev->dev.id;
master->dev.of_node = pdev->dev.of_node;
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index ee1995b91287..0db69a2a72ff 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -679,8 +679,8 @@ static int zynq_qspi_probe(struct platform_device *pdev)
}
xqspi->irq = platform_get_irq(pdev, 0);
- if (xqspi->irq <= 0) {
- ret = -ENXIO;
+ if (xqspi->irq < 0) {
+ ret = xqspi->irq;
goto clk_dis_all;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq,
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index fb2ca9b90eab..94d9a33d9af5 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -14,9 +14,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -1295,8 +1293,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
zynqmp_qspi_init_hw(xqspi);
xqspi->irq = platform_get_irq(pdev, 0);
- if (xqspi->irq <= 0) {
- ret = -ENXIO;
+ if (xqspi->irq < 0) {
+ ret = xqspi->irq;
goto clk_dis_all;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9291b2a0e887..8d6304cb061e 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -4,36 +4,36 @@
// Copyright (C) 2005 David Brownell
// Copyright (C) 2008 Secret Lab Technologies Ltd.
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/init.h>
+#include <linux/acpi.h>
#include <linux/cache.h>
-#include <linux/dma-mapping.h>
+#include <linux/clk/clk-conf.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/highmem.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
-#include <linux/clk/clk-conf.h>
-#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi-mem.h>
-#include <linux/gpio/consumer.h>
-#include <linux/pm_runtime.h>
+#include <linux/percpu.h>
+#include <linux/platform_data/x86/apple.h>
#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/property.h>
-#include <linux/export.h>
+#include <linux/ptp_clock_kernel.h>
#include <linux/sched/rt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
#include <uapi/linux/sched/types.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/platform_data/x86/apple.h>
-#include <linux/ptp_clock_kernel.h>
-#include <linux/percpu.h>
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
@@ -64,7 +64,7 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
if (len != -ENODEV)
return len;
- return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
+ return sysfs_emit(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
}
static DEVICE_ATTR_RO(modalias);
@@ -89,7 +89,7 @@ static ssize_t driver_override_show(struct device *dev,
ssize_t len;
device_lock(dev);
- len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
+ len = sysfs_emit(buf, "%s\n", spi->driver_override ? : "");
device_unlock(dev);
return len;
}
@@ -631,6 +631,16 @@ static int __spi_add_device(struct spi_device *spi)
struct device *dev = ctlr->dev.parent;
int status;
+ /* Chipselects are numbered 0..max; validate. */
+ if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
+ ctlr->num_chipselect);
+ return -EINVAL;
+ }
+
+ /* Set the bus ID string */
+ spi_dev_set_name(spi);
+
/*
* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
@@ -682,26 +692,15 @@ static int __spi_add_device(struct spi_device *spi)
* @spi: spi_device to register
*
* Companion function to spi_alloc_device. Devices allocated with
- * spi_alloc_device can be added onto the spi bus with this function.
+ * spi_alloc_device can be added onto the SPI bus with this function.
*
* Return: 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
- struct device *dev = ctlr->dev.parent;
int status;
- /* Chipselects are numbered 0..max; validate. */
- if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
- ctlr->num_chipselect);
- return -EINVAL;
- }
-
- /* Set the bus ID string */
- spi_dev_set_name(spi);
-
mutex_lock(&ctlr->add_lock);
status = __spi_add_device(spi);
mutex_unlock(&ctlr->add_lock);
@@ -709,25 +708,6 @@ int spi_add_device(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_add_device);
-static int spi_add_device_locked(struct spi_device *spi)
-{
- struct spi_controller *ctlr = spi->controller;
- struct device *dev = ctlr->dev.parent;
-
- /* Chipselects are numbered 0..max; validate. */
- if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
- ctlr->num_chipselect);
- return -EINVAL;
- }
-
- /* Set the bus ID string */
- spi_dev_set_name(spi);
-
- WARN_ON(!mutex_is_locked(&ctlr->add_lock));
- return __spi_add_device(spi);
-}
-
/**
* spi_new_device - instantiate one new SPI device
* @ctlr: Controller to which device is connected
@@ -889,7 +869,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
* spi_res_alloc - allocate a spi resource that is life-cycle managed
* during the processing of a spi_message while using
* spi_transfer_one
- * @spi: the spi device for which we allocate memory
+ * @spi: the SPI device for which we allocate memory
* @release: the release code to execute for this resource
* @size: size to alloc and return
* @gfp: GFP allocation flags
@@ -915,7 +895,7 @@ static void *spi_res_alloc(struct spi_device *spi, spi_res_release_t release,
}
/**
- * spi_res_free - free an spi resource
+ * spi_res_free - free an SPI resource
* @res: pointer to the custom data of a resource
*/
static void spi_res_free(void *res)
@@ -931,7 +911,7 @@ static void spi_res_free(void *res)
/**
* spi_res_add - add a spi_res to the spi_message
- * @message: the spi message
+ * @message: the SPI message
* @res: the spi_resource
*/
static void spi_res_add(struct spi_message *message, void *res)
@@ -943,7 +923,7 @@ static void spi_res_add(struct spi_message *message, void *res)
}
/**
- * spi_res_release - release all spi resources for this message
+ * spi_res_release - release all SPI resources for this message
* @ctlr: the @spi_controller
* @message: the @spi_message
*/
@@ -1006,7 +986,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), activate);
}
/* Some SPI masters need both GPIO CS & slave_select */
- if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
+ if ((spi->controller->flags & SPI_CONTROLLER_GPIO_SS) &&
spi->controller->set_cs)
spi->controller->set_cs(spi, !enable);
} else if (spi->controller->set_cs) {
@@ -1424,7 +1404,7 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
return -EINVAL;
/*
* If there is unknown effective speed, approximate it
- * by underestimating with half of the requested hz.
+ * by underestimating with half of the requested Hz.
*/
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
if (!hz)
@@ -1739,11 +1719,11 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
}
/**
- * __spi_pump_messages - function which processes spi message queue
+ * __spi_pump_messages - function which processes SPI message queue
* @ctlr: controller to process queue for
* @in_kthread: true if we are in the context of the message pump thread
*
- * This function checks if there is any spi message in the queue that
+ * This function checks if there is any SPI message in the queue that
* needs processing and if so call out to the driver to initialize hardware
* and transfer each message.
*
@@ -1758,7 +1738,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
unsigned long flags;
int ret;
- /* Take the IO mutex */
+ /* Take the I/O mutex */
mutex_lock(&ctlr->io_mutex);
/* Lock queue */
@@ -2169,8 +2149,8 @@ static int __spi_queued_transfer(struct spi_device *spi,
/**
* spi_queued_transfer - transfer function for queued transfers
- * @spi: spi device which is requesting transfer
- * @msg: spi message which is to handled is queued to driver queue
+ * @spi: SPI device which is requesting transfer
+ * @msg: SPI message which is to handled is queued to driver queue
*
* Return: zero on success, else a negative error code.
*/
@@ -2399,9 +2379,6 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
struct spi_device *spi;
struct device_node *nc;
- if (!ctlr->dev.of_node)
- return;
-
for_each_available_child_of_node(ctlr->dev.of_node, nc) {
if (of_node_test_and_set_flag(nc, OF_POPULATED))
continue;
@@ -2432,11 +2409,12 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { }
struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
u8 chip_select)
{
+ struct spi_controller *ctlr = spi->controller;
struct spi_device *ancillary;
int rc = 0;
/* Alloc an spi_device */
- ancillary = spi_alloc_device(spi->controller);
+ ancillary = spi_alloc_device(ctlr);
if (!ancillary) {
rc = -ENOMEM;
goto err_out;
@@ -2451,8 +2429,10 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
ancillary->max_speed_hz = spi->max_speed_hz;
ancillary->mode = spi->mode;
+ WARN_ON(!mutex_is_locked(&ctlr->add_lock));
+
/* Register the new device */
- rc = spi_add_device_locked(ancillary);
+ rc = __spi_add_device(ancillary);
if (rc) {
dev_err(&spi->dev, "failed to register ancillary device\n");
goto err_out;
@@ -2499,7 +2479,7 @@ static int acpi_spi_count(struct acpi_resource *ares, void *data)
* acpi_spi_count_resources - Count the number of SpiSerialBus resources
* @adev: ACPI device
*
- * Returns the number of SpiSerialBus resources in the ACPI-device's
+ * Return: the number of SpiSerialBus resources in the ACPI-device's
* resource-list; or a negative error code.
*/
int acpi_spi_count_resources(struct acpi_device *adev)
@@ -2633,10 +2613,10 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
* @adev: ACPI Device for the spi device
* @index: Index of the spi resource inside the ACPI Node
*
- * This should be used to allocate a new spi device from and ACPI Node.
- * The caller is responsible for calling spi_add_device to register the spi device.
+ * This should be used to allocate a new SPI device from and ACPI Device node.
+ * The caller is responsible for calling spi_add_device to register the SPI device.
*
- * If ctlr is set to NULL, the Controller for the spi device will be looked up
+ * If ctlr is set to NULL, the Controller for the SPI device will be looked up
* using the resource.
* If index is set to -1, index is not used.
* Note: If index is -1, ctlr must be set.
@@ -2817,8 +2797,7 @@ static ssize_t slave_show(struct device *dev, struct device_attribute *attr,
struct device *child;
child = device_find_any_child(&ctlr->dev);
- return sprintf(buf, "%s\n",
- child ? to_spi_device(child)->modalias : NULL);
+ return sysfs_emit(buf, "%s\n", child ? to_spi_device(child)->modalias : NULL);
}
static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
@@ -3056,7 +3035,7 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr)
ctlr->unused_native_cs = ffs(~native_cs_mask) - 1;
- if ((ctlr->flags & SPI_MASTER_GPIO_SS) && num_cs_gpios &&
+ if ((ctlr->flags & SPI_CONTROLLER_GPIO_SS) && num_cs_gpios &&
ctlr->max_native_cs && ctlr->unused_native_cs >= ctlr->max_native_cs) {
dev_err(dev, "No unused native chip select available\n");
return -EINVAL;
@@ -3084,6 +3063,20 @@ static int spi_controller_check_ops(struct spi_controller *ctlr)
return 0;
}
+/* Allocate dynamic bus number using Linux idr */
+static int spi_controller_id_alloc(struct spi_controller *ctlr, int start, int end)
+{
+ int id;
+
+ mutex_lock(&board_lock);
+ id = idr_alloc(&spi_master_idr, ctlr, start, end, GFP_KERNEL);
+ mutex_unlock(&board_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id == -ENOSPC ? -EBUSY : id;
+ ctlr->bus_num = id;
+ return 0;
+}
+
/**
* spi_register_controller - register SPI master or slave controller
* @ctlr: initialized master, originally from spi_alloc_master() or
@@ -3111,8 +3104,8 @@ int spi_register_controller(struct spi_controller *ctlr)
{
struct device *dev = ctlr->dev.parent;
struct boardinfo *bi;
+ int first_dynamic;
int status;
- int id, first_dynamic;
if (!dev)
return -ENODEV;
@@ -3125,27 +3118,13 @@ int spi_register_controller(struct spi_controller *ctlr)
if (status)
return status;
+ if (ctlr->bus_num < 0)
+ ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi");
if (ctlr->bus_num >= 0) {
/* Devices with a fixed bus num must check-in with the num */
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
- ctlr->bus_num + 1, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
- ctlr->bus_num = id;
- } else if (ctlr->dev.of_node) {
- /* Allocate dynamic bus number using Linux idr */
- id = of_alias_get_id(ctlr->dev.of_node, "spi");
- if (id >= 0) {
- ctlr->bus_num = id;
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
- ctlr->bus_num + 1, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
- }
+ status = spi_controller_id_alloc(ctlr, ctlr->bus_num, ctlr->bus_num + 1);
+ if (status)
+ return status;
}
if (ctlr->bus_num < 0) {
first_dynamic = of_alias_get_highest_id("spi");
@@ -3154,13 +3133,9 @@ int spi_register_controller(struct spi_controller *ctlr)
else
first_dynamic++;
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
- 0, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id;
- ctlr->bus_num = id;
+ status = spi_controller_id_alloc(ctlr, first_dynamic, 0);
+ if (status)
+ return status;
}
ctlr->bus_lock_flag = 0;
init_completion(&ctlr->xfer_completion);
@@ -3339,7 +3314,8 @@ void spi_unregister_controller(struct spi_controller *ctlr)
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
mutex_unlock(&ctlr->add_lock);
- /* Release the last reference on the controller if its driver
+ /*
+ * Release the last reference on the controller if its driver
* has not yet been converted to devm_spi_alloc_master/slave().
*/
if (!ctlr->devm_allocated)
@@ -3552,7 +3528,7 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
/* All the others need rx_buf/tx_buf also set */
for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
- /* Update rx_buf, tx_buf and dma */
+ /* Update rx_buf, tx_buf and DMA */
if (xfers[i].rx_buf)
xfers[i].rx_buf += offset;
if (xfers[i].rx_dma)
@@ -3622,7 +3598,7 @@ EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
/**
- * spi_split_transfers_maxwords - split spi transfers into multiple transfers
+ * spi_split_transfers_maxwords - split SPI transfers into multiple transfers
* when an individual transfer exceeds a
* certain number of SPI words
* @ctlr: the @spi_controller for this transfer
@@ -3650,13 +3626,7 @@ int spi_split_transfers_maxwords(struct spi_controller *ctlr,
size_t maxsize;
int ret;
- if (xfer->bits_per_word <= 8)
- maxsize = maxwords;
- else if (xfer->bits_per_word <= 16)
- maxsize = 2 * maxwords;
- else
- maxsize = 4 * maxwords;
-
+ maxsize = maxwords * roundup_pow_of_two(BITS_TO_BYTES(xfer->bits_per_word));
if (xfer->len > maxsize) {
ret = __spi_split_transfer_maxsize(ctlr, msg, &xfer,
maxsize, gfp);
@@ -3671,7 +3641,8 @@ EXPORT_SYMBOL_GPL(spi_split_transfers_maxwords);
/*-------------------------------------------------------------------------*/
-/* Core methods for SPI controller protocol drivers. Some of the
+/*
+ * Core methods for SPI controller protocol drivers. Some of the
* other core methods are currently defined as inline functions.
*/
@@ -3731,7 +3702,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
- * or from it. When this function returns, the spi device is deselected.
+ * or from it. When this function returns, the SPI device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
@@ -3906,11 +3877,9 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
*/
if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
spi_get_csgpiod(spi, 0))) {
- size_t maxsize;
+ size_t maxsize = BITS_TO_BYTES(spi->bits_per_word);
int ret;
- maxsize = (spi->bits_per_word + 7) / 8;
-
/* spi_split_transfers_maxsize() requires message->spi */
message->spi = spi;
@@ -4071,7 +4040,7 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
* spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
- * Context: any (irqs may be blocked, etc)
+ * Context: any (IRQs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
@@ -4125,7 +4094,7 @@ EXPORT_SYMBOL_GPL(spi_async);
* spi_async_locked - version of spi_async with exclusive bus usage
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
- * Context: any (irqs may be blocked, etc)
+ * Context: any (IRQs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
@@ -4388,9 +4357,9 @@ static u8 *buf;
/**
* spi_write_then_read - SPI synchronous write followed by read
* @spi: device with which data will be exchanged
- * @txbuf: data to be written (need not be dma-safe)
+ * @txbuf: data to be written (need not be DMA-safe)
* @n_tx: size of txbuf, in bytes
- * @rxbuf: buffer into which data will be read (need not be dma-safe)
+ * @rxbuf: buffer into which data will be read (need not be DMA-safe)
* @n_rx: size of rxbuf, in bytes
* Context: can sleep
*
@@ -4401,7 +4370,7 @@ static u8 *buf;
*
* Parameters to this routine are always copied using a small buffer.
* Performance-sensitive or bulk transfer code should instead use
- * spi_{async,sync}() calls with dma-safe buffers.
+ * spi_{async,sync}() calls with DMA-safe buffers.
*
* Return: zero on success, else a negative error code.
*/
@@ -4446,7 +4415,7 @@ int spi_write_then_read(struct spi_device *spi,
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
- /* Do the i/o */
+ /* Do the I/O */
status = spi_sync(spi, &message);
if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index 80e36d03c4e2..0e0ccef4871e 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -11,45 +11,45 @@
static const struct usb_device_id usb_prism_tbl[] = {
PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"),
- PRISM_DEV(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11"),
- PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter"),
+ PRISM_DEV(0x07aa, 0x0012, "Corega USB Wireless LAN Stick-11"),
+ PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps USB WLAN Adapter"),
PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"),
- PRISM_DEV(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
- PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter"),
+ PRISM_DEV(0x08de, 0x7a01, "PRISM25 USB IEEE 802.11 Mini Adapter"),
+ PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B USB LAN Adapter"),
PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
- PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter"),
+ PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 USB Wireless Adapter"),
PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"),
PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"),
- PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter"),
- PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter"),
- PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter"),
- PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter"),
- PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter"),
+ PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 USB Wireless 802.11b Adapter"),
+ PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 USB Wireless Adapter"),
+ PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps USB WLAN Adapter"),
+ PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 USB Wireless Adapter"),
+ PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 USB Wireless Adapter"),
PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"),
PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"),
PRISM_DEV(0x0846, 0x4110, "NetGear MA111"),
PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"),
- PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB Wireless USB Adapter"),
- PRISM_DEV(0x2001, 0x3700, "DWL-122 Wireless USB Adapter"),
- PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter"),
+ PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB USB Wireless Adapter"),
+ PRISM_DEV(0x2001, 0x3700, "DWL-122 USB Wireless Adapter"),
+ PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F USB Wireless Adapter"),
PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"),
- PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter"),
- PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter"),
+ PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H USB WLAN Adapter"),
+ PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 USB WLAN Adapter"),
PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"),
PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"),
- PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter"),
- PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter"),
+ PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan USB 802.11b Adapter"),
+ PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA USB 802.11b Adapter"),
PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."),
- PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter"),
+ PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 USB 802.11b Adapter"),
PRISM_DEV(0x0543, 0x0f01,
"ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"),
PRISM_DEV(0x067c, 0x1022,
- "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter"),
+ "Siemens SpeedStream 1022 11Mbps USB WLAN Adapter"),
PRISM_DEV(0x049f, 0x0033,
"Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"),
{ } /* terminator */
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 3d1b511ea284..a7050f63b7cc 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -689,7 +689,6 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
return PTR_ERR(bip);
}
- bip->bip_iter.bi_size = bio_integrity_bytes(bi, bio_sectors(bio));
/* virtual start sector must be in integrity interval units */
bip_set_seed(bip, bio->bi_iter.bi_sector >>
(bi->interval_exp - SECTOR_SHIFT));
@@ -697,7 +696,7 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
(unsigned long long)bip->bip_iter.bi_sector);
- resid = bip->bip_iter.bi_size;
+ resid = bio_integrity_bytes(bi, bio_sectors(bio));
while (resid > 0 && sg_miter_next(miter)) {
len = min_t(size_t, miter->length, resid);
diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c
index 756b218880a7..81ebbf6de0de 100644
--- a/drivers/thermal/amlogic_thermal.c
+++ b/drivers/thermal/amlogic_thermal.c
@@ -22,8 +22,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/broadcom/bcm2711_thermal.c b/drivers/thermal/broadcom/bcm2711_thermal.c
index c243a76a3471..03ac2d02e9d4 100644
--- a/drivers/thermal/broadcom/bcm2711_thermal.c
+++ b/drivers/thermal/broadcom/bcm2711_thermal.c
@@ -15,8 +15,8 @@
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
index 72d1dbe60b8f..0b73abdaa792 100644
--- a/drivers/thermal/broadcom/brcmstb_thermal.c
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
@@ -17,8 +17,8 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
#include <linux/thermal.h>
#define AVS_TMON_STATUS 0x00
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 3f09ef8be41a..fb54ed4bf6f0 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -13,9 +13,9 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/of_device.h>
#include <linux/thermal.h>
#define HI6220_TEMP0_LAG (0x0)
diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
index d4b40869c7d7..e89b11b3f2b9 100644
--- a/drivers/thermal/imx8mm_thermal.c
+++ b/drivers/thermal/imx8mm_thermal.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c
index 8d6b4ef23746..7224f8d21db9 100644
--- a/drivers/thermal/imx_sc_thermal.c
+++ b/drivers/thermal/imx_sc_thermal.c
@@ -8,7 +8,6 @@
#include <linux/firmware/imx/sci.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index a94ec0a0c9dd..826358cbe810 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -11,7 +11,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
#include <linux/nvmem-consumer.h>
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index 5e1164226ada..ddd600820f68 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -15,6 +15,7 @@
#define INT3400_THERMAL_TABLE_CHANGED 0x83
#define INT3400_ODVP_CHANGED 0x88
#define INT3400_KEEP_ALIVE 0xA0
+#define INT3400_FAKE_TEMP (20 * 1000) /* faked temp sensor with 20C */
enum int3400_thermal_uuid {
INT3400_THERMAL_ACTIVE = 0,
@@ -453,6 +454,7 @@ static void int3400_notify(acpi_handle handle,
void *data)
{
struct int3400_thermal_priv *priv = data;
+ struct device *dev;
char *thermal_prop[5];
int therm_event;
@@ -475,12 +477,14 @@ static void int3400_notify(acpi_handle handle,
return;
}
- thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", priv->thermal->type);
- thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", priv->thermal->temperature);
+ dev = thermal_zone_device(priv->thermal);
+
+ thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", thermal_zone_device_type(priv->thermal));
+ thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", INT3400_FAKE_TEMP);
thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=");
thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", therm_event);
thermal_prop[4] = NULL;
- kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, thermal_prop);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, thermal_prop);
kfree(thermal_prop[0]);
kfree(thermal_prop[1]);
kfree(thermal_prop[2]);
@@ -490,7 +494,7 @@ static void int3400_notify(acpi_handle handle,
static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
int *temp)
{
- *temp = 20 * 1000; /* faked temp sensor with 20C */
+ *temp = INT3400_FAKE_TEMP;
return 0;
}
@@ -499,32 +503,28 @@ static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
{
struct int3400_thermal_priv *priv = thermal_zone_device_priv(thermal);
int result = 0;
+ int enabled;
if (!priv)
return -EINVAL;
- if (mode != thermal->mode) {
- int enabled;
-
- enabled = mode == THERMAL_DEVICE_ENABLED;
+ enabled = mode == THERMAL_DEVICE_ENABLED;
- if (priv->os_uuid_mask) {
- if (!enabled) {
- priv->os_uuid_mask = 0;
- result = set_os_uuid_mask(priv, priv->os_uuid_mask);
- }
- goto eval_odvp;
+ if (priv->os_uuid_mask) {
+ if (!enabled) {
+ priv->os_uuid_mask = 0;
+ result = set_os_uuid_mask(priv, priv->os_uuid_mask);
}
-
- if (priv->current_uuid_index < 0 ||
- priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID)
- return -EINVAL;
-
- result = int3400_thermal_run_osc(priv->adev->handle,
- int3400_thermal_uuids[priv->current_uuid_index],
- &enabled);
+ goto eval_odvp;
}
+ if (priv->current_uuid_index < 0 ||
+ priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID)
+ return -EINVAL;
+
+ result = int3400_thermal_run_osc(priv->adev->handle,
+ int3400_thermal_uuids[priv->current_uuid_index],
+ &enabled);
eval_odvp:
evaluate_odvp(priv);
diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
index 217786fba185..c93a28eec4db 100644
--- a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c
@@ -70,18 +70,7 @@ static struct platform_driver int3401_driver = {
},
};
-static int __init proc_thermal_init(void)
-{
- return platform_driver_register(&int3401_driver);
-}
-
-static void __exit proc_thermal_exit(void)
-{
- platform_driver_unregister(&int3401_driver);
-}
-
-module_init(proc_thermal_init);
-module_exit(proc_thermal_exit);
+module_platform_driver(int3401_driver);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
index 09e032f822f3..16fd9df5f36d 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
@@ -59,7 +59,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev,
* ACPI/MSR. So we don't want to fail for auxiliary DTSs.
*/
proc_priv->soc_dts = intel_soc_dts_iosf_init(
- INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
+ INTEL_SOC_DTS_INTERRUPT_MSI, false, 0);
if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
ret = pci_enable_msi(pdev);
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c
index db97499f4f0a..d00def3c4703 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.c
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.c
@@ -37,44 +37,11 @@
/* DTS encoding for TJ MAX temperature */
#define SOC_DTS_TJMAX_ENCODING 0x7F
-/* Only 2 out of 4 is allowed for OSPM */
-#define SOC_MAX_DTS_TRIPS 2
-
/* Mask for two trips in status bits */
#define SOC_DTS_TRIP_MASK 0x03
-/* DTS0 and DTS 1 */
-#define SOC_MAX_DTS_SENSORS 2
-
-static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
- int *temp)
-{
- int status;
- u32 out;
- struct intel_soc_dts_sensor_entry *dts;
- struct intel_soc_dts_sensors *sensors;
-
- dts = thermal_zone_device_priv(tzd);
- sensors = dts->sensors;
- mutex_lock(&sensors->dts_update_lock);
- status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
- SOC_DTS_OFFSET_PTPS, &out);
- mutex_unlock(&sensors->dts_update_lock);
- if (status)
- return status;
-
- out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
- if (!out)
- *temp = 0;
- else
- *temp = sensors->tj_max - out * 1000;
-
- return 0;
-}
-
-static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
- int thres_index, int temp,
- enum thermal_trip_type trip_type)
+static int update_trip_temp(struct intel_soc_dts_sensors *sensors,
+ int thres_index, int temp)
{
int status;
u32 temp_out;
@@ -85,7 +52,6 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
u32 store_te_out;
u32 te_out;
u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
- struct intel_soc_dts_sensors *sensors = dts->sensors;
if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
@@ -148,8 +114,6 @@ static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
if (status)
goto err_restore_te_out;
- dts->trip_types[thres_index] = trip_type;
-
return 0;
err_restore_te_out:
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
@@ -165,6 +129,22 @@ err_restore_ptps:
return status;
}
+static int configure_trip(struct intel_soc_dts_sensor_entry *dts,
+ int thres_index, enum thermal_trip_type trip_type,
+ int temp)
+{
+ int ret;
+
+ ret = update_trip_temp(dts->sensors, thres_index, temp);
+ if (ret)
+ return ret;
+
+ dts->trips[thres_index].temperature = temp;
+ dts->trips[thres_index].type = trip_type;
+
+ return 0;
+}
+
static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
int temp)
{
@@ -176,23 +156,12 @@ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
return -EINVAL;
mutex_lock(&sensors->dts_update_lock);
- status = update_trip_temp(dts, trip, temp,
- dts->trip_types[trip]);
+ status = update_trip_temp(sensors, trip, temp);
mutex_unlock(&sensors->dts_update_lock);
return status;
}
-static int sys_get_trip_type(struct thermal_zone_device *tzd,
- int trip, enum thermal_trip_type *type)
-{
- struct intel_soc_dts_sensor_entry *dts = thermal_zone_device_priv(tzd);
-
- *type = dts->trip_types[trip];
-
- return 0;
-}
-
static int sys_get_curr_temp(struct thermal_zone_device *tzd,
int *temp)
{
@@ -217,8 +186,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
- .get_trip_temp = sys_get_trip_temp,
- .get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
};
@@ -245,22 +212,18 @@ static int soc_dts_enable(int id)
static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
{
- if (dts) {
- iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
- SOC_DTS_OFFSET_ENABLE, dts->store_status);
- thermal_zone_device_unregister(dts->tzone);
- }
+ iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
+ SOC_DTS_OFFSET_ENABLE, dts->store_status);
+ thermal_zone_device_unregister(dts->tzone);
}
static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
- bool notification_support, int trip_cnt,
- int read_only_trip_cnt)
+ bool critical_trip)
{
+ int writable_trip_cnt = SOC_MAX_DTS_TRIPS;
char name[10];
unsigned long trip;
- int trip_count = 0;
- int trip_mask = 0;
- int writable_trip_cnt = 0;
+ int trip_mask;
unsigned long ptps;
u32 store_ptps;
unsigned long i;
@@ -273,11 +236,11 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
goto err_ret;
dts->id = id;
- if (notification_support) {
- trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
- writable_trip_cnt = trip_count - read_only_trip_cnt;
- trip_mask = GENMASK(writable_trip_cnt - 1, 0);
- }
+
+ if (critical_trip)
+ writable_trip_cnt--;
+
+ trip_mask = GENMASK(writable_trip_cnt - 1, 0);
/* Check if the writable trip we provide is not used by BIOS */
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
@@ -290,13 +253,12 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
trip_mask &= ~BIT(i / 8);
}
dts->trip_mask = trip_mask;
- dts->trip_count = trip_count;
snprintf(name, sizeof(name), "soc_dts%d", id);
- dts->tzone = thermal_zone_device_register(name,
- trip_count,
- trip_mask,
- dts, &tzone_ops,
- NULL, 0, 0);
+ dts->tzone = thermal_zone_device_register_with_trips(name, dts->trips,
+ SOC_MAX_DTS_TRIPS,
+ trip_mask,
+ dts, &tzone_ops,
+ NULL, 0, 0);
if (IS_ERR(dts->tzone)) {
ret = PTR_ERR(dts->tzone);
goto err_ret;
@@ -316,26 +278,6 @@ err_ret:
return ret;
}
-int intel_soc_dts_iosf_add_read_only_critical_trip(
- struct intel_soc_dts_sensors *sensors, int critical_offset)
-{
- int i, j;
-
- for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
- int temp = sensors->tj_max - critical_offset;
- unsigned long count = entry->trip_count;
- unsigned long mask = entry->trip_mask;
-
- j = find_first_zero_bit(&mask, count);
- if (j < count)
- return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
- }
-
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip);
-
void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
{
u32 sticky_out;
@@ -371,12 +313,17 @@ void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
}
EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
-struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
- enum intel_soc_dts_interrupt_type intr_type, int trip_count,
- int read_only_trip_count)
+static void dts_trips_reset(struct intel_soc_dts_sensors *sensors, int dts_index)
+{
+ configure_trip(&sensors->soc_dts[dts_index], 0, 0, 0);
+ configure_trip(&sensors->soc_dts[dts_index], 1, 0, 0);
+}
+
+struct intel_soc_dts_sensors *
+intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,
+ bool critical_trip, int crit_offset)
{
struct intel_soc_dts_sensors *sensors;
- bool notification;
int tj_max;
int ret;
int i;
@@ -384,9 +331,6 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
if (!iosf_mbi_available())
return ERR_PTR(-ENODEV);
- if (!trip_count || read_only_trip_count > trip_count)
- return ERR_PTR(-EINVAL);
-
tj_max = intel_tcc_get_tjmax(-1);
if (tj_max < 0)
return ERR_PTR(tj_max);
@@ -399,37 +343,46 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
mutex_init(&sensors->dts_update_lock);
sensors->intr_type = intr_type;
sensors->tj_max = tj_max * 1000;
- if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
- notification = false;
- else
- notification = true;
+
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
+ enum thermal_trip_type trip_type;
+ int temp;
+
sensors->soc_dts[i].sensors = sensors;
- ret = add_dts_thermal_zone(i, &sensors->soc_dts[i],
- notification, trip_count,
- read_only_trip_count);
+
+ ret = configure_trip(&sensors->soc_dts[i], 0,
+ THERMAL_TRIP_PASSIVE, 0);
+ if (ret)
+ goto err_reset_trips;
+
+ if (critical_trip) {
+ trip_type = THERMAL_TRIP_CRITICAL;
+ temp = sensors->tj_max - crit_offset;
+ } else {
+ trip_type = THERMAL_TRIP_PASSIVE;
+ temp = 0;
+ }
+ ret = configure_trip(&sensors->soc_dts[i], 1, trip_type, temp);
if (ret)
- goto err_free;
+ goto err_reset_trips;
}
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- ret = update_trip_temp(&sensors->soc_dts[i], 0, 0,
- THERMAL_TRIP_PASSIVE);
- if (ret)
- goto err_remove_zone;
-
- ret = update_trip_temp(&sensors->soc_dts[i], 1, 0,
- THERMAL_TRIP_PASSIVE);
+ ret = add_dts_thermal_zone(i, &sensors->soc_dts[i], critical_trip);
if (ret)
goto err_remove_zone;
}
return sensors;
+
err_remove_zone:
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
remove_dts_thermal_zone(&sensors->soc_dts[i]);
-err_free:
+err_reset_trips:
+ for (i = 0; i < SOC_MAX_DTS_SENSORS; i++)
+ dts_trips_reset(sensors, i);
+
kfree(sensors);
return ERR_PTR(ret);
}
@@ -440,9 +393,8 @@ void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
int i;
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- update_trip_temp(&sensors->soc_dts[i], 0, 0, 0);
- update_trip_temp(&sensors->soc_dts[i], 1, 0, 0);
remove_dts_thermal_zone(&sensors->soc_dts[i]);
+ dts_trips_reset(sensors, i);
}
kfree(sensors);
}
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.h b/drivers/thermal/intel/intel_soc_dts_iosf.h
index c54945748200..162841df0ebe 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.h
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.h
@@ -12,6 +12,9 @@
/* DTS0 and DTS 1 */
#define SOC_MAX_DTS_SENSORS 2
+/* Only 2 out of 4 is allowed for OSPM */
+#define SOC_MAX_DTS_TRIPS 2
+
enum intel_soc_dts_interrupt_type {
INTEL_SOC_DTS_INTERRUPT_NONE,
INTEL_SOC_DTS_INTERRUPT_APIC,
@@ -26,8 +29,7 @@ struct intel_soc_dts_sensor_entry {
int id;
u32 store_status;
u32 trip_mask;
- u32 trip_count;
- enum thermal_trip_type trip_types[2];
+ struct thermal_trip trips[SOC_MAX_DTS_TRIPS];
struct thermal_zone_device *tzone;
struct intel_soc_dts_sensors *sensors;
};
@@ -40,12 +42,11 @@ struct intel_soc_dts_sensors {
struct intel_soc_dts_sensor_entry soc_dts[SOC_MAX_DTS_SENSORS];
};
-struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
- enum intel_soc_dts_interrupt_type intr_type, int trip_count,
- int read_only_trip_count);
+
+struct intel_soc_dts_sensors *
+intel_soc_dts_iosf_init(enum intel_soc_dts_interrupt_type intr_type,
+ bool critical_trip, int crit_offset);
void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors);
void intel_soc_dts_iosf_interrupt_handler(
struct intel_soc_dts_sensors *sensors);
-int intel_soc_dts_iosf_add_read_only_critical_trip(
- struct intel_soc_dts_sensors *sensors, int critical_offset);
#endif
diff --git a/drivers/thermal/intel/intel_soc_dts_thermal.c b/drivers/thermal/intel/intel_soc_dts_thermal.c
index 92e5c19d03f6..9c825c6e1f38 100644
--- a/drivers/thermal/intel/intel_soc_dts_thermal.c
+++ b/drivers/thermal/intel/intel_soc_dts_thermal.c
@@ -51,7 +51,8 @@ static int __init intel_soc_thermal_init(void)
return -ENODEV;
/* Create a zone with 2 trips with marked as read only */
- soc_dts = intel_soc_dts_iosf_init(INTEL_SOC_DTS_INTERRUPT_APIC, 2, 1);
+ soc_dts = intel_soc_dts_iosf_init(INTEL_SOC_DTS_INTERRUPT_APIC, true,
+ crit_offset);
if (IS_ERR(soc_dts)) {
err = PTR_ERR(soc_dts);
return err;
@@ -88,21 +89,7 @@ static int __init intel_soc_thermal_init(void)
}
}
- err = intel_soc_dts_iosf_add_read_only_critical_trip(soc_dts,
- crit_offset);
- if (err)
- goto error_trips;
-
return 0;
-
-error_trips:
- if (soc_dts_thres_irq) {
- free_irq(soc_dts_thres_irq, soc_dts);
- acpi_unregister_gsi(soc_dts_thres_gsi);
- }
- intel_soc_dts_iosf_exit(soc_dts);
-
- return err;
}
static void __exit intel_soc_thermal_exit(void)
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
index e95f799454fe..6c392147e6d1 100644
--- a/drivers/thermal/intel/intel_tcc_cooling.c
+++ b/drivers/thermal/intel/intel_tcc_cooling.c
@@ -60,7 +60,7 @@ static const struct x86_cpu_id tcc_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL),
- X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, NULL),
+ X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, NULL),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, NULL),
diff --git a/drivers/thermal/k3_bandgap.c b/drivers/thermal/k3_bandgap.c
index 1c3e590157ec..68f59b3735d3 100644
--- a/drivers/thermal/k3_bandgap.c
+++ b/drivers/thermal/k3_bandgap.c
@@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/thermal.h>
#include <linux/types.h>
diff --git a/drivers/thermal/k3_j72xx_bandgap.c b/drivers/thermal/k3_j72xx_bandgap.c
index 5be1f09eeb2c..a5a0fc9b9356 100644
--- a/drivers/thermal/k3_j72xx_bandgap.c
+++ b/drivers/thermal/k3_j72xx_bandgap.c
@@ -10,10 +10,10 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/err.h>
#include <linux/types.h>
-#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/thermal.h>
#include <linux/of.h>
diff --git a/drivers/thermal/mediatek/auxadc_thermal.c b/drivers/thermal/mediatek/auxadc_thermal.c
index f59d36de20a0..c537aed71017 100644
--- a/drivers/thermal/mediatek/auxadc_thermal.c
+++ b/drivers/thermal/mediatek/auxadc_thermal.c
@@ -15,7 +15,6 @@
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c
index b693fac2d677..054c965ae5e1 100644
--- a/drivers/thermal/mediatek/lvts_thermal.c
+++ b/drivers/thermal/mediatek/lvts_thermal.c
@@ -13,7 +13,7 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/nvmem-consumer.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
index 5ddc39b2be32..756ac6842ff9 100644
--- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
+++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
index 0e8ebfcd84c5..78c5cfe6a0c0 100644
--- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
@@ -10,7 +10,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index 9029d01e029b..bd2fb8c2e968 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -11,7 +11,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index b8571f7090aa..293f8dd9fe0a 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -11,7 +11,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reboot.h>
diff --git a/drivers/thermal/rzg2l_thermal.c b/drivers/thermal/rzg2l_thermal.c
index b56981f85306..6b2bf3426f52 100644
--- a/drivers/thermal/rzg2l_thermal.c
+++ b/drivers/thermal/rzg2l_thermal.c
@@ -9,8 +9,8 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/math.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 45e5c840d130..58f4d8f7a3fd 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -15,7 +15,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index 2fb90fdad76e..e27c4bdc8912 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -6,7 +6,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c
index 903fcf1763f1..142a7e5d12f4 100644
--- a/drivers/thermal/st/stm_thermal.c
+++ b/drivers/thermal/st/stm_thermal.c
@@ -14,8 +14,6 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
index 195f3c5d0b38..cca16d632d9f 100644
--- a/drivers/thermal/sun8i_thermal.c
+++ b/drivers/thermal/sun8i_thermal.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
diff --git a/drivers/thermal/tegra/tegra30-tsensor.c b/drivers/thermal/tegra/tegra30-tsensor.c
index c243e9d76d3c..d911fa60f100 100644
--- a/drivers/thermal/tegra/tegra30-tsensor.c
+++ b/drivers/thermal/tegra/tegra30-tsensor.c
@@ -18,7 +18,7 @@
#include <linux/iopoll.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/reset.h>
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index cc2b5e81c620..a59700593d32 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -348,7 +348,8 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip_id)
struct thermal_trip trip;
/* Ignore disabled trip points */
- if (test_bit(trip_id, &tz->trips_disabled))
+ if (test_bit(trip_id, &tz->trips_disabled) ||
+ trip.temperature == THERMAL_TEMP_INVALID)
return;
__thermal_zone_get_trip(tz, trip_id, &trip);
@@ -496,6 +497,25 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
+/**
+ * thermal_zone_device_exec - Run a callback under the zone lock.
+ * @tz: Thermal zone.
+ * @cb: Callback to run.
+ * @data: Data to pass to the callback.
+ */
+void thermal_zone_device_exec(struct thermal_zone_device *tz,
+ void (*cb)(struct thermal_zone_device *,
+ unsigned long),
+ unsigned long data)
+{
+ mutex_lock(&tz->lock);
+
+ cb(tz, data);
+
+ mutex_unlock(&tz->lock);
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_exec);
+
static void thermal_zone_device_check(struct work_struct *work)
{
struct thermal_zone_device *tz = container_of(work, struct
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 17c1bbed734d..04513f9fbfa1 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -54,10 +54,6 @@ int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
void *thermal_governor);
-int __for_each_thermal_trip(struct thermal_zone_device *,
- int (*cb)(struct thermal_trip *, void *),
- void *);
-
struct thermal_zone_device *thermal_zone_get_by_id(int id);
struct thermal_attr {
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index bc07ae1c284c..4ca905723429 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -10,8 +10,7 @@
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/types.h>
@@ -292,13 +291,13 @@ static int __thermal_of_unbind(struct device_node *map_np, int index, int trip_i
ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
index, &cooling_spec);
- of_node_put(cooling_spec.np);
-
if (ret < 0) {
pr_err("Invalid cooling-device entry\n");
return ret;
}
+ of_node_put(cooling_spec.np);
+
if (cooling_spec.args_count < 2) {
pr_err("wrong reference to cooling device, missing limits\n");
return -EINVAL;
@@ -325,13 +324,13 @@ static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id,
ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
index, &cooling_spec);
- of_node_put(cooling_spec.np);
-
if (ret < 0) {
pr_err("Invalid cooling-device entry\n");
return ret;
}
+ of_node_put(cooling_spec.np);
+
if (cooling_spec.args_count < 2) {
pr_err("wrong reference to cooling device, missing limits\n");
return -EINVAL;
diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c
index 907f3a4d7bc8..53115cfdfd42 100644
--- a/drivers/thermal/thermal_trip.c
+++ b/drivers/thermal/thermal_trip.c
@@ -9,28 +9,26 @@
*/
#include "thermal_core.h"
-int __for_each_thermal_trip(struct thermal_zone_device *tz,
- int (*cb)(struct thermal_trip *, void *),
- void *data)
+int for_each_thermal_trip(struct thermal_zone_device *tz,
+ int (*cb)(struct thermal_trip *, void *),
+ void *data)
{
int i, ret;
- struct thermal_trip trip;
lockdep_assert_held(&tz->lock);
- for (i = 0; i < tz->num_trips; i++) {
-
- ret = __thermal_zone_get_trip(tz, i, &trip);
- if (ret)
- return ret;
+ if (!tz->trips)
+ return -ENODATA;
- ret = cb(&trip, data);
+ for (i = 0; i < tz->num_trips; i++) {
+ ret = cb(&tz->trips[i], data);
if (ret)
return ret;
}
return 0;
}
+EXPORT_SYMBOL_GPL(for_each_thermal_trip);
int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
{
diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c
index aef6119cc004..6f32ab61d174 100644
--- a/drivers/thermal/uniphier_thermal.c
+++ b/drivers/thermal/uniphier_thermal.c
@@ -12,7 +12,6 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 82d35dbbfa6c..9be63a1f1f0c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -222,16 +222,11 @@ static inline int calculate_baud_abs_diff(struct uart_port *port,
unsigned int baud, unsigned int mode)
{
unsigned int n = port->uartclk / (mode * baud);
- int abs_diff;
if (n == 0)
n = 1;
- abs_diff = baud - (port->uartclk / (mode * n));
- if (abs_diff < 0)
- abs_diff = -abs_diff;
-
- return abs_diff;
+ return abs_diff(baud, port->uartclk / (mode * n));
}
/*
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index b6e70c5cfa17..e1df63a88aac 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -342,7 +342,7 @@ static const struct sysrq_key_op sysrq_ftrace_dump_op = {
static void sysrq_handle_showmem(int key)
{
- show_mem(0, NULL);
+ show_mem();
}
static const struct sysrq_key_op sysrq_showmem_op = {
.handler = sysrq_handle_showmem,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 63db04b9113a..27d8e3a1aace 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3031,7 +3031,7 @@ void __do_SAK(struct tty_struct *tty)
} while_each_pid_task(session, PIDTYPE_SID, p);
/* Now kill any processes that happen to have the tty open */
- do_each_thread(g, p) {
+ for_each_process_thread(g, p) {
if (p->signal->tty == tty) {
tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n",
task_pid_nr(p), p->comm);
@@ -3048,7 +3048,7 @@ void __do_SAK(struct tty_struct *tty)
PIDTYPE_SID);
}
task_unlock(p);
- } while_each_thread(g, p);
+ }
read_unlock(&tasklist_lock);
put_pid(session);
}
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index be8313cdbac3..358f216c6cd6 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -606,7 +606,7 @@ static void fn_scroll_back(struct vc_data *vc)
static void fn_show_mem(struct vc_data *vc)
{
- show_mem(0, NULL);
+ show_mem();
}
static void fn_show_state(struct vc_data *vc)
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
index 6fb0e007af63..386674ead7f0 100644
--- a/drivers/ufs/core/ufs-mcq.c
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -580,7 +580,6 @@ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba,
{
struct ufshcd_lrb *lrbp = &hba->lrb[task_tag];
struct utp_transfer_req_desc *utrd;
- u32 mask = hwq->max_entries - 1;
__le64 cmd_desc_base_addr;
bool ret = false;
u64 addr, match;
@@ -608,7 +607,10 @@ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba,
ret = true;
goto out;
}
- sq_head_slot = (sq_head_slot + 1) & mask;
+
+ sq_head_slot++;
+ if (sq_head_slot == hwq->max_entries)
+ sq_head_slot = 0;
}
out:
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 8d6fd4c3324f..c1557d21b027 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -321,7 +321,7 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0,
REG_UFS_CFG1);
- if (host->hw_ver.major == 0x05)
+ if (host->hw_ver.major >= 0x05)
ufshcd_rmwl(host->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0);
/* make sure above configuration is applied before we return */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 1a16a8bdea60..4f68f6ef3cc1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -2642,21 +2642,21 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CONTROL\n", __func__);
ret = proc_control(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_BULK:
snoop(&dev->dev, "%s: BULK\n", __func__);
ret = proc_bulk(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_RESETEP:
snoop(&dev->dev, "%s: RESETEP\n", __func__);
ret = proc_resetep(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_RESET:
@@ -2668,7 +2668,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__);
ret = proc_clearhalt(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_GETDRIVER:
@@ -2695,7 +2695,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
ret = proc_submiturb(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
#ifdef CONFIG_COMPAT
@@ -2703,14 +2703,14 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: CONTROL32\n", __func__);
ret = proc_control_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_BULK32:
snoop(&dev->dev, "%s: BULK32\n", __func__);
ret = proc_bulk_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_DISCSIGNAL32:
@@ -2722,7 +2722,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
ret = proc_submiturb_compat(ps, p);
if (ret >= 0)
- inode->i_mtime = inode->i_ctime = current_time(inode);
+ inode->i_mtime = inode_set_ctime_current(inode);
break;
case USBDEVFS_IOCTL32:
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index f41a385a5c42..6e9ef35a43a7 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1377,7 +1377,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
inode = new_inode(sb);
if (inode) {
- struct timespec64 ts = current_time(inode);
+ struct timespec64 ts = inode_set_ctime_current(inode);
inode->i_ino = get_next_ino();
inode->i_mode = perms->mode;
@@ -1385,7 +1385,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
inode->i_gid = perms->gid;
inode->i_atime = ts;
inode->i_mtime = ts;
- inode->i_ctime = ts;
inode->i_private = data;
if (fops)
inode->i_fop = fops;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 28249d0bf062..ce9e31f3d26b 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1969,8 +1969,7 @@ gadgetfs_make_inode (struct super_block *sb,
inode->i_mode = mode;
inode->i_uid = make_kuid(&init_user_ns, default_uid);
inode->i_gid = make_kgid(&init_user_ns, default_gid);
- inode->i_atime = inode->i_mtime = inode->i_ctime
- = current_time(inode);
+ inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
inode->i_private = data;
inode->i_fop = fops;
}
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 37be945a0230..40a03b08d7cf 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -580,7 +580,7 @@ static int cq_create(struct mlx5_vdpa_net *ndev, u16 idx, u32 num_ent)
/* Use vector 0 by default. Consider adding code to choose least used
* vector.
*/
- err = mlx5_vector2eqn(mdev, 0, &eqn);
+ err = mlx5_comp_eqn_get(mdev, 0, &eqn);
if (err)
goto err_vec;
diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c
index deed156e6165..c82c1f4fc588 100644
--- a/drivers/vfio/pci/mlx5/cmd.c
+++ b/drivers/vfio/pci/mlx5/cmd.c
@@ -1025,8 +1025,8 @@ static int mlx5vf_create_cq(struct mlx5_core_dev *mdev,
goto err_buff;
}
- vector = raw_smp_processor_id() % mlx5_comp_vectors_count(mdev);
- err = mlx5_vector2eqn(mdev, vector, &eqn);
+ vector = raw_smp_processor_id() % mlx5_comp_vectors_max(mdev);
+ err = mlx5_comp_eqn_get(mdev, vector, &eqn);
if (err)
goto err_vec;
diff --git a/drivers/video/fbdev/core/svgalib.c b/drivers/video/fbdev/core/svgalib.c
index 9e01322fabe3..2cba158888ea 100644
--- a/drivers/video/fbdev/core/svgalib.c
+++ b/drivers/video/fbdev/core/svgalib.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/fb.h>
+#include <linux/math.h>
#include <linux/svga.h>
#include <asm/types.h>
#include <asm/io.h>
@@ -372,12 +373,6 @@ EXPORT_SYMBOL(svga_get_caps);
* F_VCO = (F_BASE * M) / N
* F_OUT = F_VCO / (2^R)
*/
-
-static inline u32 abs_diff(u32 a, u32 b)
-{
- return (a > b) ? (a - b) : (b - a);
-}
-
int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)
{
u16 am, an, ar;
diff --git a/drivers/virt/acrn/ioreq.c b/drivers/virt/acrn/ioreq.c
index cecdc1c13af7..29e1ef1915fd 100644
--- a/drivers/virt/acrn/ioreq.c
+++ b/drivers/virt/acrn/ioreq.c
@@ -351,7 +351,7 @@ static bool handle_cf8cfc(struct acrn_vm *vm,
return is_handled;
}
-static bool in_range(struct acrn_ioreq_range *range,
+static bool acrn_in_range(struct acrn_ioreq_range *range,
struct acrn_io_request *req)
{
bool ret = false;
@@ -389,7 +389,7 @@ static struct acrn_ioreq_client *find_ioreq_client(struct acrn_vm *vm,
list_for_each_entry(client, &vm->ioreq_clients, list) {
read_lock_bh(&client->range_lock);
list_for_each_entry(range, &client->range_list, list) {
- if (in_range(range, req)) {
+ if (acrn_in_range(range, req)) {
found = client;
break;
}
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index db110cc442b1..691978cddab7 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -65,7 +65,8 @@ static void w1_unref_block(struct w1_cb_block *block)
u16 len = w1_reply_len(block);
if (len) {
cn_netlink_send_mult(block->first_cn, len,
- block->portid, 0, GFP_KERNEL);
+ block->portid, 0,
+ GFP_KERNEL, NULL, NULL);
}
kfree(block);
}
@@ -83,7 +84,8 @@ static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
{
u16 len = w1_reply_len(block);
if (len + space >= block->maxlen) {
- cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL);
+ cn_netlink_send_mult(block->first_cn, len, block->portid,
+ 0, GFP_KERNEL, NULL, NULL);
block->first_cn->len = 0;
block->cn = NULL;
block->msg = NULL;
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index d5d7c402b651..d43153fec18e 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -269,6 +269,13 @@ config XEN_PRIVCMD
disaggregated Xen setups this driver might be needed for other
domains, too.
+config XEN_PRIVCMD_IRQFD
+ bool "Xen irqfd support"
+ depends on XEN_PRIVCMD && XEN_VIRTIO && EVENTFD
+ help
+ Using the irqfd mechanism a virtio backend running in a daemon can
+ speed up interrupt injection into a guest.
+
config XEN_ACPI_PROCESSOR
tristate "Xen ACPI processor"
depends on XEN && XEN_PV_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index f13c3b76ad1e..35659bf70746 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -1044,7 +1044,7 @@ EXPORT_SYMBOL_GPL(gnttab_pages_clear_private);
/**
* gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
- * @nr_pages; number of pages to free
+ * @nr_pages: number of pages to free
* @pages: the pages
*/
void gnttab_free_pages(int nr_pages, struct page **pages)
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index f447cd37cc4c..f00ad5f5f1d4 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -9,11 +9,16 @@
#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+#include <linux/eventfd.h>
+#include <linux/file.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/workqueue.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -833,6 +838,263 @@ out:
return rc;
}
+#ifdef CONFIG_XEN_PRIVCMD_IRQFD
+/* Irqfd support */
+static struct workqueue_struct *irqfd_cleanup_wq;
+static DEFINE_MUTEX(irqfds_lock);
+static LIST_HEAD(irqfds_list);
+
+struct privcmd_kernel_irqfd {
+ struct xen_dm_op_buf xbufs;
+ domid_t dom;
+ bool error;
+ struct eventfd_ctx *eventfd;
+ struct work_struct shutdown;
+ wait_queue_entry_t wait;
+ struct list_head list;
+ poll_table pt;
+};
+
+static void irqfd_deactivate(struct privcmd_kernel_irqfd *kirqfd)
+{
+ lockdep_assert_held(&irqfds_lock);
+
+ list_del_init(&kirqfd->list);
+ queue_work(irqfd_cleanup_wq, &kirqfd->shutdown);
+}
+
+static void irqfd_shutdown(struct work_struct *work)
+{
+ struct privcmd_kernel_irqfd *kirqfd =
+ container_of(work, struct privcmd_kernel_irqfd, shutdown);
+ u64 cnt;
+
+ eventfd_ctx_remove_wait_queue(kirqfd->eventfd, &kirqfd->wait, &cnt);
+ eventfd_ctx_put(kirqfd->eventfd);
+ kfree(kirqfd);
+}
+
+static void irqfd_inject(struct privcmd_kernel_irqfd *kirqfd)
+{
+ u64 cnt;
+ long rc;
+
+ eventfd_ctx_do_read(kirqfd->eventfd, &cnt);
+
+ xen_preemptible_hcall_begin();
+ rc = HYPERVISOR_dm_op(kirqfd->dom, 1, &kirqfd->xbufs);
+ xen_preemptible_hcall_end();
+
+ /* Don't repeat the error message for consecutive failures */
+ if (rc && !kirqfd->error) {
+ pr_err("Failed to configure irq for guest domain: %d\n",
+ kirqfd->dom);
+ }
+
+ kirqfd->error = rc;
+}
+
+static int
+irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int sync, void *key)
+{
+ struct privcmd_kernel_irqfd *kirqfd =
+ container_of(wait, struct privcmd_kernel_irqfd, wait);
+ __poll_t flags = key_to_poll(key);
+
+ if (flags & EPOLLIN)
+ irqfd_inject(kirqfd);
+
+ if (flags & EPOLLHUP) {
+ mutex_lock(&irqfds_lock);
+ irqfd_deactivate(kirqfd);
+ mutex_unlock(&irqfds_lock);
+ }
+
+ return 0;
+}
+
+static void
+irqfd_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt)
+{
+ struct privcmd_kernel_irqfd *kirqfd =
+ container_of(pt, struct privcmd_kernel_irqfd, pt);
+
+ add_wait_queue_priority(wqh, &kirqfd->wait);
+}
+
+static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd)
+{
+ struct privcmd_kernel_irqfd *kirqfd, *tmp;
+ __poll_t events;
+ struct fd f;
+ void *dm_op;
+ int ret;
+
+ kirqfd = kzalloc(sizeof(*kirqfd) + irqfd->size, GFP_KERNEL);
+ if (!kirqfd)
+ return -ENOMEM;
+ dm_op = kirqfd + 1;
+
+ if (copy_from_user(dm_op, irqfd->dm_op, irqfd->size)) {
+ ret = -EFAULT;
+ goto error_kfree;
+ }
+
+ kirqfd->xbufs.size = irqfd->size;
+ set_xen_guest_handle(kirqfd->xbufs.h, dm_op);
+ kirqfd->dom = irqfd->dom;
+ INIT_WORK(&kirqfd->shutdown, irqfd_shutdown);
+
+ f = fdget(irqfd->fd);
+ if (!f.file) {
+ ret = -EBADF;
+ goto error_kfree;
+ }
+
+ kirqfd->eventfd = eventfd_ctx_fileget(f.file);
+ if (IS_ERR(kirqfd->eventfd)) {
+ ret = PTR_ERR(kirqfd->eventfd);
+ goto error_fd_put;
+ }
+
+ /*
+ * Install our own custom wake-up handling so we are notified via a
+ * callback whenever someone signals the underlying eventfd.
+ */
+ init_waitqueue_func_entry(&kirqfd->wait, irqfd_wakeup);
+ init_poll_funcptr(&kirqfd->pt, irqfd_poll_func);
+
+ mutex_lock(&irqfds_lock);
+
+ list_for_each_entry(tmp, &irqfds_list, list) {
+ if (kirqfd->eventfd == tmp->eventfd) {
+ ret = -EBUSY;
+ mutex_unlock(&irqfds_lock);
+ goto error_eventfd;
+ }
+ }
+
+ list_add_tail(&kirqfd->list, &irqfds_list);
+ mutex_unlock(&irqfds_lock);
+
+ /*
+ * Check if there was an event already pending on the eventfd before we
+ * registered, and trigger it as if we didn't miss it.
+ */
+ events = vfs_poll(f.file, &kirqfd->pt);
+ if (events & EPOLLIN)
+ irqfd_inject(kirqfd);
+
+ /*
+ * Do not drop the file until the kirqfd is fully initialized, otherwise
+ * we might race against the EPOLLHUP.
+ */
+ fdput(f);
+ return 0;
+
+error_eventfd:
+ eventfd_ctx_put(kirqfd->eventfd);
+
+error_fd_put:
+ fdput(f);
+
+error_kfree:
+ kfree(kirqfd);
+ return ret;
+}
+
+static int privcmd_irqfd_deassign(struct privcmd_irqfd *irqfd)
+{
+ struct privcmd_kernel_irqfd *kirqfd;
+ struct eventfd_ctx *eventfd;
+
+ eventfd = eventfd_ctx_fdget(irqfd->fd);
+ if (IS_ERR(eventfd))
+ return PTR_ERR(eventfd);
+
+ mutex_lock(&irqfds_lock);
+
+ list_for_each_entry(kirqfd, &irqfds_list, list) {
+ if (kirqfd->eventfd == eventfd) {
+ irqfd_deactivate(kirqfd);
+ break;
+ }
+ }
+
+ mutex_unlock(&irqfds_lock);
+
+ eventfd_ctx_put(eventfd);
+
+ /*
+ * Block until we know all outstanding shutdown jobs have completed so
+ * that we guarantee there will not be any more interrupts once this
+ * deassign function returns.
+ */
+ flush_workqueue(irqfd_cleanup_wq);
+
+ return 0;
+}
+
+static long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
+{
+ struct privcmd_data *data = file->private_data;
+ struct privcmd_irqfd irqfd;
+
+ if (copy_from_user(&irqfd, udata, sizeof(irqfd)))
+ return -EFAULT;
+
+ /* No other flags should be set */
+ if (irqfd.flags & ~PRIVCMD_IRQFD_FLAG_DEASSIGN)
+ return -EINVAL;
+
+ /* If restriction is in place, check the domid matches */
+ if (data->domid != DOMID_INVALID && data->domid != irqfd.dom)
+ return -EPERM;
+
+ if (irqfd.flags & PRIVCMD_IRQFD_FLAG_DEASSIGN)
+ return privcmd_irqfd_deassign(&irqfd);
+
+ return privcmd_irqfd_assign(&irqfd);
+}
+
+static int privcmd_irqfd_init(void)
+{
+ irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", 0, 0);
+ if (!irqfd_cleanup_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void privcmd_irqfd_exit(void)
+{
+ struct privcmd_kernel_irqfd *kirqfd, *tmp;
+
+ mutex_lock(&irqfds_lock);
+
+ list_for_each_entry_safe(kirqfd, tmp, &irqfds_list, list)
+ irqfd_deactivate(kirqfd);
+
+ mutex_unlock(&irqfds_lock);
+
+ destroy_workqueue(irqfd_cleanup_wq);
+}
+#else
+static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int privcmd_irqfd_init(void)
+{
+ return 0;
+}
+
+static inline void privcmd_irqfd_exit(void)
+{
+}
+#endif /* CONFIG_XEN_PRIVCMD_IRQFD */
+
static long privcmd_ioctl(struct file *file,
unsigned int cmd, unsigned long data)
{
@@ -868,6 +1130,10 @@ static long privcmd_ioctl(struct file *file,
ret = privcmd_ioctl_mmap_resource(file, udata);
break;
+ case IOCTL_PRIVCMD_IRQFD:
+ ret = privcmd_ioctl_irqfd(file, udata);
+ break;
+
default:
break;
}
@@ -992,15 +1258,27 @@ static int __init privcmd_init(void)
err = misc_register(&xen_privcmdbuf_dev);
if (err != 0) {
pr_err("Could not register Xen hypercall-buf device\n");
- misc_deregister(&privcmd_dev);
- return err;
+ goto err_privcmdbuf;
+ }
+
+ err = privcmd_irqfd_init();
+ if (err != 0) {
+ pr_err("irqfd init failed\n");
+ goto err_irqfd;
}
return 0;
+
+err_irqfd:
+ misc_deregister(&xen_privcmdbuf_dev);
+err_privcmdbuf:
+ misc_deregister(&privcmd_dev);
+ return err;
}
static void __exit privcmd_exit(void)
{
+ privcmd_irqfd_exit();
misc_deregister(&privcmd_dev);
misc_deregister(&xen_privcmdbuf_dev);
}
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 67aa74d20162..946bd56f0ac5 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -381,7 +381,7 @@ xen_swiotlb_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
static int
xen_swiotlb_dma_supported(struct device *hwdev, u64 mask)
{
- return xen_phys_to_dma(hwdev, io_tlb_default_mem.end - 1) <= mask;
+ return xen_phys_to_dma(hwdev, default_swiotlb_limit()) <= mask;
}
const struct dma_map_ops xen_swiotlb_dma_ops = {
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 9cb61db67efd..296703939846 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -473,11 +473,8 @@ static int xen_upload_processor_pm_data(void)
if (!_pr)
continue;
- if (!pr_backup) {
- pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
- if (pr_backup)
- memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
- }
+ if (!pr_backup)
+ pr_backup = kmemdup(_pr, sizeof(*_pr), GFP_KERNEL);
(void)upload_pm_data(_pr);
}
diff --git a/drivers/xen/xen-pciback/conf_space_quirks.h b/drivers/xen/xen-pciback/conf_space_quirks.h
index d873abe35bf6..fc1557dfef49 100644
--- a/drivers/xen/xen-pciback/conf_space_quirks.h
+++ b/drivers/xen/xen-pciback/conf_space_quirks.h
@@ -21,8 +21,6 @@ struct xen_pcibk_config_quirk {
int xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field
*field);
-int xen_pcibk_config_quirks_remove_field(struct pci_dev *dev, int reg);
-
int xen_pcibk_config_quirks_init(struct pci_dev *dev);
void xen_pcibk_config_field_free(struct config_field *field);
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h
index 9a64196e831d..f9599ed2f2e2 100644
--- a/drivers/xen/xen-pciback/pciback.h
+++ b/drivers/xen/xen-pciback/pciback.h
@@ -201,6 +201,3 @@ static inline void xen_pcibk_lateeoi(struct xen_pcibk_device *pdev,
int xen_pcibk_xenbus_register(void);
void xen_pcibk_xenbus_unregister(void);
#endif
-
-/* Handles shared IRQs that can to device domain and control domain. */
-void xen_pcibk_irq_handler(struct pci_dev *dev, int reset);
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 3f3836cb7279..fcb335bb7b18 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -429,7 +429,7 @@ static void xenbus_check_frontend(char *class, char *dev)
printk(KERN_DEBUG "XENBUS: frontend %s %s\n",
frontend, xenbus_strstate(fe_state));
backend = xenbus_read(XBT_NIL, frontend, "backend", NULL);
- if (!backend || IS_ERR(backend))
+ if (IS_ERR_OR_NULL(backend))
goto out;
err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state);
if (err == 1)
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 12e02eb01f59..028a182bcc9e 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -840,8 +840,8 @@ void xs_suspend(void)
{
xs_suspend_enter();
- down_write(&xs_watch_rwsem);
mutex_lock(&xs_response_mutex);
+ down_write(&xs_watch_rwsem);
}
void xs_resume(void)
@@ -866,8 +866,8 @@ void xs_resume(void)
void xs_suspend_cancel(void)
{
- mutex_unlock(&xs_response_mutex);
up_write(&xs_watch_rwsem);
+ mutex_unlock(&xs_response_mutex);
xs_suspend_exit();
}
diff --git a/drivers/zorro/names.c b/drivers/zorro/names.c
index fa3c83dbe843..077114ccc840 100644
--- a/drivers/zorro/names.c
+++ b/drivers/zorro/names.c
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/zorro.h>
+#include "zorro.h"
struct zorro_prod_info {
__u16 prod;